/** * Author: Baptiste Coudray * School: HEPIA * Class: ITI-3 * Year 2020-2021 */ #include <stdio.h> #include <stdint.h> #include <mpi.h> #include <math.h> #include <stdbool.h> #include <unistd.h> #include "gol.h" #include "gfx.h" #include "../futhark_mpi/dispatch.h" #define INDEX_2D_TO_1D(y, x, nb_columns) ((y) * (nb_columns) + (x)) #define ROOT_RANK 0 #define FPS 60 //int createGridCommunicators(MPI_Comm *cartComm, MPI_Comm *rowComm, MPI_Comm *colComm, int nProc) { // int gridN = (int) sqrt(nProc); // int dimensions[2] = {gridN, gridN}; // int periods[2] = {true, true}; // Cyclic on row-column // // MPI_Cart_create(MPI_COMM_WORLD, 2, dimensions, periods, 1, cartComm); // // /* Create row communicator */ // int remainDims[2] = {false, true}; // MPI_Cart_sub(*cartComm, remainDims, rowComm); // // /* Create column communicator */ // remainDims[0] = true; // rows // remainDims[1] = false; // columns // MPI_Cart_sub(*cartComm, remainDims, colComm); // return gridN; //} // //int *divideBoard(int n, int chunkN, int nProc) { // int *indexes = calloc((size_t) nProc * 2, sizeof(int)); // for (int i = 0, y = 0, x = 0; i < nProc; ++i) { // indexes[i * 2] = y; // indexes[i * 2 + 1] = x; // // x += chunkN; // if (x >= n) { // x = 0; // y += chunkN; // } // } // return indexes; //} // // //void shareAndBuildEnvelope(int8_t *chunkBoardMyEnvelope, int8_t *chunkBoardEnvelope, MPI_Comm rowComm, // MPI_Comm colComm, int gridN, int coordinates[2], int chunkN, int chunkM) { // int coordinateY = coordinates[0]; // int coordinateX = coordinates[1]; // MPI_Request requests[16] = {0}; // int iRequest = 0; // // // North // { // int8_t *chunkBoardMyEnvelopeNorth = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(NORTH_INDEX, 0, chunkN)]; // int8_t *chunkBoardEnvelopeNorth = &chunkBoardEnvelope[INDEX_2D_TO_1D(NORTH_INDEX, 1, chunkM)]; // int destSource = (coordinateY - 1) < 0 ? (gridN - 1) : (coordinateY - 1); // // MPI_Isend(chunkBoardMyEnvelopeNorth, chunkN, MPI_INT8_T, destSource, NORTH_ROW_TAG, colComm, // &requests[iRequest++]); // /* Neighbour send south row, which correspond to north envelope */ // MPI_Irecv(chunkBoardEnvelopeNorth, chunkN, MPI_INT8_T, destSource, SOUTH_ROW_TAG, colComm, // &requests[iRequest++]); // } // // // East // { // int8_t *chunkBoardMyEnvelopeEast = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(EAST_INDEX, 0, chunkN)]; // int8_t *chunkBoardEnvelopeEast = &chunkBoardEnvelope[INDEX_2D_TO_1D(EAST_INDEX, 1, chunkM)]; // int destSource = (coordinateX + 1) % gridN; // // MPI_Isend(chunkBoardMyEnvelopeEast, chunkN, MPI_INT8_T, destSource, EAST_COLUMN_TAG, rowComm, // &requests[iRequest++]); // /* Neighbour send west column, which correspond to east envelope */ // MPI_Irecv(chunkBoardEnvelopeEast, chunkN, MPI_INT8_T, destSource, WEST_COLUMN_TAG, rowComm, // &requests[iRequest++]); // } // // // South // { // int8_t *chunkBoardMyEnvelopeSouth = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(SOUTH_INDEX, 0, chunkN)]; // int8_t *chunkBoardEnvelopeSouth = &chunkBoardEnvelope[INDEX_2D_TO_1D(SOUTH_INDEX, 1, chunkM)]; // int destSource = (coordinateY + 1) % gridN; // // MPI_Isend(chunkBoardMyEnvelopeSouth, chunkN, MPI_INT8_T, destSource, SOUTH_ROW_TAG, colComm, // &requests[iRequest++]); // /* Neighbour send north row, which correspond to south envelope */ // MPI_Irecv(chunkBoardEnvelopeSouth, chunkN, MPI_INT8_T, destSource, NORTH_ROW_TAG, colComm, // &requests[iRequest++]); // } // // // West // { // int8_t *chunkBoardMyEnvelopeWest = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(WEST_INDEX, 0, chunkN)]; // int8_t *chunkBoardEnvelopeWest = &chunkBoardEnvelope[INDEX_2D_TO_1D(WEST_INDEX, 1, chunkM)]; // int destSource = (coordinateX - 1) < 0 ? (gridN - 1) : (coordinateX - 1); // // MPI_Isend(chunkBoardMyEnvelopeWest, chunkN, MPI_INT8_T, destSource, WEST_COLUMN_TAG, rowComm, // &requests[iRequest++]); // /* Neighbour send east column, which correspond to west envelope */ // MPI_Irecv(chunkBoardEnvelopeWest, chunkN, MPI_INT8_T, destSource, EAST_COLUMN_TAG, rowComm, // &requests[iRequest++]); // } // // int8_t missingCells[4] = {0}; // // // North-East // { // int8_t *chunkBoardMyEnvelopeNorthEast = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(NORTH_INDEX, chunkN - 1, chunkN)]; // int destSrcY = (coordinateY - 1) < 0 ? gridN - 1 : coordinateY - 1; // int destSrcX = (coordinateX + 1) % gridN; // int destSource = INDEX_2D_TO_1D(destSrcY, destSrcX, gridN); // // MPI_Isend(chunkBoardMyEnvelopeNorthEast, 1, MPI_INT8_T, destSource, NORTH_EAST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // /* Neighbour send south-west cell, which correspond to north-east cell */ // MPI_Irecv(&missingCells[1], 1, MPI_INT8_T, destSource, SOUTH_WEST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // } // // // South-East // { // int8_t *chunkBoardMyEnvelopeSouthEast = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(SOUTH_INDEX, chunkN - 1, chunkN)]; // int destSrcY = (coordinateY + 1) % gridN; // int destSrcX = (coordinateX + 1) % gridN; // int destSource = INDEX_2D_TO_1D(destSrcY, destSrcX, gridN); // // MPI_Isend(chunkBoardMyEnvelopeSouthEast, 1, MPI_INT8_T, destSource, SOUTH_EAST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // /* Neighbour send north-west cell, which correspond to south-east cell */ // MPI_Irecv(&missingCells[2], 1, MPI_INT8_T, destSource, NORTH_WEST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // } // // // South-West // { // int8_t *chunkBoardMyEnvelopeSouthWest = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(SOUTH_INDEX, 0, chunkN)]; // int destSrcY = (coordinateY + 1) % gridN; // int destSrcX = (coordinateX - 1) < 0 ? gridN - 1 : coordinateX - 1; // int destSource = INDEX_2D_TO_1D(destSrcY, destSrcX, gridN); // // MPI_Isend(chunkBoardMyEnvelopeSouthWest, 1, MPI_INT8_T, destSource, SOUTH_WEST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // /* Neighbour send north-east cell, which correspond to south-west cell */ // MPI_Irecv(&missingCells[3], 1, MPI_INT8_T, destSource, NORTH_EAST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // } // // // North-West // { // int8_t *chunkBoardMyEnvelopeNorthWest = &chunkBoardMyEnvelope[INDEX_2D_TO_1D(NORTH_INDEX, 0, chunkN)]; // int destSrcY = (coordinateY - 1) < 0 ? gridN - 1 : coordinateY - 1; // int destSrcX = (coordinateX - 1) < 0 ? gridN - 1 : coordinateX - 1; // int destSource = INDEX_2D_TO_1D(destSrcY, destSrcX, gridN); // // MPI_Isend(chunkBoardMyEnvelopeNorthWest, 1, MPI_INT8_T, destSource, NORTH_WEST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest++]); // /* Neighbour send south-east cell, which correspond to north-west cell */ // MPI_Irecv(&missingCells[0], 1, MPI_INT8_T, destSource, SOUTH_EAST_CELL_TAG, MPI_COMM_WORLD, // &requests[iRequest]); // } // // MPI_Waitall(16, requests, MPI_STATUSES_IGNORE); // // /* Copy missing cells into the envelope */ // chunkBoardEnvelope[INDEX_2D_TO_1D(NORTH_INDEX, chunkN, chunkM)] = chunkBoardEnvelope[INDEX_2D_TO_1D( // EAST_INDEX, 0, chunkM)] = missingCells[1]; // chunkBoardEnvelope[INDEX_2D_TO_1D(SOUTH_INDEX, chunkN, chunkM)] = chunkBoardEnvelope[INDEX_2D_TO_1D(EAST_INDEX, // chunkN, // chunkM)] = missingCells[2]; // chunkBoardEnvelope[INDEX_2D_TO_1D(SOUTH_INDEX, 0, chunkM)] = chunkBoardEnvelope[INDEX_2D_TO_1D(WEST_INDEX, // chunkN, // chunkM)] = missingCells[3]; // chunkBoardEnvelope[INDEX_2D_TO_1D(NORTH_INDEX, 0, chunkM)] = chunkBoardEnvelope[INDEX_2D_TO_1D(WEST_INDEX, // 0, // chunkM)] = missingCells[0]; //} // //void chunkBoardToBoard(int8_t *board, int n, const int8_t *chunkBoard, int chunkN, const int *indexes, int rank) { // int y = indexes[rank * 2]; // int x = indexes[rank * 2 + 1]; // // for (int i = 0; i < chunkN; ++i) { // for (int j = 0; j < chunkN; ++j) { // board[INDEX_2D_TO_1D(y + i, x + j, n)] = chunkBoard[INDEX_2D_TO_1D(i, j, chunkN)]; // } // } //} // //int main(int argc, char *argv[]) { // if (argc < 3) { // printf("%s <deviceName> <boardN>\n", argv[0]); // exit(0); // } // int myRank; // int nProc; // // /* MPI Initialization */ // MPI_Init(&argc, &argv); // MPI_Comm_rank(MPI_COMM_WORLD, &myRank); // MPI_Comm_size(MPI_COMM_WORLD, &nProc); // srand((unsigned int) myRank); // // MPI_Comm cartComm, rowComm, colComm; // int gridN = createGridCommunicators(&cartComm, &rowComm, &colComm, nProc); // // int myCartRank; // MPI_Comm_rank(cartComm, &myCartRank); // // int coordinates[2] = {0}; // MPI_Cart_coords(cartComm, myCartRank, 2, coordinates); // // /* Futhark Initialization */ // struct futhark_context_config *contextConfig = futhark_context_config_new(); // futhark_context_config_set_debugging(contextConfig, 1); // int nbDevices = atoi(argv[1]); // char device[3] = {0}; // snprintf(device, sizeof(device), "#%d", myRank % nbDevices); // futhark_context_config_set_device(contextConfig, device); // struct futhark_context *futharkContext = futhark_context_new(contextConfig); // // /* GoL Initialization */ // int boardN = atoi(argv[2]); // int boardNN = boardN * boardN; // int chunkN = (int) (boardN / sqrt(nProc)); // int chunkNN = chunkN * chunkN; // int chunkM = chunkN + 2; // int *indexes = divideBoard(boardN, chunkN, nProc); // // int8_t *board = myRank == ROOT_RANK ? calloc((size_t) boardNN, sizeof(int8_t)) : NULL; // int8_t *chunkBoard = calloc((size_t) chunkNN, sizeof(int8_t)); // int8_t *chunkBoardMyEnvelope = calloc(((size_t) (4 * chunkN)), sizeof(int8_t)); // int8_t *chunkBoardEnvelope = calloc(((size_t) (4 * chunkM)), sizeof(int8_t)); // // initChunkBoard(chunkBoard, chunkN); // // /* GFX Initialization */ // struct gfx_context_t *gfxContext = // myRank == ROOT_RANK ? gfx_create("Game of Life", (uint) boardN, (uint) boardN) : NULL; // if (myRank == ROOT_RANK && !gfxContext) { // fprintf(stderr, "Graphic mode initialization failed!\n"); // return EXIT_FAILURE; // } // if (myRank == ROOT_RANK) { // SDL_ShowCursor(SDL_ENABLE); // } // // bool exit = false; // while (!exit) { // struct futhark_i8_2d *futChunkBoard = futhark_new_i8_2d(futharkContext, chunkBoard, chunkN, chunkN); // futhark_context_sync(futharkContext); // struct futhark_i8_2d *futChunkBoardMyEnvelope; // futhark_entry_get_envelope(futharkContext, &futChunkBoardMyEnvelope, futChunkBoard); // futhark_context_sync(futharkContext); // futhark_values_i8_2d(futharkContext, futChunkBoardMyEnvelope, chunkBoardMyEnvelope); // futhark_context_sync(futharkContext); // // shareAndBuildEnvelope(chunkBoardMyEnvelope, chunkBoardEnvelope, rowComm, colComm, gridN, coordinates, chunkN, // chunkM); // // struct futhark_i8_2d *futChunkBoardEnvelope = futhark_new_i8_2d(futharkContext, chunkBoardEnvelope, 4, chunkM); // futhark_context_sync(futharkContext); // struct futhark_i8_2d *futNextChunkBoard; // futhark_entry_next_chunk_board(futharkContext, &futNextChunkBoard, futChunkBoard, futChunkBoardEnvelope); // futhark_context_sync(futharkContext); // futhark_values_i8_2d(futharkContext, futNextChunkBoard, chunkBoard); // futhark_context_sync(futharkContext); // // if (myRank == ROOT_RANK) { // chunkBoardToBoard(board, boardN, chunkBoard, chunkN, indexes, myRank); // int8_t *tmpChunkBoard = calloc((size_t) chunkNN, sizeof(int8_t)); // MPI_Status status = {0}; // for (int i = 0; i < nProc - 1; ++i) { // MPI_Recv(tmpChunkBoard, chunkNN, MPI_INT8_T, MPI_ANY_SOURCE, CHUNK_BOARD_TAG, MPI_COMM_WORLD, &status); // chunkBoardToBoard(board, boardN, tmpChunkBoard, chunkN, indexes, status.MPI_SOURCE); // } // free(tmpChunkBoard); // } else { // MPI_Send(chunkBoard, chunkNN, MPI_INT8_T, ROOT_RANK, CHUNK_BOARD_TAG, MPI_COMM_WORLD); // } // // if (myRank == ROOT_RANK) { // SDL_PumpEvents(); // SDL_Event event; // SDL_PollEvent(&event); // // exit = gfx_keypressed() == SDLK_ESCAPE || // (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE); // // gfx_clear(gfxContext, COLOR_BLACK); // for (int y = 0; y < boardN; ++y) { // for (int x = 0; x < boardN; ++x) { // int cell = (int) board[INDEX_2D_TO_1D(y, x, boardN)]; // gfx_putpixel(gfxContext, x, y, MAKE_COLOR(cell * 255, cell * 255, cell * 255)); // } // } // gfx_present(gfxContext); // } // // futhark_context_sync(futharkContext); // futhark_free_i8_2d(futharkContext, futChunkBoard); // futhark_free_i8_2d(futharkContext, futChunkBoardMyEnvelope); // futhark_free_i8_2d(futharkContext, futChunkBoardEnvelope); // futhark_free_i8_2d(futharkContext, futNextChunkBoard); // // MPI_Bcast(&exit, 1, MPI_C_BOOL, ROOT_RANK, MPI_COMM_WORLD); // usleep(1000000 / FPS); // } // // free(indexes); // free(chunkBoard); // free(chunkBoardEnvelope); // free(chunkBoardMyEnvelope); // // if (myRank == ROOT_RANK) { // free(board); // gfx_destroy(gfxContext); // } // // futhark_context_free(futharkContext); // futhark_context_config_free(contextConfig); // // MPI_Comm_free(&cartComm); // MPI_Comm_free(&rowComm); // MPI_Comm_free(&colComm); // MPI_Finalize(); // return 0; //} void print_chunk_board(chunk_info_t *ci) { for (int i = 0; i < ci->dimensions[0]; ++i) { for (int j = 0; j < ci->dimensions[1]; ++j) { printf("%d ", ((int8_t *) ci->data)[INDEX_2D_TO_1D(i, j, ci->dimensions[1])]); } printf("\n"); } } void init_chunk_board(chunk_info_t *ci) { for (int i = 0; i < ci->dimensions[0]; ++i) { for (int j = 0; j < ci->dimensions[1]; ++j) { ((int8_t *) ci->data)[INDEX_2D_TO_1D(i, j, ci->dimensions[1])] = rand() % 2; } } } void compute_next_chunk_board(struct dispatch_context *dc, struct futhark_context *fc, chunk_info_t *ci) { envelope_t outer_envelope = get_outer_envelope(dc, fc, 1); struct futhark_i8_2d *fut_north = futhark_new_i8_2d(fc, outer_envelope.north.data, outer_envelope.north.dimensions[0], outer_envelope.north.dimensions[1]); struct futhark_i8_2d *fut_north_east = futhark_new_i8_2d(fc, outer_envelope.north_east.data, outer_envelope.north_east.dimensions[0], outer_envelope.north_east.dimensions[1]); struct futhark_i8_2d *fut_east = futhark_new_i8_2d(fc, outer_envelope.east.data, outer_envelope.east.dimensions[0], outer_envelope.east.dimensions[1]); struct futhark_i8_2d *fut_south_east = futhark_new_i8_2d(fc, outer_envelope.south_east.data, outer_envelope.south_east.dimensions[0], outer_envelope.south_east.dimensions[1]); struct futhark_i8_2d *fut_south = futhark_new_i8_2d(fc, outer_envelope.south.data, outer_envelope.south.dimensions[0], outer_envelope.south.dimensions[1]); struct futhark_i8_2d *fut_south_west = futhark_new_i8_2d(fc, outer_envelope.south_west.data, outer_envelope.south_west.dimensions[0], outer_envelope.south_west.dimensions[1]); struct futhark_i8_2d *fut_west = futhark_new_i8_2d(fc, outer_envelope.west.data, outer_envelope.west.dimensions[0], outer_envelope.west.dimensions[1]); struct futhark_i8_2d *fut_north_west = futhark_new_i8_2d(fc, outer_envelope.north_west.data, outer_envelope.north_west.dimensions[0], outer_envelope.north_west.dimensions[1]); struct futhark_i8_2d *fut_chunk_board = futhark_new_i8_2d(fc, ci->data, ci->dimensions[0], ci->dimensions[1]); struct futhark_i8_2d *fut_next_chunk_board; futhark_entry_next_chunk_board(fc, &fut_next_chunk_board, fut_chunk_board, fut_north_west, fut_north, fut_north_east, fut_west, fut_east, fut_south_west, fut_south, fut_south_east); futhark_context_sync(fc); futhark_values_i8_2d(fc, fut_next_chunk_board, ci->data); futhark_free_i8_2d(fc, fut_chunk_board); futhark_free_i8_2d(fc, fut_next_chunk_board); futhark_free_i8_2d(fc, fut_north_west); futhark_free_i8_2d(fc, fut_north); futhark_free_i8_2d(fc, fut_north_east); futhark_free_i8_2d(fc, fut_west); futhark_free_i8_2d(fc, fut_east); futhark_free_i8_2d(fc, fut_south_west); futhark_free_i8_2d(fc, fut_south); futhark_free_i8_2d(fc, fut_south_east); envelope_free(&outer_envelope); } int main(int argc, char *argv[]) { MPI_Init(&argc, &argv); int my_rank; int world_size; MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); MPI_Comm_size(MPI_COMM_WORLD, &world_size); struct futhark_context_config *fut_config = futhark_context_config_new(); struct futhark_context *fut_context = futhark_context_new(fut_config); int board_n = atoi(argv[1]); int board_m = atoi(argv[2]); int board_dimensions[2] = {board_n, board_m}; struct dispatch_context *disp_context = dispatch_context_new(board_dimensions, sizeof(int8_t), 2); chunk_info_t ci = get_chunk_info(disp_context); init_chunk_board(&ci); /* GFX Initialization */ struct gfx_context_t *gfx_context = my_rank == ROOT_RANK ? gfx_create("Game of Life", (uint) board_dimensions[0], (uint) board_dimensions[0]) : NULL; if (my_rank == ROOT_RANK && !gfx_context) { fprintf(stderr, "Graphic mode initialization failed!\n"); return EXIT_FAILURE; } if (my_rank == ROOT_RANK) { SDL_ShowCursor(SDL_ENABLE); } bool exit = false; while (!exit) { /* GoL Iteration */ compute_next_chunk_board(disp_context, fut_context, &ci); /* Recover GoL board */ int8_t *board = get_data(disp_context); if (my_rank == ROOT_RANK) { SDL_PumpEvents(); SDL_Event event; SDL_PollEvent(&event); exit = gfx_keypressed() == SDLK_ESCAPE || (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE); gfx_clear(gfx_context, COLOR_BLACK); for (int y = 0; y < board_dimensions[0]; ++y) { for (int x = 0; x < board_dimensions[1]; ++x) { int cell = (int) board[INDEX_2D_TO_1D(y, x, board_dimensions[1])]; gfx_putpixel(gfx_context, x, y, MAKE_COLOR(cell * 255, cell * 255, cell * 255)); } } gfx_present(gfx_context); free(board); } MPI_Bcast(&exit, 1, MPI_C_BOOL, ROOT_RANK, MPI_COMM_WORLD); usleep(1000000 / FPS); } if (my_rank == ROOT_RANK) { gfx_destroy(gfx_context); } dispatch_context_free(disp_context); futhark_context_config_free(fut_config); futhark_context_free(fut_context); MPI_Finalize(); }