summaryrefslogtreecommitdiff
path: root/mpi/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpi/src/main.c')
-rw-r--r--mpi/src/main.c69
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) {