|C H A P T E R 13|
Debugging OpenMP Programs
The OpenMP application programming interface (API) is a portable, parallel programming model for shared memory multiprocessor architectures, developed in collaboration with a number of computer vendors. Support for debugging Fortran and C OpenMP programs with dbx is based on the general multi-threaded debugging features of dbx. All of the dbx commands that operate on threads and LWPs can be used for OpenMP debugging. dbx does not support asynchronous thread control in OpenMP debugging.
This chapter is organized in to the following sections:
See the OpenMP API Users Guide for information on the directives, run-time library routines, and environment variables comprising the OpenMP Version 2.0 Application Program Interfaces, as implemented by the Sun Studio Fortran 95 and C compilers.
To better describe OpenMP debugging, it is helpful to understand how OpenMP code is transformed by the compilers. Consider the following Fortran example:
The code in line 12 through line 18 is a parallel region. The f95 compiler converts this section of code to an outlined subroutine that will be called from the OpenMP runtime library. This outlined subroutine has an internally generated name, in this case _$d1A12.MAIN_. The f95 compiler then replaces the code for the parallel region with a call to the OpenMP runtime library and passes the outlined subroutine as one of its arguments. The OpenMP runtime library handles all the thread-related issues and dispatches slave threads that execute the outlined subroutine in parallel. The C compiler works in the same way.
When debugging an OpenMP program, the outlined subroutine is treated by dbx as any other function, with the exception that you cannot explicitly set a breakpoint in that function by using its internally generated name.
In addition to the usual functionality for debugging multithreaded programs, dbx allows you to do the following in an OpenMP program:
For example, refer to the Fortran code inHow Compilers Transform OpenMP Code, and assume that master thread t@1 is at line 10. You single step into line 12, and slave threads t@2, t@3, and t@4 are created to execute the runtime library calls. Thread t@3 reaches the breakpoint first and causes the program execution to stop. So the single step that was initiated by thread t@1ends on thread t@3.This behavior is different from normal stepping in which you are usually on the same thread after the single step as before.
When execution is stopped in parallel region, a where command shows a stack trace that contains the outlined subroutine as well as several runtime library calls. Using the Fortran example from How Compilers Transform OpenMP Code, and stopping execution at line 15, the where command produces the following stack trace.
The top frame on the stack is the frame of the outlined function. Even though the code is outlined, the source line number still maps back to 15. The other two frames are for runtime library routines.
When execution is stopped in a parallel region, a where command from a slave thread does not have a stack traceback to its parent thread, as shown in the above example. A where command from the master thread, however, has a full traceback:
If the number of threads is not large, you might be able to determine how execution reached the breakpoint in a slave thread by using the threads command (see threads Command) to list all the threads, and then switch to each thread to determine which one is the master thread.
When execution is stopped in a parallel region, a dump command may print more than one copy of private variables. In the following example, the dump command prints two copies of the variable i:
Two copies of variable i are printed because the outlined routine is implemented as a nested function of the hosting routine, and private variables are implemented as local variables of the outlined routine. Since a dump command prints all the variables in scope, both the i in hosting routine and the i in the outlined routine are displayed.
When you are single stepping inside of a parallel region in an OpenMP program, the execution sequence may not be the same as the source code sequence. This difference in sequence occurs because the code in the parallel region is usually transformed and rearranged by the compiler. Single stepping in OpenMP code is similar to single stepping in optimized code where the optimizer has usually moved code around.