High Performance Linux Clusters with OSCAR, Rocks, OpenMosix, and MPI [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

High Performance Linux Clusters with OSCAR, Rocks, OpenMosix, and MPI [Electronic resources] - نسخه متنی

Joseph D. Sloan

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








16.6 Symbolic Debuggers


If these first two approaches
don't seem to be working for you,
it's time to turn to a symbolic debugger. (Arguably,
the sooner you switch to a symbolic debugger, the better.) Symbolic
debuggers will allow you to trace the execution of your program, stop
and examine variables, make changes, and resume execution. While
you'll need to learn how to use them, most are
fairly intuitive and don't take long to master. All
you really need to do is learn a few basic commands to get started.
You can learn more commands as the need arises.

There are a number of symbolic debuggers available, including
debuggers that are specifically designed to work with parallel
programs such as commercial products like
TotalView. With a little extra effort,
you'll probably be able to get by with some more
common debuggers. In this chapter we'll look at
gdb and ddd, first with
serial programs and then with parallel programs.

gdb is a command-line symbolic debugger from the
GNU project. As such, it is freely available. You probably already
have it installed on your Linux system. ddd is a
GUI frontend that can be used with gdb (or other
debuggers) in an X Window System environment.[1] You may need to install ddd, but the
process is straightforward and is described in Chapter 9.

[1] There
are other friendly ways of running gdb.
xxgdb is an X Windows System version.
gdb is often run from within Emacs.



16.6.1 gdb


To
demonstrate gdb, we'll use the
program
area.cChapter 13
with one slight added error. (Also, the macro for
f has been replaced with a function.) Here is the
now buggy code:

#include <stdio.h>
/* problem parameters */
#define numberSteps 50
#define lowerLimit 2.0
#define upperLimit 5.0
double f(double x)
{
return x*x;
}
int main ( int argc, char * argv[ ] )
{
int i;
double area = 0.0;
double step = (upperLimit - lowerLimit) / numberSteps;
double at, height;
for (i = 0; i <= numberSteps; i--)
{ at = lowerLimit + i * step + step / 2.0;
height = f(at);
area = area + step * height;
}
printf ("The area from %f to %f is: %f\n",
lowerLimit, upperLimit, area );
return 0;
}

If you try to run this, it doesn't print anything
and doesn't return. With that kind of behavior, it
is pretty easy to guess that there is something wrong with the loop.
But let's play dumb for a moment and see how we
could discover this using gdb.

Before you can run
gdb with a program, you should compile that
program with the -g option.

[sloanjd@amy DEBUG]$ gcc -g area.c -o area

The -g option generates code that produces
debugging information. This is necessary to make the symbol table
available so that you can refer to variables by name.

Unlike most compilers, gcc will allow you to use
an optimization option (-O) with
-g. Keep in mind that optimizing code may reorder
instructions or may eliminate variables. This can be mind-boggling to
a debugger so, in general, you should avoid optimizing your code when
you plan to use a symbolic debugger. With gcc,
you have some latitude, but beware!

Once the code is properly compiled, you can start
gdb. There are several ways to do this, but the
simplest is to pass the name of the program as a command-line
argument. For example,

[sloanjd@amy DEBUG]$ gdb -q area
(gdb)

In this case, the
-q option is used to
suppress the general information that it prints by default. When the
program is loaded and ready to go, it returns the
(gdb) prompt. You can get a list of command
categories by typing help at the prompt. To see a
listing of the commands within a category, type
help followed by the category name, for example,
help data. Commands may be abbreviated provided
the shortened name is unambiguous. For example,
append may be shortened to app
but not to ap since it would be confused with
apropos.

The most reasonable place to start is
probably the list command (abbreviated
l). list will begin listing
your program, 10 lines at a time.

