Programming Lab #4: Programming with MPI

Due: Friday, March 4, 2011 at 9pm


Changelog

Date Description
17-Feb-11 Original posting
23-Feb-11 Discussion about plotting
1-Mar-11 Stdout and stderr


In this assignment you'll port, to MPI, the electrophysiology simulator you used in the second assignment Your existing multithreaded implementation may help save you time in getting started. Try and make the code go as fast as you can.

Let one of the MPI processes handle the plotting capability. Your code must properly handle values of N that aren't evenly divisible by the processor geometry (specified by the -x and -y command line flags). If working in groups of two, you must implement both one and two-dimensional processor geometries. (Those working on their own only need to support 1D geometries) Unfortunately, the ieng6 servers do not have sufficient numbers of processors to demonstrate the need for multidimensional geometries. In class, we will look at results from a large scale machine to demonstrate why we need multidimensional partitionings.

In the spirit of friendly competition, post your performance results to the A4 Moodle forum.

A new provided code has been installed in $PUB/HW/A4. It is nearly identical to the code from Assignment #2, with changes to cmdLine.cpp, report.cpp, apf.cpp to handle a new command line argument and replace the timer call with the MPI Timer. As in Assignment two, refrain from changing any files mentioned in the README file.

How to test your code

Test your code by comparing the summary norms (L2 and Max) against results on 1 processor.

How to take timings

To take timings, use MPI's timer function MPI_Wtime() to measure wall clock time. To measure time, take the difference in times sampled by two successive calls to MPI_Wtime():

        double t0   = MPI_Wtime(); 
        // some code....
        double t1   = MPI_Wtime();
        double time = (t1-t0);

MPI_Wtime() reports time in seconds and its man-page is available using the man command on the ieng6 servers.

Recall that the running time of the application is that of the last processor to finish. Don't time individual iterations, but rather, time an entire run, but excluding initialization, calls to MPI_Init() and MPI_Finalize() and any other activities that are not representative of a run with many iterations. communication time.

It can be difficult to measure communication times accurately, owing to the short time durations involved. Therefore, we will use an indirect measurement technique. We do this by disabling communication of ghost cells and subtracting the resultant time from that obtained from a run that includes communication. To this end, we have added a new -k command line option (cmdLine.cpp). When -k is asserted, your code should disable all calls to MPI Send, Isend, Ireceive and Receive, that handle ghost cell communication, as well as any code needed to pack message buffers. Do not disable any other message passing calls unless you deem this necessary.

Your timings will reflect contention from other jobs. To avoid the effects of contention, we'll use the following technique to filter out the variations. Run the program at least 3 times (for each input size and number of cores, or any variable that affects the running time) until you see a consistent timing emerge, such that a majority of the timings agree to within 10%. If you observe a lot more variation, then try doubling the number of runs to see if you can obtain a better consensus. Exclude outlying timings, but note them in your report. Report the minimal running time rather than the average, as previously discussed in class.

Plotting Capability

When implementing the simulator's plotting capability (enabled by the -p flag), you will need to gather all the data on one processor before plotting. However, you must still store the solution in a distributed form as discussed in class today, where each processor holds a portion of the solution, plus the ghost cells. You should use a MPI Gather operations (see links to documentation below) to collect all the pieces onto the one processor, taking care not to plot ghost cells. Solutions that employ point to point sends instead of Gather will lose some credit.

Gathering 2D blocked data is a challenge. Since time is short, we'll simplify the requirements for plotting.

The plotting feature need only support 1D partitioning 

Remember, you still need to support 2d partitioning of the computation. But plotting will only handle runs where the data has been partitioned with one of the -x and -y flags set to 1.

Building and Running MPI Code

Some sample MPI applications have been installed in $(PUB)/Examples/MPI, and a new "arch" file arch.gnu.mpi has been installed in $(PUB)/Arch.

