/* Composite model of sequential and parallel 1d-diffusion solvers. * Compares the results of the sequential and parallel computation to * determine functional equivalence of the two versions. * * The initial values are taken as inputs. The two global boundary * points are fixed. * * Command line example: civl verify -inputNPROCSB=3 -inputNSTEPSB=3 -inputWSTEP=1 \ -inputNXB=6 diffusion1d.cvl */ #include #include #include #include // Definitions from programs: #define OWNER(index) ((nprocs*(index+1)-1)/nx) // inputs: $input int NPROCS; // number of processes for parallel version $input int NPROCSB; // upper bound on nprocs $input double K; // k = alpha^2 * dt/(dx^2) $input int NSTEPS; // number of time steps $input int WSTEP; // write every this many time steps $input int NSTEPSB; // upperbound on nsteps $input int NX; // global number of discrete spatial points $input int NXB; // upper bound on nx $input double u_init[NX]; // initial values for temperature (u) // assumptions: $assume 2 <= NX && NX <= NXB; $assume K>0 && K<.5; $assume NSTEPS >= 1; // check this: wstep >= 1 && wstep <= NSTEPS; $assume NX > NPROCS; $assume 0 < NPROCS && NPROCS <= NPROCSB; $assume 0 < NSTEPS && NSTEPS <= NSTEPSB; // global variables: int output_seq[NX]; // final (color) result of sequential computation int output_par[NX]; // final (color) result of parallel computation $proc procs[NPROCS]; // the MPI processes $gcomm MPI_GCOMM_WORLD; // the global communicator object // MPI model: typedef enum {MPI_INT, MPI_DOUBLE} MPI_Datatype; #define BCAST_TAG 999 #define MPI_PROC_NULL -1 typedef struct { int size; int source; int tag; } MPI_Status; #define MPI_STATUS_IGNORE NULL int sizeofDatatype(MPI_Datatype datatype) { switch (datatype) { case MPI_INT: return sizeof(int); case MPI_DOUBLE: return sizeof(double); default: $assert(0, "Unreachable"); } } /* Sends a message. */ void MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, $comm comm) { if (dest >= 0) { int size = count*sizeofDatatype(datatype); $message out = $message_pack(comm->place, dest, tag, buf, size); $comm_enqueue(comm, out); } } /* Receives a message. */ void MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, $comm comm, MPI_Status *status) { if (source >= 0) { $message in = $comm_dequeue(comm, source, tag); int size = count*sizeofDatatype(datatype); $message_unpack(in, buf, size); if (status != MPI_STATUS_IGNORE) { status->size = $message_size(in); status->source = $message_source(in); status->tag = $message_tag(in); } } } void MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count) { *count = status->size/sizeofDatatype(datatype); } void MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, $comm comm, MPI_Status *status) { MPI_Send(sendbuf, sendcount, sendtype, dest, sendtag, comm); MPI_Recv(recvbuf, recvcount, recvtype, source, recvtag, comm, status); } /* Broadcasts a message from root to everyone else. * Need to use a differnt comm. */ void MPI_Bcast(void *buf, int count, MPI_Datatype datatype, int root, $comm comm) { int place = $comm_place(comm); if (place == root) { int nprocs = $comm_size(comm); for (int i=0; i=2); assert(k>0 && k<.5); assert(nsteps >= 1); assert(wstep >= 1 && wstep <=nsteps); u = (double*)$malloc(seq_scope, nx*sizeof(double)); assert(u); for (i = 0; i < nx; i++) u[i] = u_init[pos++]; } void write_frame(int time) { for (int i=0; i=nprocs); assert(k>0 && k<.5); assert(nx>=2); assert(nsteps>=1); first = firstForProc(rank); nxl = countForProc(rank); if (first == 0 || nxl == 0) left = MPI_PROC_NULL; else left = OWNER(first-1); if (first+nxl >= nx || nxl == 0) right = MPI_PROC_NULL; else right = OWNER(first+nxl); u = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double)); assert(u != NULL); u_new = (double*)$malloc(proc_scope, (nxl+2)*sizeof(double)); assert(u_new != NULL); if (rank == 0) { buf = (double*)$malloc(proc_scope, (1+nx/nprocs)*sizeof(double)); for (i=1; i <= nxl; i++) u[i] = u_init[pos++]; // instead of reading from file for (i=1; i < nprocs; i++) { for (j=0; j