(gdb) l
7
8 double f(double x)
9 {
10 return x*x;
11 }
12
13 int main ( int argc, char * argv[ ] )
14 {
15 int i;
16 double area = 0.0;

If you continue with list, it will display the
next 10 lines of code. If you give it a single numeric value, it will
list 10 lines starting at that line. If you give it two numeric
values separated by a comma, it will treat those values as a range
and print that code. For example,

(gdb) l 18,20
18 double at, height;
19
20 for (i = 0; i <= numberSteps; i--)

If you enter help list at the prompt,
you'll see a list of additional ways to use
list.

Next, let's put a
breakpoint
on line 20. A breakpoint allows you to start a program and have it
automatically stop when it reaches the target line. If the line is
never reached, e.g., it is embedded in a conditional statement that
fails, then the code won't stop. If the line is
executed several times, such as a breakpoint within a loop, it will
stop each time.

(gdb) b 20
Breakpoint 1 at 0x804836e: file area.c, line 20.

You can list breakpoints with the info
breakpoint
command. Type help
b
at the prompt to learn more breakpoints and the commands
that can be used with them. (gdb also supports
watchpoints,
which stop when a watched variable changes, and
catchpoints,
which catch an exception).

Now let's run the program.

(gdb) run
Starting program: /home/sloanjd/DEBUG/area
Breakpoint 1, main (argc=1, argv=0xbfffe774) at area.c:20
20 for (i = 0; i <= numberSteps; i-)

You'll note that it stopped at our breakpoint as
expected.

Let's look at a few variables to make sure
everything has been initialized correctly.

(gdb) print area
$1 = 0
(gdb) print step
$2 = 0.059999999999999998

So far, everything looks good.

(gdb) print numberSteps
No symbol "numberSteps" in current context.

This may look like a problem, but it isn't.
You'll recall that numberSteps
isn't a program variable. It was defined with a
#define statement. The preprocessor substitutes
the value for the name throughout the program before compilation, so
we won't be able to look at this with the debugger.
That's not a big problem but something you should be
aware of.

We can step through individual lines of code with the
next command.

(gdb) n
21 { at = lowerLimit + i * step + step / 2.0;
(gdb) n
22 height = f(at);
(gdb) n
23 area = area + step * height;
(gdb) n
24 for (i = 0; i <= numberSteps; i++)

The
step command is just like the
next command except that next
will treat a subroutine call as one instruction while
step will enter into the subroutine.

We'll come back to step after we
have looked at some of the variables.

(gdb) print area
$3 = 0.24725399999999992
(gdb) print height
$4 = 4.1208999999999989
(gdb) print step * height
$5 = 0.24725399999999992

Notice that print will handle expressions as well
as simple variables, a real convenience. Everything still looks good.

Going back to step, here is the second iteration
of the loop traced with step.

(gdb) s
21 { at = lowerLimit + i * step + step / 2.0;
(gdb) s
22 height = f(at);
(gdb) s
f (x=2.0899999999999999) at area.c:10
10 return x*x;
(gdb) s
11 }
(gdb) s
main (argc=1, argv=0xbfffe774) at area.c:23
23 area = area + step * height;
(gdb) s
20 for (i = 0; i <= numberSteps; i++)

Notice that we are diving into the function f.

The body of the loop seems to be working correctly. Maybe there is
something wrong with the print statement? To examine the values it is
getting, we'll set a second breakpoint and resume
execution.

(gdb) l 25,27
25
26 printf ("The area from %f to %f is: %f\n",
27 lowerLimit, upperLimit, area );
(gdb) b 26
Breakpoint 2 at 0x80483c4: file area.c, line 26.
(gdb) continue
Continuing.

At this point the program hangs. Since the body of the loop looks OK
and we aren't getting to the
printf, there must be something wrong with the
loop control structure.

Let's interrupt the program (CTRL-C) and examine the
counter i.

Program received signal SIGINT, Interrupt.
0x0804833d in f (x=-83775291.069999993) at area.c:10
10 return x*x;
(gdb) print i
No symbol "i" in current context.
(gdb) n
11 }
(gdb) n
main (argc=1, argv=0xbfffd774) at area.c:23
23 area = area + step * height;
(gdb) print i
$7 = -1396254885

When the program was interrupted, we were in the function
f so i was out of scope. We
needed to step through a couple of instructions to return to the main
program to examine i. And when we did, we saw that
something was obviously wrong.

We can change the value of i and continue.

(gdb) set var i=51
(gdb) continue
Continuing.
Breakpoint 2, main (argc=1, argv=0xbfffd774) at area.c:26
26 printf ("The area from %f to %f is: %f\n",

With an appropriate value of i, we exit the loop.
Clearly, i isn't being updated
appropriately.

We can continue until the end now, although our output
won't make much sense, and then exit
gdb.

(gdb) continue
Continuing.
The area from 2.000000 to 5.000000 is: 203220027199808325287936.000000
Program exited normally.
(gdb) q

Or we could have just quit where we were.

No doubt you noticed that the code had been changed from
i++ to i-- long before the end
of this section. This is definitely a problem that rereading the code
should have found. Nevertheless, you should have an idea of how to
use gdb at this
point.


16.6.2 ddd


Data Display
Debugger is a frontend for command-line debuggers (or
inferior debugger, in ddd parlance).
We'll use it with gdb, but it
is not limited to gdb. You must have the X
Window System running. Since ddd is a frontend
to gdb and you already know how to use
gdb, there isn't much new to
learn. But ddd does have a few nice tricks.
Although we won't go into it here, one of
ddd's real strengths is
displaying complex data structures such as linked lists.

As with gdb, compile your program with the
-g option. Next, open ddd
with executable as an argument.

[sloanjd@amy DEBUG]$ ddd area

A ddd splash screen will appear briefly and then
three windows will open. The top window is the
ddd Tip of the Day window[2] as shown
in Figure 16-1.

[2] Tip
#31, the tip in this figure, tells you how to get rid of the
ddd Tip of the Day.



Figure 16-1. ddd Tip of the Day #31

Read the tip, if you like, and then close the window.

The large window underneath the tip window is the main window
you'll be working from. Off to the side
you'll see a smaller window with a few
ddd commands. The small command window can be
repositioned so that it doesn't overlap with the
main window if you wish. Figure 16-2 shows both of
these windows.


Figure 16-2. ddd's main window

The window is pretty self-explanatory. The upper pane holds your
source code, while the lower pane is a text interface to
gdb. You can type gdb
commands in the lower pane just as you did on the command line.
gdb commands are also available via the menus at
the top of the window, or you can use the command window to enter the
most common commands. For example, if you want to edit the source,
you can type edit in the command window (just as
you would in gdb) or you can click on the edit
button. Either way, you'll be thrown into an editor.
(Sorry, you can't edit it directly in the upper
pane.)

To add a breakpoint, you can select a line in the upper pane and then
click on the break button (with the stop sign) on the tool bar. As
you step through the code, a large green arrow at the edge of the top
pane points to the current line. If you move the cursor over a
variable, after a few seconds, a pop-up box will display the
variable's current values.

The display can be reconfigured if you wish. For example, if you want
to look at the machine code in addition to (or instead of) the source
listings, you can open a machine language window (and close the
source window). You can also resize windows and change fonts to your
heart's content.


/ 142