The Makefile for the present assignment uses the MPI version of the "arch" file, as we will use special versions of the compiler set up for MPI (the compiler commands are actually wrappers to gcc). Be sure to that your Makefile properly defines the PUB macros, and that it includes the correct "arch" file as follows.

PUB     = /home/linux/ieng6/cs160w/public/
include $(PUB)/Arch/arch.gnu.mpi

You may develop code on any machine that runs MPI, but your assignment will be graded against behavior on ieng6-204, so you be sure that your report is based on results obtained from that machine.


Turnin

Turn in your source code electronically not later than the deadline at 9pm on the day the assignment is due. We will provide instructions about the electronic turnin procedure on Moodle.

The timestamp on the electronic turnin establishes the time that you handed in the assignment, and successive turnins will overwrite any existing turnin. Once the deadline has passed (with a few minutes' grace period), you will not be able to turn in your assignment. Be careful to turn in on time.

Important Note: Since the turnin script will try to compile your project before letting you submit your assignment, it's important that you turn in all the files you have. However, when grading your assignment, we will substitute all the files that you are not allowed to modify (as noted in the list above) with the original copies of the version we provided you. This is why it is important that you do not change those files in your own turnin, as they will be lost.

Don't wait until the last minute to attempt a turnin for the first time. The turnin program will ask you various questions, and it will check for the presence of certain required files, as well as your source code. It will also build the source code if you like, to catch any obvious build errors. Try out the turnin process early on so you are sure that you you are familiar with the process, and that all the required additional files are present.

Your turnin must include a valid team self-evaluation discussing the division of labor and other aspects of how you worked together as a team. A copy of the form is available in $PUB/turnin/teameval.txt. This form is mandatory, as the turnin process will not complete without it. You must also provide a MEMBERS file that identifies your team members, with your full names and email addresses. A template showing the format can be found in $PUB/turnin/MEMBERS. Empty forms, or formed not diligently fill out, will result in a 10% penalty being assessed, in addition to holding up the grading process.


Stdout and Stderr

While the PPF package can help sort out some I/O problems, it can only synchronize a single line of output. When you have multiple lines, and you are using PPF_Print() or just printf(), you will find that fflush() does not sort out the problem of garbled I/O.

The only sure way of getting I/O to stdout (or stderr) to properly synchronize is to use sprintf() to generate string output, and then collect via Gatherv() at the root. In other words, only 1 process should actually perform the I/O.

There is an example in the publicly available Ring benchmark code:

$PUB/Examples/MPI/Ring/getHost.C

MPI Documentation

There is a nice tutorial with some worked examples. Man pages for the MPI calls may be accessed with the man command and they are also available On-line. More extensive documentation can be found at http://www-cse.ucsd.edu/users/baden/Doc/mpi.html. The on-line man pages for MPI calls used in this assignment appear below.

MPI _Init Initialize the MPI environment. Call this prior to making any MPI calls.
MPI_Finalize Exit the MPI environment. Call this function before exiting your program.
MPI_Comm_size Queries the total number of processes use in this program invocation.
MPI_Comm_rank Queries this process's unique identifier, an integer called the rank
MPI _Send Sends a message to another process, a return signifies that the message buffer may be reused.
MPI_Recv Receives a message from another process, a return signifies that the message has been received.
MPI_Irecv Immediate form of Receive. A return does not signify that the message has been received. For this you need to use MPI_Wait()
MPI_Wait Return indicates that a previously posted Irecv (or Isend) has completed
MPI_Wtimer Timer.
MPI_Gather Gathers data from all processes onto the designated root process. All processes contribute the same amount of data. A collective routine, which all processes in the communicator must call.
MPI_Gatherv The "Vector" version of Gather(). Unlike Gatherv(), processes may contribute different amounts of data. Requires a call to Gather() to determine the sizes of the gathered data contributions. A collective routine, which all processes in the communicator must call.
MPI_Barrier Blocks calling process until all processes have checked in. A collective routine, which all processes in the communicator must call.


Copyright © 2011 Scott B. Baden   [Wed Feb 23 16:13:10 PST 2011]