/** * Creates a matrix from an input stream. Returns data as an array of rows. * Caller responsible for freeing returned structure. */ Matrix* create_matrix(FILE *in) { Matrix *m = NULL; int rows = 0; int columns = 0; if (!at_valid_matrix(in)) goto MatrixMalformedError; if (!read_dims(in, &rows, &columns)) { goto MatrixDimError; } m = new_matrix(rows, columns); int i = 0; for (i = 0; i < m->rows; ++i) { if (!read_row(in, m->data[i], m->columns)) { goto MatrixEntryError; } } return m; // evil gotos for exception handling MatrixMalformedError: printf("The input.dat file appears corrupt, are you sure it's the proper format?\n"); goto FreeAndReturn; MatrixDimError: printf("Matrix dimension data corrupt\n"); goto FreeAndReturn; MatrixEntryError: printf("Matrix data corrupt\n"); goto FreeAndReturn; FreeAndReturn: free_matrix(&m); return NULL; }
/* main entry point to program. Determines number of tasks, the 0 task becomes the head, reading the data and broadcasting it to all other tasks which act as workers. The 0 task then computes its portion of the result and then receives the results from all workers. The result is then printed. */ int main(int argc, char *argv[]) { int i, head, lo, hi, me, tasks; int a_rows, a_cols, a_cells, b_rows, b_cols, b_cells; int *recv_cnts, *disps; int *datapack, *temp; FILE *fp; MPI_Status status; /* init MPI, retrieve number of tasks, retrieve my index in tasks */ MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &tasks); MPI_Comm_rank(MPI_COMM_WORLD, &me); /* first task is head, collecting results */ head = 0; /* check for input file parameter */ if (argc < 2) { if (me == head) BAIL_ALL("Please provide an input parameter"); } if (me == head ) { /* create arrays for receive counts and displacements for MPI_Gatherv */ if ((recv_cnts = (int *)malloc(tasks*sizeof(int))) == NULL) BAIL_ALL("Unable to allocate receive counts array"); if ((disps = (int *)malloc(tasks*sizeof(int))) == NULL) BAIL_ALL("Unable to allocate displacements arrary"); /* attempt to open the input file */ if ((fp = fopen(argv[1], "r")) == NULL) BAIL_ALL("Unable to open the input file"); while (!feof(fp)) { /* read the dimensions of matrix A */ if (!read_dims(fp, &a_rows, &a_cols)) BAIL_ALL("Unable to read the dimensions of matrix A"); a_cells = a_rows * a_cols; /* allocate the space for the dimensions and matrix A */ if ((datapack = (int *)malloc((2+a_cells)*sizeof(int))) == NULL) BAIL_ALL("Unable to allocate space for matrix A"); /* put row and column data in the datapack */ datapack[0] = a_rows; datapack[1] = a_cols; /* attempt to read in the matrix A values */ if (read_matrix(fp, datapack+2, a_cells) < a_cells) BAIL_ALL("Unable to read the contents of matrix A"); /* read the dimensions of matrix B */ if (!read_dims(fp, &b_rows, &b_cols)) BAIL_ALL("Unable to read the dimensions of matrix B"); b_cells = b_rows * b_cols; /* allocate the extra space for dimensions and matrix B */ if ((datapack = (int *)realloc(datapack, (4+a_cells+b_cells)*sizeof(int))) == NULL) BAIL_ALL("Unable to allocate space for matrix B"); /* put row and column data in the datapack */ datapack[2 + a_cells] = b_rows; datapack[3 + a_cells] = b_cols; /* attempt to read in the matrix B values */ if (read_matrix(fp, datapack+4+a_cells, b_cells) < b_cells) BAIL_ALL("Unable to read the contents of matrix B"); /* check for multiplication compatibility */ if (a_cols != b_rows || a_rows < 1 || a_cols < 1 || b_rows < 1 || b_cols < 1) { printf("Matrix A and B are not multiplicative compatible\n"); } else { /* calc the range of cells I am responsible for */ calc_range(a_rows*b_cols, me, tasks, &lo, &hi); /* allocate an array for the portion I will compute */ if ((temp = (int *)malloc((hi-lo+1)*sizeof(int))) == NULL) BAIL_ALL("Unable to allocate space for the temp array"); /* tell the workers the size of the datapack coming in */ i = 4 + a_cells + b_cells; MPI_Bcast(&i, 1, MPI_INT, me, MPI_COMM_WORLD); /* send the datapack to the workers */ MPI_Bcast(datapack, 4+a_cells+b_cells, MPI_INT, me, MPI_COMM_WORLD); /* calculate my portion of the results */ for (i=lo; i<=hi; i++) { temp[i-lo] = calc_cell(datapack+2, datapack+4+a_cells, a_cols, a_rows, b_cols, i); } /* calculate the proper displacements and sizes for returned results */ for (i=0; i<tasks; i++) { int worker_hi; calc_range(a_rows*b_cols, i, tasks, disps+i, &worker_hi); recv_cnts[i] = worker_hi - disps[i] + 1; } /* print out the matrices */ printf("MATRIX A\n"); print_matrix(datapack+2, a_rows, a_cols); printf("MATRIX B\n"); print_matrix(datapack+4+a_cells, b_rows, b_cols); /* gatherv the results */ MPI_Gatherv(temp, hi-lo+1, MPI_INT, datapack, recv_cnts, disps, MPI_INT, me, MPI_COMM_WORLD); /* print out the result */ printf("RESULT\n"); print_matrix(datapack, a_rows, b_cols); free(temp); } free(datapack); } } else { /* not the head task */ for (;;) { /* check if more results are coming */ MPI_Bcast(&i, 1, MPI_INT, head, MPI_COMM_WORLD); if (!i) break; /* allocate space for the data pack */ datapack = (int *)malloc(i*sizeof(int)); /* receive the datapack */ MPI_Bcast(datapack, i, MPI_INT, head, MPI_COMM_WORLD); /* get values from the data pack */ a_rows = datapack[0]; a_cols = datapack[1]; a_cells = a_rows*a_cols; b_rows = datapack[2 + a_cells]; b_cols = datapack[3 + a_cells]; b_cells = b_rows*b_cols; /* calculate the range of cells that I am responsible for */ calc_range(a_rows*b_cols, me, tasks, &lo, &hi); /* allocate an array for the results I will send back */ temp = (int *)malloc((hi-lo+1)*sizeof(int)); /* and calculate my set of results */ for (i=lo; i<=hi; i++) { temp[i-lo] = calc_cell(datapack+2, datapack+4+a_cells, a_cols, a_rows, b_cols, i); } /* return the values to the head task */ MPI_Gatherv(temp, hi-lo+1, MPI_INT, NULL, NULL, NULL, MPI_INT, head, MPI_COMM_WORLD); free(datapack); free(temp); } } if (me == head) { fclose(fp); BAIL_ALL("Job complete!"); } /* shut down */ MPI_Finalize(); exit(0); }