#include #include #include #include #include #include "configuration.h" #include "mpicomm.h" #include "mesh.h" #include "field.h" #ifdef DEBUG_ATTACH #include void wait_for_debugger(); #endif void print_decomposition(const conf_t *configuraiton, const box_t *decomposition, FILE *f); void print_adjacency_matrix(const mesh_t *mesh, const conf_t *configuraiton, FILE *f); void halo_exchange_demo(const mesh_t *mesh, const conf_t *configuration); int main(int argc, char *argv[]) { int mpi_rank, nprocs; const char* error; mesh_t mesh; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); // initialize random number generator srand((mpi_rank + 17) * (int)time(NULL)); conf_t configuration; conf_init(&configuration); if(mpi_rank == 0) { // parse comand line args on root process only error = conf_set_from_args(&configuration, argc, argv); if(error) { fprintf(stderr, "%s\n", error); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); } } // Broadcast configuration (nonblocking) MPI_Request req_bcast_conf; mpi_broadcast_configuration_start(&configuration, &req_bcast_conf); // Create and broadcast decomposition box_t *decomposition = malloc(nprocs * sizeof(*decomposition)); if(mpi_rank == 0) { const box_t *cube = &configuration.global_domain; box_decompose(cube, nprocs, decomposition); } mpi_broadcast_decomposition(decomposition); // Finish nonblocking configuration broadcast mpi_broadcast_configuration_finish(&req_bcast_conf); if(info_enabled(&configuration)) { conf_print(&configuration, stdout); print_decomposition(&configuration, decomposition, stdout); } #ifdef DEBUG_ATTACH if(mpi_rank == configuration.debug_rank) { wait_for_debugger(); } #endif mesh_init(&mesh, &configuration, decomposition); print_adjacency_matrix(&mesh, &configuration, stdout); halo_exchange_demo(&mesh, &configuration); mesh_free(&mesh); free(decomposition); MPI_Finalize(); return EXIT_SUCCESS; } // -------------------------------------------------------------------------- void halo_exchange_demo(const mesh_t *mesh, const conf_t *configuration) { int mpi_rank, i, n; int_field_t field; const neighbor_info *nb; int_field_init(&field, configuration, mesh); MPI_Comm_rank(mesh->communicator, &mpi_rank); // Set field data and exchange halo information n = configuration->n_iterations; if(info_enabled(configuration)) { printf("Exchanging halo information (%d iterations)...\n\n", n); } for(i = 0; i < n; i++) { if(trace_enabled(configuration)) { printf("Iteration %d\n", i); } int_field_set_constant(&field, mpi_rank); int_field_halo_exchange(&field); } if(info_enabled(configuration)) { printf("Validating...\n\n"); } // Validate local field data if(!int_field_check_value(&field, &mesh->local_domain, mpi_rank)) { fprintf(stderr, "ERROR (rank %d): Local cell data corrupted.\n", mpi_rank); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); } // Validate halo data received from each neighbor for(i = 0; i < mesh->n_neighbors; i++) { nb = &mesh->neighbors[i]; if(!int_field_check_value(&field, &nb->halo_incoming.domain, nb->mpi_rank)) { fprintf(stderr, "ERROR (rank %d): Halo values for neighbor rank %d not correct.\n", mpi_rank, nb->mpi_rank); MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); } } if(info_enabled(configuration)) { printf("Validation successful.\n\n"); } int_field_free(&field); } void print_decomposition(const conf_t *configuration, const box_t *boxes, FILE *f) { int nprocs; MPI_Comm_size(MPI_COMM_WORLD, &nprocs); long volume, min_volume = LONG_MAX, max_volume = 0; int i, j; for(i = 0; i < nprocs; i++) { volume = boxes[i].volume; if(min_volume > volume) min_volume = boxes[i].volume; if(max_volume < volume) max_volume = boxes[i].volume; } fprintf(f, "Cells per processor (min-max): %ld - %ld\n\n", min_volume, max_volume); if(trace_enabled(configuration)) { char buf[128]; box_t intersection; fprintf(f, "Decomposition:\n"); for(i = 0; i < nprocs; i++) { fprintf(f, " * box %5d: %s\n", i, box_to_string(&boxes[i], buf, sizeof(buf))); for(j = 0; j < i; j++) { box_intersect(&boxes[i], &boxes[j], &intersection); if(!box_is_empty(&intersection)){ fprintf(f, " * intersects with box %d\n", j); } } } fprintf(f, "\n"); } } void print_adjacency_matrix(const mesh_t *mesh, const conf_t *configuration, FILE *f) { if(configuration->verbosity_level >= DEBUG) { int mpi_rank, nprocs; int *sendbuf, *recvbuf, *row; neighbor_info *nb; int i, j, min, max, n; MPI_Comm_size(MPI_COMM_WORLD, &nprocs); MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); sendbuf = calloc(nprocs, sizeof(*sendbuf)); recvbuf = mpi_rank == 0 ? calloc(nprocs * nprocs, sizeof(*recvbuf)) : NULL; for(i = 0; i < mesh->n_neighbors; i++) { nb = &mesh->neighbors[i]; sendbuf[nb->mpi_rank] = nb->halo_incoming.domain.volume; } MPI_Gather( sendbuf, nprocs, MPI_INT, recvbuf, nprocs, MPI_INT, 0, MPI_COMM_WORLD); if(mpi_rank == 0) { fprintf(f, "Adjacency matrix:\n"); fprintf(f, "%2s ", ""); for(i = 0; i < nprocs; i++) { fprintf(f, "%2d ", i); } fprintf(f, "\n"); for(j = 0; j < nprocs; j++) { row = recvbuf + j * nprocs; fprintf(f, "%2d ", j); for(i = 0; i < nprocs; i++) { fprintf(f, "%2s ", row[i] ? "X" : ""); } fprintf(f, "\n"); } fprintf(f, "\n"); min = INT_MAX; max = 0; for(i = 0; i < nprocs * nprocs; i++) { n = recvbuf[i]; if(n > 0 && min > n) min = recvbuf[i]; if(max < n) max = n; } fprintf(f, "Number of halo cells per neighbor (min-max): %d - %d\n\n", min, max); free(recvbuf); } free(sendbuf); } } #ifdef DEBUG_ATTACH void wait_for_debugger() { int rank; volatile int resume = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); printf("Rank %d (pid %d) waiting for debugger to attach...\n", rank, getpid()); while(!resume) { sleep(1); } } #endif