diff options
author | Logan Hunt <loganhunt@simponic.xyz> | 2021-12-08 01:50:12 -0700 |
---|---|---|
committer | Logan Hunt <loganhunt@simponic.xyz> | 2021-12-08 01:50:12 -0700 |
commit | c846568cf28b4d128cf893dc0abb6ccb5ccdcc32 (patch) | |
tree | 01ad0e303ea59103f2af9b9aa007785b88fa80ca /mpi/src/main.c | |
parent | 253b267f1cee377a834860fb4deac54ef9a78b7a (diff) | |
download | gol-c846568cf28b4d128cf893dc0abb6ccb5ccdcc32.tar.gz gol-c846568cf28b4d128cf893dc0abb6ccb5ccdcc32.zip |
Timing study
Diffstat (limited to 'mpi/src/main.c')
-rw-r--r-- | mpi/src/main.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/mpi/src/main.c b/mpi/src/main.c index 9fed89e..02e2bb6 100644 --- a/mpi/src/main.c +++ b/mpi/src/main.c @@ -15,10 +15,12 @@ Any live cell with more than three live neighbors dies (overpopulation). Any dead cell with exactly three live neighbors becomes a live cell (reproduction). */ -#define PADDING 16 +#define PADDING 10 //#define VERBOSE 1 #define SEED 100 +// A structure to keep the global arguments because each process +// will use its own GAME structure struct Args { int process_count; int iterations; @@ -30,6 +32,7 @@ struct Args { int data_per_proc; }; +// Make a datatype out of an Args struct void broadcast_and_receive_input(MPI_Comm comm, struct Args* args) { int blocks[8] = {1,1,1,1,1,1,1,1}; MPI_Aint displacements[8]; @@ -50,6 +53,7 @@ void broadcast_and_receive_input(MPI_Comm comm, struct Args* args) { MPI_Bcast(args, 1, arg_t, 0, comm); } +// Scatter the grid among nodes void scatter_data(MPI_Comm comm, struct Args* args, unsigned char* local_data, int rank, int* data_counts, int* displacements, char* filename) { unsigned char* data; @@ -63,12 +67,14 @@ void scatter_data(MPI_Comm comm, struct Args* args, unsigned char* local_data, i data = malloc(size); memset(data, 0, size); game.grid = data; + // Choose where to read initial position if (strcmp(filename, "random") == 0) { randomize(&game); } else { read_in(filename, &game); } } + // Do the scatter (some nodes may work on more rows) MPI_Scatterv(data, data_counts, displacements, MPI_UNSIGNED_CHAR, local_data, data_counts[rank], MPI_UNSIGNED_CHAR, 0, comm); if (rank == 0) { @@ -77,12 +83,13 @@ void scatter_data(MPI_Comm comm, struct Args* args, unsigned char* local_data, i } +// Do the simulation void simulate(int argc, char** argv) { srand(SEED); - double totalStart = MPI_Wtime(); struct Args args; args.padding = PADDING; + // Initialize MPI stuff int rank, process_count; MPI_Comm comm; MPI_Init(&argc, &argv); @@ -91,7 +98,9 @@ void simulate(int argc, char** argv) { MPI_Comm_size(comm, &args.process_count); char* filename; + double global_start; if (rank == 0) { + // Parse the arguments if (argc == 7) { filename = argv[2]; args.width = atoi(argv[3]); @@ -99,7 +108,7 @@ void simulate(int argc, char** argv) { args.iterations = atoi(argv[5]); args.log_each_step = atoi(argv[6]); } else { - printf("Usage: ./gol simulate <filename | random> <width> <height> <iterations> <log-each-step?1:0> <block-size>\n"); + printf("Usage: ./gol simulate <filename | random> <width> <height> <iterations> <log-each-step?1:0>\n"); filename = "random"; args.height = 5; args.width = 5; @@ -107,12 +116,17 @@ void simulate(int argc, char** argv) { args.log_each_step = 0; } + global_start = MPI_Wtime(); + + // Figure out how much work the average node will be doing args.rows_per_proc = (args.height + args.padding*2)/args.process_count; args.data_per_proc = args.rows_per_proc * (args.width + args.padding*2); } broadcast_and_receive_input(comm, &args); + // Calculate the exact work each thread will do and arguments for + // the Scatterv to scatter the grid int grid_size = ((args.width + args.padding*2)*(args.height + args.padding*2)); int* data_counts = malloc(sizeof(int) * args.process_count); int* displacements = malloc(sizeof(int) * args.process_count); @@ -123,19 +137,20 @@ void simulate(int argc, char** argv) { data_counts[args.process_count-1] += grid_size % (args.data_per_proc * args.process_count); unsigned char* local_data = malloc(data_counts[rank]*sizeof(unsigned char)); memset(local_data, 0, sizeof(unsigned char) * data_counts[rank]); + + // Scatter the data among nodes scatter_data(comm, &args, local_data, rank, data_counts, displacements, filename); - // Allocate space for current grid (1 byte per tile) char iteration_file[1024]; - double timeComputingLife = 0; - float localTime = 0; - + // Local_game is our current job struct GAME local_game; local_game.grid = local_data; local_game.width = args.width; local_game.height = data_counts[rank] / (args.width + args.padding*2); local_game.padding = args.padding; + + // Assign halo elements to send to be received from above and below nodes unsigned char* halo_above = NULL; unsigned char* halo_below = NULL; if (rank > 0) { @@ -148,32 +163,46 @@ void simulate(int argc, char** argv) { } unsigned char* global_data; + if (rank == 0) { + global_data = malloc(sizeof(unsigned char) * grid_size); + memset(global_data, 0, sizeof(unsigned char) * grid_size); + } + + // Timing code + double time_computing_life = 0; + double start,end; for (int i = 0; i <= args.iterations; i++) { + // Iteration 0 will just be the initial grid if (i > 0) { int total_width = args.width + args.padding*2; + + MPI_Status status; if (rank < args.process_count - 1) { MPI_Send(&local_game.grid[(local_game.height-1) * total_width], total_width, MPI_UNSIGNED_CHAR, rank+1, 1, comm); } if (rank > 0) { - MPI_Recv(halo_above, total_width, MPI_UNSIGNED_CHAR, rank-1, 1, comm, NULL); + MPI_Recv(halo_above, total_width, MPI_UNSIGNED_CHAR, rank-1, 1, comm, &status); MPI_Send(&local_game.grid[0], total_width, MPI_UNSIGNED_CHAR, rank-1, 0, comm); } if (rank < args.process_count - 1) { - MPI_Recv(halo_below, total_width, MPI_UNSIGNED_CHAR, rank+1, 0, comm, NULL); + MPI_Recv(halo_below, total_width, MPI_UNSIGNED_CHAR, rank+1, 0, comm, &status); } MPI_Barrier(comm); + start = MPI_Wtime(); + // Compute the next grid next(&local_game, halo_above, halo_below); + end = MPI_Wtime(); + time_computing_life += end-start; } if (args.log_each_step) { - if (rank == 0) { - global_data = malloc(sizeof(unsigned char) * grid_size); - memset(global_data, 0, sizeof(unsigned char) * grid_size); - } + // If we are logging each step, perform IO operations + // Gather all of the local grids into global_data MPI_Gatherv(local_game.grid, data_counts[rank], MPI_UNSIGNED_CHAR, global_data, data_counts, displacements, MPI_UNSIGNED_CHAR, 0, comm); if (rank == 0) { - #ifdef VERBOSE + #if VERBOSE == 1 printf("\n===Iteration %i===\n", i); + // Print the baord without the padding elements for (int y = args.padding; y < args.height+args.padding; y++) { for (int x = args.padding; x < args.width+args.padding; x++) { printf("%s ", global_data[y*(args.width+2*args.padding) + x] ? "X" : " "); @@ -183,6 +212,7 @@ void simulate(int argc, char** argv) { printf("===End iteration %i===\n", i); #endif + // Save to a file struct GAME global_game; global_game.grid = global_data; global_game.width = args.width; @@ -194,12 +224,15 @@ void simulate(int argc, char** argv) { } } - double totalEnd = MPI_Wtime(); - MPI_Finalize(); + double total_end = MPI_Wtime(); if (rank == 0) { - printf("\n===Timing===\nTime computing life: %f\nClock time: %f\n", timeComputingLife, (totalEnd - totalStart)); + printf("\n===Timing===\nTime computing life: %f\nClock time: %f\n", time_computing_life, (total_end - global_start)); + free(local_game.grid); + free(data_counts); + free(halo_above); + free(halo_below); } - + MPI_Finalize(); } int main(int argc, char** argv) { |