Previous Section Table of Contents Next Section

16.3 Programming Tools

On most systems, a number of debugging tools are readily available. Others can be easily added. While most are designed to work with serial code, they are still worth mastering, since most of your errors will be serial in nature.

First, you should learn to use the features built into your programming language. For example, in C you might use asserts to verify the correct operation of your code. You should also learn how to write error handlers. This advice extends beyond the language to any libraries you are using. For example, MPI provides two error handlers, MPI_ERROR_ARE_FATAL and MPI_ERRORS_RETURN. And the MPICH implementation defines additional error handlers. While we have been ignoring them in our programming examples in order to keep the code as simple as possible, almost all MPI functions return error codes.

Next, learn to use the features provided by your compiler. Most compilers provide a wealth of support that is only a compile option or two away. Since the added checking increases compile time, these are generally disabled by default. But if you take the time to read the documentation, you'll find a lot of useful features. For example, with gcc you can use the options -Wall to turn on a number of (but not all) warnings, -ansi to specify the language standard to use, and -pedantic to issue all mandatory diagnostics, including those frequently omitted. mpicc will pass options like these on to the underlying compiler, so you can use them when compiling MPI programs. When using these, you'll likely see a number of warning messages that you can safely ignore, but you may find a pearl or two as well. Keep in mind that there are a large number of additional options available with gcc, so be sure to read the documentation.

Additionally, many systems have other utilities that can be helpful. The granddaddy of them all is lint. This is a program that analyzes code for potential errors with which most older compilers didn't bother. Most of the problems that lint checks for are now caught by modern compilers (if you use the right flags). Fortunately, lint has been superceded with more extensive checkers. If you are running Linux, you probably already have splint installed.

Here is an example of using splint. The -I option is used to include the path to the file mpi.h.

[sloanjd@amy AREA]$ splint -I/opt/lam-7.0/include rect.c

Splint 3.0.1.7 --- 24 Jan 2003

   

...

rect.c:80:13: Return value (type int) ignored: MPI_Recv(&chunk,...

rect.c:85:5: Return value (type int) ignored: MPI_Finalize( )

   

Finished checking --- 29 code warnings

Most of the output has been deleted (out of embarrassment), but you should get the idea. Of course, this is a working program. It just could be better.

There are a number of other tools that you might want to investigate. For example, memory checkers will examine your code for potential memory leaks. Probably the best known is the commercial product purify, but you might want to look at the GNU product checkergcc. Symbolic debuggers are described later in this chapter. And don't overlook profilers (described in Chapter 17). While not designed as debugging tools, they frequently reveal lots of problems.

    Previous Section Table of Contents Next Section