Supercomputing Applications

Lab 14B Report Form

Experimenting with the Parallel version

of the N-body program

Your name: __________________________________, Period: _____, Date __________

Explain how the parallel algorithm of gravityMPIShell6Particles.c is working.

RunSimulation uses malloc (memory allocation) to create an array of NumParticles. Describe the malloc statement here in your own words. What is the meaning of sizeof(Particle)*NumParticles as far as memory allocation:

malloc(sizeof(Particle)*NumParticles);

What is the purpose of (Particle *) in front of the malloc?

The first function call in RunSimulation is InitConfig(Particles,NumParticles); Inside this function, I've specifically assigned values for the positions of six particles. Sketch the initial position of the six particles. Use x and y axes with an origin for point of reference.

ComputeGravForces(Particles,NumParticles): Each process has a copy of this initial configuration. The next function call is to ComputeGravForces();. This is a lengthy function.

Particle *CommParticles = (Particle *)malloc(sizeof(Particle)*NumParticles); This creates a space for an auxiliary array to receive Particles from the processor on your left.

The loop below initializes the ForceAccumX and ForceAccumY to 0. These are used in the calculation of forces on each particle.

for (i=0; i<NumParticles; i++)

{

Particles[i].ForceAccumX=0;

Particles[i].ForceAccumY=0;

}

These statements determine the numerical value of the processor to your left (one less than you - or, if you're the root, the last process). Think of a ring of processes, the last process connects with the first. The processor to your right is numerically one more (unless you're the last process, then the root process is the process to your right, because of the ring formation).

// COMPUTE PROC IDS OF LEFT AND RIGHT NEIGHBORING PROCS

LeftProc = (MyID+NumProcs-1)%NumProcs;

RightProc = (MyID+1)%NumProcs;

What is the purpose of %NumProcs?

Explain in your own words what is happening with this next section of code:

for (k=0; k<NumProcs/2; k++)

{

// SEND UPDATED "RECEIVED" PARTICLES TO NEXT PROCESSOR

if (k>0)

MPI_Send(CommParticles,NumParticles,MPI_PARTICLE,

RightProc,0,MPI_COMM_WORLD);

// RECEIVE PARTICLES FROM PREV PROCESSOR (LEFT)

MPI_Recv(CommParticles,NumParticles,MPI_PARTICLE,

LeftProc,0,MPI_COMM_WORLD,&Status);

// COMPUTE FORCES BETWEEN RECEIVED AND LOCAL PARTICLES

// (UPDATE LOCAL AND RECEIVED PARTICLES)

for (i=0; i<NumParticles; i++)

for (j=0; j<NumParticles; j++)

{

ComputeGravForce(Particles[i],CommParticles[j],

&ForceX,&ForceY);

Particles[i].ForceAccumX+=ForceX;

Particles[i].ForceAccumY+=ForceY;

CommParticles[j].ForceAccumX-=ForceX;

CommParticles[j].ForceAccumY-=ForceY;

}

}

What is this code doing?

Run an experiment comparing the parallel MPI code with your serial, non-parallel, code from Lab14A. Verify if these two versions have the same behavior. Plot using Gnuplot the serial results and the parallel results to compare.

2006-02-08T14:15:41