Professor Norm Matloff
University of California, Davis
Go to the Omni home page.
You'll need gcc, and either bison or yacc.
Unpack and build, e.g. for version 1.6 (as of September 2009, version 2.0 is beta but looks good):
gunzip -c Omni-1.6.tar.gz | tar xpf - cd Omni-1.6 configure make make install
I would suggest that you add the flag --without-jvm in your configure command.
This will install in /usr/local. To install in some other directory, say /x/y/z, change the configure command above to
configure --prefix=/x/y/z --enable-gcc
If configure finds that you lack yacc, use a substitute, e.g. byacc. If you later find problems, rebuild without --enable-gcc.
To compile a C program x.c, type
omcc -g x.c
The -t option to omcc is very useful. It outputs a file tmp.c which shows the result of applying the various OpenMP macros to the user's source file x.c. By correlating the latter file with tmp.c, one can see exactly how the OpenMP constructs are being implemented. This can be helpful in performance issues, and for debugging.
To set the number of threads, say to 4, type (e.g. for the C shell)
setenv OMPC_NUM_PROCS 4
Then just run the executable produced from your compilation step.
The information here focuses on use of the GDB debugger (or DDD as a GUI front end to GDB). Note that there are other options, such as commercial products like TotalView.
Using a symbolic debugger on code which uses macros is often difficult. Since the executable file is generated not from the user's original source file but rather from output of the preprocessor's work on that file, it is difficult to maintain connections to the original source. This is why, for instance, some debuggers do not support C++'s STL.
In this light, note that the compiler renames your function main() to _ompc_main(). Your other variable names should be the same as before.
Along these same lines, note that GDB's focus at startup, i.e. the point of reference for commands, will be the file which is the result of the preprocessing, not your source file. To specify a line in the latter, you must specify its name, e.g.
b myfile.c:35
to set a breakpoint at line 35 of myfile.c. Once you reach a line in that file, the focus is there, so you no longer need to specify the file name.
Make sure to make calls to omp_get_num_threads() and omp_get_thread_num() , whether you need them or not. The presence of these calls seems to help, somehow.
If you haven't used GDB with threads before (but are experienced with GDB), here is an example, consisting of part of a debugging session on my Dijkstra example (on a uniprocessor system) . First I compiled, and set the number of threads.
% omcc -g Dijkstra.c Compiling 'Dijkstra.c'... % setenv OMPC_NUM_PROCS 2
I then ran my program in GDB. Note that GDB announces the threads when they are created:
% gdb a.out GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) Copyright 2003 Free Software Foundation, Inc. ...
We would first set our initial breakpoints. Note that since our program actually begins execution in the Omni code rather than our own, we must qualify breakpoint commands with our source file name, e.g.
(gdb) b Dijkstra.c:85
Then run:
(gdb) r 1 Starting program: /home/matloff/a.out 1 [New Thread 1073969376 (LWP 2980)] [New Thread 1377004336 (LWP 3005)]
Remember, there are two threads here, and either of them could hit the breakpoint. One of them does:
Breakpoint 1, __ompc_func_0 () at Dijkstra.c:102 102 updateohd(startv,endv);
Which thread is this, and where is the other thread? We can find out:
(gdb) info threads 2 Thread 1377004336 (LWP 3005) 0xffffe002 in ?? () * 1 Thread 1073969376 (LWP 2980) __ompc_func_0 () at Dijkstra.c:102
The asterisk on the second line says tat we are now in thread 1. We can switch to thread 2 if we like:
(gdb) thread 2 [Switching to thread 2 (Thread 1377004336 (LWP 3005))]#0 0xffffe002 in ?? () (gdb) bt
Here we have switched to thread 2, and used the bt command to find out where it is. We could then issue the GDB c command to continue in this thread, or we could switch back to thread 1 before continuing. Either way, both threads will continue to execute (concurrently, on this uniprocessor system, or in parallel, on a multiprocessor system), and either one could be the next one to hit the breakpoint again.
Issuing the command thread, without a number, will return the number of the current thread.