int MPI_Gatherv(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int *recvcounts, int *displs, MPI_Datatype recvtype, int root, MPI_Comm comm) { return PMPI_Gatherv(sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root, comm); }
int main(int argc, char **argv) { /* Validate arguments */ if (argc != 5) { fprintf(stderr, "Usage: %s [input file] [output file] [grid size] [iterations]\n", argv[0]); return 1; } double t1 = MPI_Wtime(); /* Initialize MPI */ int tasks, rank; MPI_Init(NULL, NULL); MPI_Comm_size(MPI_COMM_WORLD, &tasks); MPI_Comm_rank(MPI_COMM_WORLD, &rank); double t_init = MPI_Wtime(); /* Declare global variables */ double *initial = NULL; int N = atoi(argv[3]); int T = atoi(argv[4]); /*****************************************************************/ /* READ DATA */ /*****************************************************************/ if (rank == 0) { if (DEBUG) { fprintf(stderr, "\n-------------------------------------------\n"); fprintf(stderr, "Starting heat.c with %d processes\n", tasks); } /* Read data */ FILE *in = fopen(argv[1], "r"); initial = malloc(N * N * sizeof(double)); if (DEBUG) { for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { double val = (double) (i * (N - i - 1) * j * (N - j - 1)); initial[(i - 1) * N + (j - 1)] = val; } } } else { for (int i = 0; i < N * N; i++) { int x, y; double z; fscanf(in, "%d %d %lf\n", &x, &y, &z); initial[(x - 1) * N + (y - 1)] = z; } } fclose(in); } double t_read = MPI_Wtime(); /*****************************************************************/ /* DISTRIBUTE DATA */ /*****************************************************************/ /* Preliminaries */ int rowsPerWorker = N / tasks; int extra = N % tasks; /* Determine neighboring workers */ int pred = rank - 1; int succ = rank + 1; /* Determine how many values each worker will get */ int offset = 0; int offsets[tasks]; int items[tasks]; for (int i = 0; i < tasks; i++) { items[i] = rowsPerWorker * N; if (i < extra) items[i] += N; offsets[i] = offset; offset += items[i]; } /* Scatter the rows appropriately */ int myrows = items[rank] / N; /* Allocate an extra row of padding on either end */ double *current = calloc((items[rank] + 2 * N), sizeof(double)); double *old = calloc((items[rank] + 2 * N), sizeof(double)); if (DEBUG && rank == 0) fprintf(stderr, "scattering...\n"); PMPI_Scatterv(initial, items, offsets, MPI_DOUBLE, current + N, items[rank], MPI_DOUBLE, 0, MPI_COMM_WORLD); double t_scatter = MPI_Wtime(); /*****************************************************************/ /* CALCULATE */ /*****************************************************************/ MPI_Request req; double t_net = 0; for (int t = 0; t < T; t++) { if (DEBUG) fprintf(stderr, "Beginning iteration %d: rank %d\n", t, rank); /* Swap old and current so we can overwrite current */ double *temp = current; current = old; old = temp; /* Hold onto some useful pointers into old */ double *succrow = old + N * (myrows + 1); double *predrow = old; double *firstrow = old + N; double *lastrow = old + myrows; double t_temp = MPI_Wtime(); /* Send last row to succ and receive it from pred if eligible */ if (succ < tasks) { PMPI_Isend(lastrow, N, MPI_DOUBLE, succ, 0, MPI_COMM_WORLD, &req); } if (pred >= 0) { PMPI_Recv(predrow, N, MPI_DOUBLE, pred, 0, MPI_COMM_WORLD, 0); } /* Send first row to pred and receive it from succ if eligible */ if (pred >= 0) { PMPI_Isend(firstrow, N, MPI_DOUBLE, pred, 0, MPI_COMM_WORLD, &req); } if (succ < tasks) { PMPI_Recv(succrow, N, MPI_DOUBLE, succ, 0, MPI_COMM_WORLD, 0); } t_net += MPI_Wtime() - t_temp; /* Determine current from old, predrow, and succrow */ for (int j = 1; j <= myrows; j++) { for (int k = 0; k < N; k++) { /* Determine adjacent cells */ double left = 0, right = 0; if (k > 0 ) left = old[j * N + k - 1]; if (k < N - 1) right = old[j * N + k + 1]; double top = old[(j - 1) * N + k]; double bottom = old[(j + 1) * N + k]; double focus = old[j * N + k]; /* Calculate the new cell value */ current[j * N + k] = focus + .1 * (top + bottom - 2 * focus) + .1 * (left + right - 2 * focus); } } } free(old); double t_work = MPI_Wtime(); /*****************************************************************/ /* WRITE THE OUTPUT */ /*****************************************************************/ PMPI_Gatherv(current + N, items[rank], MPI_DOUBLE, initial, items, offsets, MPI_DOUBLE, 0, MPI_COMM_WORLD); double t_gather = MPI_Wtime(); free(current); if (rank == 0 && !DEBUG) { FILE *out = fopen(argv[2], "w"); for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { fprintf(out, "%d %d %lf\n", i, j, initial[i * N + j]); } } fclose(out); } double t2 = MPI_Wtime(); if (rank == 0) { fprintf(stderr, "-----------------------------------------\n"); fprintf(stderr, "TIMING INFORMATION \n"); fprintf(stderr, "-----------------------------------------\n"); fprintf(stderr, "RANK INIT READ SCATTER WORK GATHER WRITE TOTAL NET\n"); } MPI_Barrier(MPI_COMM_WORLD); fprintf(stderr, "%4.2d %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n", rank, t_init - t1, t_read - t_init, t_scatter - t_read, t_work - t_scatter, t_gather - t_work, t2 - t_gather, t2 - t1, t_net); free(initial); MPI_Finalize(); return 0; }