3
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
4
<title>8.�DRD: a thread error detector</title>
5
<link rel="stylesheet" href="vg_basic.css" type="text/css">
6
<meta name="generator" content="DocBook XSL Stylesheets V1.69.1">
7
<link rel="start" href="index.html" title="Valgrind Documentation">
8
<link rel="up" href="manual.html" title="Valgrind User Manual">
9
<link rel="prev" href="hg-manual.html" title="7.�Helgrind: a thread error detector">
10
<link rel="next" href="ms-manual.html" title="9.�Massif: a heap profiler">
12
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13
<div><table class="nav" width="100%" cellspacing="3" cellpadding="3" border="0" summary="Navigation header"><tr>
14
<td width="22px" align="center" valign="middle"><a accesskey="p" href="hg-manual.html"><img src="images/prev.png" width="18" height="21" border="0" alt="Prev"></a></td>
15
<td width="25px" align="center" valign="middle"><a accesskey="u" href="manual.html"><img src="images/up.png" width="21" height="18" border="0" alt="Up"></a></td>
16
<td width="31px" align="center" valign="middle"><a accesskey="h" href="index.html"><img src="images/home.png" width="27" height="20" border="0" alt="Up"></a></td>
17
<th align="center" valign="middle">Valgrind User Manual</th>
18
<td width="22px" align="center" valign="middle"><a accesskey="n" href="ms-manual.html"><img src="images/next.png" width="18" height="21" border="0" alt="Next"></a></td>
20
<div class="chapter" lang="en">
21
<div class="titlepage"><div><div><h2 class="title">
22
<a name="drd-manual"></a>8.�DRD: a thread error detector</h2></div></div></div>
24
<p><b>Table of Contents</b></p>
26
<dt><span class="sect1"><a href="drd-manual.html#drd-manual.overview">8.1. Background</a></span></dt>
28
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.mt-progr-models">8.1.1. Multithreaded Programming Paradigms</a></span></dt>
29
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.pthreads-model">8.1.2. POSIX Threads Programming Model</a></span></dt>
30
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.mt-problems">8.1.3. Multithreaded Programming Problems</a></span></dt>
31
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.data-race-detection">8.1.4. Data Race Detection</a></span></dt>
33
<dt><span class="sect1"><a href="drd-manual.html#drd-manual.using-drd">8.2. Using DRD</a></span></dt>
35
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.options">8.2.1. Command Line Options</a></span></dt>
36
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.data-races">8.2.2. Detected Errors: Data Races</a></span></dt>
37
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.lock-contention">8.2.3. Detected Errors: Lock Contention</a></span></dt>
38
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.api-checks">8.2.4. Detected Errors: Misuse of the POSIX threads API</a></span></dt>
39
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.clientreqs">8.2.5. Client Requests</a></span></dt>
40
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.gnome">8.2.6. Debugging GNOME Programs</a></span></dt>
41
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.qt">8.2.7. Debugging Qt Programs</a></span></dt>
42
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.boost.thread">8.2.8. Debugging Boost.Thread Programs</a></span></dt>
43
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.openmp">8.2.9. Debugging OpenMP Programs</a></span></dt>
44
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.cust-mem-alloc">8.2.10. DRD and Custom Memory Allocators</a></span></dt>
45
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.drd-versus-memcheck">8.2.11. DRD Versus Memcheck</a></span></dt>
46
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.resource-requirements">8.2.12. Resource Requirements</a></span></dt>
47
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.effective-use">8.2.13. Hints and Tips for Effective Use of DRD</a></span></dt>
49
<dt><span class="sect1"><a href="drd-manual.html#drd-manual.Pthreads">8.3. Using the POSIX Threads API Effectively</a></span></dt>
51
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.mutex-types">8.3.1. Mutex types</a></span></dt>
52
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.condvar">8.3.2. Condition variables</a></span></dt>
53
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.pctw">8.3.3. pthread_cond_timedwait() and timeouts</a></span></dt>
54
<dt><span class="sect2"><a href="drd-manual.html#drd-manual.naming-threads">8.3.4. Assigning names to threads</a></span></dt>
56
<dt><span class="sect1"><a href="drd-manual.html#drd-manual.limitations">8.4. Limitations</a></span></dt>
57
<dt><span class="sect1"><a href="drd-manual.html#drd-manual.feedback">8.5. Feedback</a></span></dt>
60
<p>To use this tool, you must specify
61
<code class="computeroutput">--tool=drd</code>
62
on the Valgrind command line.</p>
63
<div class="sect1" lang="en">
64
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
65
<a name="drd-manual.overview"></a>8.1.�Background</h2></div></div></div>
67
DRD is a Valgrind tool for detecting errors in multithreaded C and C++
68
shared-memory programs. The tool works for any program that uses the
69
POSIX threading primitives or that uses threading concepts built on
70
top of the POSIX threading primitives.
72
<div class="sect2" lang="en">
73
<div class="titlepage"><div><div><h3 class="title">
74
<a name="drd-manual.mt-progr-models"></a>8.1.1.�Multithreaded Programming Paradigms</h3></div></div></div>
76
For many applications multithreading is a necessity. There are two
77
reasons why the use of threads may be required:
79
<div class="itemizedlist"><ul type="disc">
81
To model concurrent activities. Managing the state of one
82
activity per thread can be a great simplification compared to
83
multiplexing the states of multiple activities in a single
84
thread. This is why most server and embedded software is
88
To let computations run on multiple CPU cores
89
simultaneously. This is why many High Performance Computing
90
(HPC) applications are multithreaded.
96
Multithreaded programs can use one or more of the following
97
paradigms. Which paradigm is appropriate a.o. depends on the
98
application type -- modeling concurrent activities versus HPC.
99
Some examples of multithreaded programming paradigms are:
101
<div class="itemizedlist"><ul type="disc">
103
Locking. Data that is shared between threads may only be
104
accessed after a lock has been obtained on the mutex associated
105
with the shared data item. A.o. the POSIX threads library, the
106
Qt library and the Boost.Thread library support this paradigm
110
Message passing. No data is shared between threads, but threads
111
exchange data by passing messages to each other. Well known
112
implementations of the message passing paradigm are MPI and
116
Automatic parallelization. A compiler converts a sequential
117
program into a multithreaded program. The original program may
118
or may not contain parallelization hints. As an example,
119
<code class="computeroutput">gcc</code> supports the OpenMP
120
standard from gcc version 4.3.0 on. OpenMP is a set of compiler
121
directives which tell a compiler how to parallelize a C, C++ or
125
Software Transactional Memory (STM). Data is shared between
126
threads, and shared data is updated via transactions. After each
127
transaction it is verified whether there were conflicting
128
transactions. If there were conflicts, the transaction is
129
aborted, otherwise it is committed. This is a so-called
130
optimistic approach. There is a prototype of the Intel C
131
Compiler (<code class="computeroutput">icc</code>) available that
132
supports STM. Research is ongoing about the addition of STM
133
support to <code class="computeroutput">gcc</code>.
139
DRD supports any combination of multithreaded programming paradigms as
140
long as the implementation of these paradigms is based on the POSIX
141
threads primitives. DRD however does not support programs that use
142
e.g. Linux' futexes directly. Attempts to analyze such programs with
143
DRD will cause DRD to report many false positives.
146
<div class="sect2" lang="en">
147
<div class="titlepage"><div><div><h3 class="title">
148
<a name="drd-manual.pthreads-model"></a>8.1.2.�POSIX Threads Programming Model</h3></div></div></div>
150
POSIX threads, also known as Pthreads, is the most widely available
151
threading library on Unix systems.
154
The POSIX threads programming model is based on the following abstractions:
156
<div class="itemizedlist"><ul type="disc">
158
A shared address space. All threads running within the same
159
process share the same address space. All data, whether shared or
160
not, is identified by its address.
163
Regular load and store operations, which allow to read values
164
from or to write values to the memory shared by all threads
165
running in the same process.
168
Atomic store and load-modify-store operations. While these are
169
not mentioned in the POSIX threads standard, most
170
microprocessors support atomic memory operations. And some
171
compilers provide direct support for atomic memory operations
172
through built-in functions like
173
e.g. <code class="computeroutput">__sync_fetch_and_add()</code>
174
which is supported by both <code class="computeroutput">gcc</code>
175
and <code class="computeroutput">icc</code>.
178
Threads. Each thread represents a concurrent activity.
181
Synchronization objects and operations on these synchronization
182
objects. The following types of synchronization objects are
183
defined in the POSIX threads standard: mutexes, condition
184
variables, semaphores, reader-writer locks, barriers and
191
Which source code statements generate which memory accesses depends on
192
the <span class="emphasis"><em>memory model</em></span> of the programming language
193
being used. There is not yet a definitive memory model for the C and
194
C++ languagues. For a draft memory model, see also document <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2338.html" target="_top">
198
For more information about POSIX threads, see also the Single UNIX
199
Specification version 3, also known as
200
<a href="http://www.unix.org/version3/ieee_std.html" target="_top">
204
<div class="sect2" lang="en">
205
<div class="titlepage"><div><div><h3 class="title">
206
<a name="drd-manual.mt-problems"></a>8.1.3.�Multithreaded Programming Problems</h3></div></div></div>
208
Depending on which multithreading paradigm is being used in a program,
209
one or more of the following problems can occur:
211
<div class="itemizedlist"><ul type="disc">
213
Data races. One or more threads access the same memory
214
location without sufficient locking.
217
Lock contention. One thread blocks the progress of one or more other
218
threads by holding a lock too long.
221
Improper use of the POSIX threads API. The most popular POSIX
222
threads implementation, NPTL, is optimized for speed. The NPTL
223
will not complain on certain errors, e.g. when a mutex is locked
224
in one thread and unlocked in another thread.
227
Deadlock. A deadlock occurs when two or more threads wait for
228
each other indefinitely.
231
False sharing. If threads that run on different processor cores
232
access different variables located in the same cache line
233
frequently, this will slow down the involved threads a lot due
234
to frequent exchange of cache lines.
240
Although the likelihood of the occurrence of data races can be reduced
241
through a disciplined programming style, a tool for automatic
242
detection of data races is a necessity when developing multithreaded
243
software. DRD can detect these, as well as lock contention and
244
improper use of the POSIX threads API.
247
<div class="sect2" lang="en">
248
<div class="titlepage"><div><div><h3 class="title">
249
<a name="drd-manual.data-race-detection"></a>8.1.4.�Data Race Detection</h3></div></div></div>
251
Synchronization operations impose an order on interthread memory
252
accesses. This order is also known as the happens-before relationship.
255
A multithreaded program is data-race free if all interthread memory
256
accesses are ordered by synchronization operations.
259
A well known way to ensure that a multithreaded program is data-race
260
free is to ensure that a locking discipline is followed. It is e.g.
261
possible to associate a mutex with each shared data item, and to hold
262
a lock on the associated mutex while the shared data is accessed.
265
All programs that follow a locking discipline are data-race free, but
266
not all data-race free programs follow a locking discipline. There
267
exist multithreaded programs where access to shared data is arbitrated
268
via condition variables, semaphores or barriers. As an example, a
269
certain class of HPC applications consists of a sequence of
270
computation steps separated in time by barriers, and where these
271
barriers are the only means of synchronization.
274
There exist two different algorithms for verifying the correctness of
275
multithreaded programs at runtime. The so-called Eraser algorithm
276
verifies whether all shared memory accesses follow a consistent
277
locking strategy. And the happens-before data race detectors verify
278
directly whether all interthread memory accesses are ordered by
279
synchronization operations. While the happens-before data race
280
detection algorithm is more complex to implement, and while it is more
281
sensitive to OS scheduling, it is a general approach that works for
282
all classes of multithreaded programs. Furthermore, the happens-before
283
data race detection algorithm does not report any false positives.
286
DRD is based on the happens-before algorithm.
290
<div class="sect1" lang="en">
291
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
292
<a name="drd-manual.using-drd"></a>8.2.�Using DRD</h2></div></div></div>
293
<div class="sect2" lang="en">
294
<div class="titlepage"><div><div><h3 class="title">
295
<a name="drd-manual.options"></a>8.2.1.�Command Line Options</h3></div></div></div>
296
<p>The following command-line options are available for controlling the
297
behavior of the DRD tool itself:</p>
298
<div class="variablelist">
299
<a name="drd.opts.list"></a><dl>
300
<dt><span class="term">
301
<code class="option">--check-stack-var=<yes|no> [default: no]</code>
304
Controls whether <code class="constant">DRD</code> reports data races
305
for stack variables. This is disabled by default in order to
306
accelerate data race detection. Most programs do not share
307
stack variables over threads.
309
<dt><span class="term">
310
<code class="option">--exclusive-threshold=<n> [default: off]</code>
313
Print an error message if any mutex or writer lock has been
314
held longer than the specified time (in milliseconds). This
315
option enables detecting lock contention.
317
<dt><span class="term">
318
<code class="option">
319
--report-signal-unlocked=<yes|no> [default: yes]
323
Whether to report calls to
324
<code class="function">pthread_cond_signal()</code> and
325
<code class="function">pthread_cond_broadcast()</code> where the mutex
326
associated with the signal through
327
<code class="function">pthread_cond_wait()</code> or
328
<code class="function">pthread_cond_timed_wait()</code>is not locked at
329
the time the signal is sent. Sending a signal without holding
330
a lock on the associated mutex is a common programming error
331
which can cause subtle race conditions and unpredictable
332
behavior. There exist some uncommon synchronization patterns
333
however where it is safe to send a signal without holding a
334
lock on the associated mutex.
336
<dt><span class="term">
337
<code class="option">--segment-merging=<yes|no> [default: yes]</code>
340
Controls segment merging. Segment merging is an algorithm to
341
limit memory usage of the data race detection
342
algorithm. Disabling segment merging may improve the accuracy
343
of the so-called 'other segments' displayed in race reports
344
but can also trigger an out of memory error.
346
<dt><span class="term">
347
<code class="option">--shared-threshold=<n> [default: off]</code>
350
Print an error message if a reader lock has been held longer
351
than the specified time (in milliseconds). This option enables
352
detection of lock contention.
354
<dt><span class="term">
355
<code class="option">--show-confl-seg=<yes|no> [default: yes]</code>
358
Show conflicting segments in race reports. Since this
359
information can help to find the cause of a data race, this
360
option is enabled by default. Disabling this option makes the
361
output of DRD more compact.
363
<dt><span class="term">
364
<code class="option">--show-stack-usage=<yes|no> [default: no]</code>
367
Print stack usage at thread exit time. When a program creates
368
a large number of threads it becomes important to limit the
369
amount of virtual memory allocated for thread stacks. This
370
option makes it possible to observe how much stack memory has
371
been used by each thread of the the client program. Note: the
372
DRD tool allocates some temporary data on the client thread
373
stack itself. The space necessary for this temporary data must
374
be allocated by the client program, but is not included in the
375
reported stack usage.
377
<dt><span class="term">
378
<code class="option">--var-info=<yes|no> [default: no]</code>
381
Display the names of global, static and stack variables when a
382
data race is reported. While this information can be very
383
helpful, it is not loaded into memory by default. This is
384
because for big programs reading in all debug information at
385
once may cause an out of memory error.
390
The following options are available for monitoring the behavior of the
393
<div class="variablelist">
394
<a name="drd.debugopts.list"></a><dl>
395
<dt><span class="term">
396
<code class="option">--trace-addr=<address> [default: none]</code>
399
Trace all load and store activity for the specified
400
address. This option may be specified more than once.
402
<dt><span class="term">
403
<code class="option">--trace-barrier=<yes|no> [default: no]</code>
406
Trace all barrier activity.
408
<dt><span class="term">
409
<code class="option">--trace-cond=<yes|no> [default: no]</code>
412
Trace all condition variable activity.
414
<dt><span class="term">
415
<code class="option">--trace-fork-join=<yes|no> [default: no]</code>
418
Trace all thread creation and all thread termination events.
420
<dt><span class="term">
421
<code class="option">--trace-mutex=<yes|no> [default: no]</code>
424
Trace all mutex activity.
426
<dt><span class="term">
427
<code class="option">--trace-rwlock=<yes|no> [default: no]</code>
430
Trace all reader-writer lock activity.
432
<dt><span class="term">
433
<code class="option">--trace-semaphore=<yes|no> [default: no]</code>
436
Trace all semaphore activity.
441
<div class="sect2" lang="en">
442
<div class="titlepage"><div><div><h3 class="title">
443
<a name="drd-manual.data-races"></a>8.2.2.�Detected Errors: Data Races</h3></div></div></div>
445
DRD prints a message every time it detects a data race. Please keep
446
the following in mind when interpreting DRD's output:
448
<div class="itemizedlist"><ul type="disc">
450
Every thread is assigned two <span class="emphasis"><em>thread ID's</em></span>:
451
one thread ID is assigned by the Valgrind core and one thread ID
452
is assigned by DRD. Both thread ID's start at one. Valgrind
453
thread ID's are reused when one thread finishes and another
454
thread is created. DRD does not reuse thread ID's. Thread ID's
455
are displayed e.g. as follows: 2/3, where the first number is
456
Valgrind's thread ID and the second number is the thread ID
460
The term <span class="emphasis"><em>segment</em></span> refers to a consecutive
461
sequence of load, store and synchronization operations, all
462
issued by the same thread. A segment always starts and ends at a
463
synchronization operation. Data race analysis is performed
464
between segments instead of between individual load and store
465
operations because of performance reasons.
468
There are always at least two memory accesses involved in a data
469
race. Memory accesses involved in a data race are called
470
<span class="emphasis"><em>conflicting memory accesses</em></span>. DRD prints a
471
report for each memory access that conflicts with a past memory
478
Below you can find an example of a message printed by DRD when it
481
<pre class="programlisting">
482
$ valgrind --tool=drd --var-info=yes drd/tests/rwlock_race
485
==9466== Conflicting load by thread 3/3 at 0x006020b8 size 4
486
==9466== at 0x400B6C: thread_func (rwlock_race.c:29)
487
==9466== by 0x4C291DF: vg_thread_wrapper (drd_pthread_intercepts.c:186)
488
==9466== by 0x4E3403F: start_thread (in /lib64/libpthread-2.8.so)
489
==9466== by 0x53250CC: clone (in /lib64/libc-2.8.so)
490
==9466== Location 0x6020b8 is 0 bytes inside local var "s_racy"
491
==9466== declared at rwlock_race.c:18, in frame #0 of thread 3
492
==9466== Other segment start (thread 2/2)
493
==9466== at 0x4C2847D: pthread_rwlock_rdlock* (drd_pthread_intercepts.c:813)
494
==9466== by 0x400B6B: thread_func (rwlock_race.c:28)
495
==9466== by 0x4C291DF: vg_thread_wrapper (drd_pthread_intercepts.c:186)
496
==9466== by 0x4E3403F: start_thread (in /lib64/libpthread-2.8.so)
497
==9466== by 0x53250CC: clone (in /lib64/libc-2.8.so)
498
==9466== Other segment end (thread 2/2)
499
==9466== at 0x4C28B54: pthread_rwlock_unlock* (drd_pthread_intercepts.c:912)
500
==9466== by 0x400B84: thread_func (rwlock_race.c:30)
501
==9466== by 0x4C291DF: vg_thread_wrapper (drd_pthread_intercepts.c:186)
502
==9466== by 0x4E3403F: start_thread (in /lib64/libpthread-2.8.so)
503
==9466== by 0x53250CC: clone (in /lib64/libc-2.8.so)
507
The above report has the following meaning:
509
<div class="itemizedlist"><ul type="disc">
511
The number in the column on the left is the process ID of the
512
process being analyzed by DRD.
515
The first line ("Thread 3") tells you Valgrind's thread ID for
516
the thread in which context the data race was detected.
519
The next line tells which kind of operation was performed (load
520
or store) and by which thread. Both Valgrind's and DRD's thread
521
ID's are displayed. On the same line the start address and the
522
number of bytes involved in the conflicting access are also
526
Next, the call stack of the conflicting access is displayed. If
527
your program has been compiled with debug information (-g), this
528
call stack will include file names and line numbers. The two
529
bottommost frames in this call stack (<code class="function">clone</code>
530
and <code class="function">start_thread</code>) show how the NPTL starts
531
a thread. The third frame
532
(<code class="function">vg_thread_wrapper</code>) is added by DRD. The
533
fourth frame (<code class="function">thread_func</code>) is the first
534
interesting line because it shows the thread entry point, that
535
is the function that has been passed as the third argument to
536
<code class="function">pthread_create()</code>.
539
Next, the allocation context for the conflicting address is
540
displayed. For dynamically allocated data the allocation call
541
stack is shown. For static variables and stack variables the
542
allocation context is only shown when the option
543
<code class="computeroutput">--var-info=yes</code> has been
544
specified. Otherwise DRD will print <code class="computeroutput">Allocation
545
context: unknown</code>.
549
A conflicting access involves at least two memory accesses. For
550
one of these accesses an exact call stack is displayed, and for
551
the other accesses an approximate call stack is displayed,
552
namely the start and the end of the segments of the other
553
accesses. This information can be interpreted as follows:
555
<div class="orderedlist"><ol type="1">
557
Start at the bottom of both call stacks, and count the
558
number stack frames with identical function name, file
559
name and line number. In the above example the three
560
bottommost frames are identical
561
(<code class="function">clone</code>,
562
<code class="function">start_thread</code> and
563
<code class="function">vg_thread_wrapper</code>).
566
The next higher stack frame in both call stacks now tells
567
you between in which source code region the other memory
568
access happened. The above output tells that the other
569
memory access involved in the data race happened between
570
source code lines 28 and 30 in file
571
<code class="computeroutput">rwlock_race.c</code>.
581
<div class="sect2" lang="en">
582
<div class="titlepage"><div><div><h3 class="title">
583
<a name="drd-manual.lock-contention"></a>8.2.3.�Detected Errors: Lock Contention</h3></div></div></div>
585
Threads must be able to make progress without being blocked for too
586
long by other threads. Sometimes a thread has to wait until a mutex or
587
reader-writer lock is unlocked by another thread. This is called
588
<span class="emphasis"><em>lock contention</em></span>.
591
Lock contention causes delays. Such delays should be as short as
592
possible. The two command line options
593
<code class="literal">--exclusive-threshold=<n></code> and
594
<code class="literal">--shared-threshold=<n></code> make it possible to
595
detect excessive lock contention by making DRD report any lock that
596
has been held longer than the specified threshold. An example:
598
<pre class="programlisting">
599
$ valgrind --tool=drd --exclusive-threshold=10 drd/tests/hold_lock -i 500
601
==10668== Acquired at:
602
==10668== at 0x4C267C8: pthread_mutex_lock (drd_pthread_intercepts.c:395)
603
==10668== by 0x400D92: main (hold_lock.c:51)
604
==10668== Lock on mutex 0x7fefffd50 was held during 503 ms (threshold: 10 ms).
605
==10668== at 0x4C26ADA: pthread_mutex_unlock (drd_pthread_intercepts.c:441)
606
==10668== by 0x400DB5: main (hold_lock.c:55)
610
The <code class="literal">hold_lock</code> test program holds a lock as long as
611
specified by the <code class="literal">-i</code> (interval) argument. The DRD
612
output reports that the lock acquired at line 51 in source file
613
<code class="literal">hold_lock.c</code> and released at line 55 was held during
614
503 ms, while a threshold of 10 ms was specified to DRD.
617
<div class="sect2" lang="en">
618
<div class="titlepage"><div><div><h3 class="title">
619
<a name="drd-manual.api-checks"></a>8.2.4.�Detected Errors: Misuse of the POSIX threads API</h3></div></div></div>
621
DRD is able to detect and report the following misuses of the POSIX
624
<div class="itemizedlist"><ul type="disc">
626
Passing the address of one type of synchronization object
627
(e.g. a mutex) to a POSIX API call that expects a pointer to
628
another type of synchronization object (e.g. a condition
632
Attempts to unlock a mutex that has not been locked.
635
Attempts to unlock a mutex that was locked by another thread.
638
Attempts to lock a mutex of type
639
<code class="literal">PTHREAD_MUTEX_NORMAL</code> or a spinlock
643
Destruction or deallocation of a locked mutex.
646
Sending a signal to a condition variable while no lock is held
647
on the mutex associated with the signal.
650
Calling <code class="function">pthread_cond_wait()</code> on a mutex
651
that is not locked, that is locked by another thread or that
652
has been locked recursively.
655
Associating two different mutexes with a condition variable
656
through <code class="function">pthread_cond_wait()</code>.
659
Destruction or deallocation of a condition variable that is
663
Destruction or deallocation of a locked reader-writer lock.
666
Attempts to unlock a reader-writer lock that was not locked by
670
Attempts to recursively lock a reader-writer lock exclusively.
673
Reinitialization of a mutex, condition variable, reader-writer
674
lock, semaphore or barrier.
677
Destruction or deallocation of a semaphore or barrier that is
681
Exiting a thread without first unlocking the spinlocks,
682
mutexes or reader-writer locks that were locked by that
689
<div class="sect2" lang="en">
690
<div class="titlepage"><div><div><h3 class="title">
691
<a name="drd-manual.clientreqs"></a>8.2.5.�Client Requests</h3></div></div></div>
693
Just as for other Valgrind tools it is possible to let a client
694
program interact with the DRD tool.
697
The interface between client programs and the DRD tool is defined in
698
the header file <code class="literal"><valgrind/drd.h></code>. The
699
available client requests are:
701
<div class="itemizedlist"><ul type="disc">
703
<code class="varname">VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID</code>.
704
Query the thread ID that was assigned by the Valgrind core to
705
the thread executing this client request. Valgrind's thread ID's
706
start at one and are recycled in case a thread stops.
709
<code class="varname">VG_USERREQ__DRD_GET_DRD_THREAD_ID</code>.
710
Query the thread ID that was assigned by DRD to
711
the thread executing this client request. DRD's thread ID's
712
start at one and are never recycled.
715
<code class="varname">VG_USERREQ__DRD_START_SUPPRESSION</code>. Some
716
applications contain intentional races. There exist
717
e.g. applications where the same value is assigned to a shared
718
variable from two different threads. It may be more convenient
719
to suppress such races than to solve these. This client request
720
allows to suppress such races. See also the macro
721
<code class="literal">DRD_IGNORE_VAR(x)</code> defined in
722
<code class="literal"><valgrind/drd.h></code>.
725
<code class="varname">VG_USERREQ__DRD_FINISH_SUPPRESSION</code>. Tell DRD
726
to no longer ignore data races in the address range that was
728
<code class="varname">VG_USERREQ__DRD_START_SUPPRESSION</code>.
731
<code class="varname">VG_USERREQ__DRD_START_TRACE_ADDR</code>. Trace all
732
load and store activity on the specified address range. When DRD
733
reports a data race on a specified variable, and it's not
734
immediately clear which source code statements triggered the
735
conflicting accesses, it can be helpful to trace all activity on
736
the offending memory location. See also the macro
737
<code class="literal">DRD_TRACE_VAR(x)</code> defined in
738
<code class="literal"><valgrind/drd.h></code>.
741
<code class="varname">VG_USERREQ__DRD_STOP_TRACE_ADDR</code>. Do no longer
742
trace load and store activity for the specified address range.
748
Note: if you compiled Valgrind yourself, the header file
749
<code class="literal"><valgrind/drd.h></code> will have been installed in
750
the directory <code class="literal">/usr/include</code> by the command
751
<code class="literal">make install</code>. If you obtained Valgrind by
752
installing it as a package however, you will probably have to install
753
another package with a name like <code class="literal">valgrind-devel</code>
754
before Valgrind's header files are present.
757
<div class="sect2" lang="en">
758
<div class="titlepage"><div><div><h3 class="title">
759
<a name="drd-manual.gnome"></a>8.2.6.�Debugging GNOME Programs</h3></div></div></div>
761
GNOME applications use the threading primitives provided by the
762
<code class="computeroutput">glib</code> and
763
<code class="computeroutput">gthread</code> libraries. These libraries
764
are built on top of POSIX threads, and hence are directly supported by
765
DRD. Please keep in mind that you have to call
766
<code class="function">g_thread_init()</code> before creating any threads, or
767
DRD will report several data races on glib functions. See also the
768
<a href="http://library.gnome.org/devel/glib/stable/glib-Threads.html" target="_top">GLib
769
Reference Manual</a> for more information about
770
<code class="function">g_thread_init()</code>.
773
One of the many facilities provided by the <code class="literal">glib</code>
774
library is a block allocator, called <code class="literal">g_slice</code>. You
775
have to disable this block allocator when using DRD by adding the
776
following to the shell environment variables:
777
<code class="literal">G_SLICE=always-malloc</code>. See also the <a href="http://library.gnome.org/devel/glib/stable/glib-Memory-Slices.html" target="_top">GLib
778
Reference Manual</a> for more information.
781
<div class="sect2" lang="en">
782
<div class="titlepage"><div><div><h3 class="title">
783
<a name="drd-manual.qt"></a>8.2.7.�Debugging Qt Programs</h3></div></div></div>
785
The Qt library is the GUI library used by the KDE project. Currently
786
there are two versions of the Qt library in use: Qt3 by KDE 3 and Qt4
787
by KDE 4. If possible, use Qt4 instead of Qt3. Qt3 is no longer
788
supported, and there are known problems with multithreading support in
789
Qt3. As an example, using QString objects in more than one thread will
790
trigger race reports (this has been confirmed by Trolltech -- see also
791
Trolltech task <a href="http://trolltech.com/developer/task-tracker/index_html" target="_top">#206152</a>).
794
Qt4 applications are supported by DRD, but only if the
795
<code class="literal">libqt4-debuginfo</code> package has been installed. Some
796
of the synchronization and threading primitives in Qt4 bypass the
797
POSIX threads library, and DRD can only intercept these if symbol
798
information for the Qt4 library is available. DRD won't tell you if it
799
has not been able to load the Qt4 debug information, but a huge number
800
of data races will be reported on data protected via
801
<code class="literal">QMutex</code> objects.
804
<div class="sect2" lang="en">
805
<div class="titlepage"><div><div><h3 class="title">
806
<a name="drd-manual.boost.thread"></a>8.2.8.�Debugging Boost.Thread Programs</h3></div></div></div>
808
The Boost.Thread library is the threading library included with the
809
cross-platform Boost Libraries. This threading library is an early
810
implementation of the upcoming C++0x threading library.
813
Applications that use the Boost.Thread library should run fine under DRD.
816
More information about Boost.Thread can be found here:
818
<div class="itemizedlist"><ul type="disc">
820
Anthony Williams, <a href="http://www.boost.org/doc/libs/1_37_0/doc/html/thread.html" target="_top">Boost.Thread</a>
821
Library Documentation, Boost website, 2007.
824
Anthony Williams, <a href="http://www.ddj.com/cpp/211600441" target="_top">What's New in Boost
825
Threads?</a>, Recent changes to the Boost Thread library,
826
Dr. Dobbs Magazine, October 2008.
832
<div class="sect2" lang="en">
833
<div class="titlepage"><div><div><h3 class="title">
834
<a name="drd-manual.openmp"></a>8.2.9.�Debugging OpenMP Programs</h3></div></div></div>
836
OpenMP stands for <span class="emphasis"><em>Open Multi-Processing</em></span>. The
837
OpenMP standard consists of a set of compiler directives for C, C++
838
and Fortran programs that allows a compiler to transform a sequential
839
program into a parallel program. OpenMP is well suited for HPC
840
applications and allows to work at a higher level compared to direct
841
use of the POSIX threads API. While OpenMP ensures that the POSIX API
842
is used correctly, OpenMP programs can still contain data races. So it
843
makes sense to verify OpenMP programs with a thread checking tool.
846
DRD supports OpenMP shared-memory programs generated by gcc. The gcc
847
compiler supports OpenMP since version 4.2.0. Gcc's runtime support
848
for OpenMP programs is provided by a library called
849
<code class="literal">libgomp</code>. The synchronization primites implemented
850
in this library use Linux' futex system call directly, unless the
851
library has been configured with the
852
<code class="literal">--disable-linux-futex</code> flag. DRD only supports
853
libgomp libraries that have been configured with this flag and in
854
which symbol information is present. For most Linux distributions this
855
means that you will have to recompile gcc. See also the script
856
<code class="literal">drd/scripts/download-and-build-gcc</code> in the
857
Valgrind source tree for an example of how to compile gcc. You will
858
also have to make sure that the newly compiled
859
<code class="literal">libgomp.so</code> library is loaded when OpenMP programs
860
are started. This is possible by adding a line similar to the
861
following to your shell startup script:
863
<pre class="programlisting">
864
export LD_LIBRARY_PATH=~/gcc-4.3.2/lib64:~/gcc-4.3.2/lib:
867
As an example, the test OpenMP test program
868
<code class="literal">drd/tests/omp_matinv</code> triggers a data race
869
when the option -r has been specified on the command line. The data
870
race is triggered by the following code:
872
<pre class="programlisting">
873
#pragma omp parallel for private(j)
874
for (j = 0; j < rows; j++)
878
const elem_t factor = a[j * cols + i];
879
for (k = 0; k < cols; k++)
881
a[j * cols + k] -= a[i * cols + k] * factor;
887
The above code is racy because the variable <code class="literal">k</code> has
888
not been declared private. DRD will print the following error message
891
<pre class="programlisting">
892
$ valgrind --check-stack-var=yes --var-info=yes --tool=drd drd/tests/omp_matinv 3 -t 2 -r
894
Conflicting store by thread 1/1 at 0x7fefffbc4 size 4
895
at 0x4014A0: gj.omp_fn.0 (omp_matinv.c:203)
896
by 0x401211: gj (omp_matinv.c:159)
897
by 0x40166A: invert_matrix (omp_matinv.c:238)
898
by 0x4019B4: main (omp_matinv.c:316)
899
Allocation context: unknown.
903
In the above output the function name <code class="function">gj.omp_fn.0</code>
904
has been generated by gcc from the function name
905
<code class="function">gj</code>. Unfortunately the variable name
906
<code class="literal">k</code> is not shown as the allocation context -- it is
907
not clear to me whether this is caused by Valgrind or whether this is
908
caused by gcc. The most usable information in the above output is the
909
source file name and the line number where the data race has been detected
910
(<code class="literal">omp_matinv.c:203</code>).
913
Note: DRD reports errors on the <code class="literal">libgomp</code> library
914
included with gcc 4.2.0 up to and including 4.3.2. This might indicate
915
a race condition in the POSIX version of <code class="literal">libgomp</code>.
918
For more information about OpenMP, see also
919
<a href="http://openmp.org/" target="_top">openmp.org</a>.
922
<div class="sect2" lang="en">
923
<div class="titlepage"><div><div><h3 class="title">
924
<a name="drd-manual.cust-mem-alloc"></a>8.2.10.�DRD and Custom Memory Allocators</h3></div></div></div>
926
DRD tracks all memory allocation events that happen via either the
927
standard memory allocation and deallocation functions
928
(<code class="function">malloc</code>, <code class="function">free</code>,
929
<code class="function">new</code> and <code class="function">delete</code>) or via entry
930
and exit of stack frames. DRD uses memory allocation and deallocation
931
information for two purposes:
933
<div class="itemizedlist"><ul type="disc">
935
To know where the scope ends of POSIX objects that have not been
936
destroyed explicitly. It is e.g. not required by the POSIX
937
threads standard to call
938
<code class="function">pthread_mutex_destroy()</code> before freeing the
939
memory in which a mutex object resides.
942
To know where the scope of variables ends. If e.g. heap memory
943
has been used by one thread, that thread frees that memory, and
944
another thread allocates and starts using that memory, no data
945
races must be reported for that memory.
951
It is essential for correct operation of DRD that the tool knows about
952
memory allocation and deallocation events. DRD does not yet support
953
custom memory allocators, so you will have to make sure that any
954
program which runs under DRD uses the standard memory allocation
955
functions. As an example, the GNU libstdc++ library can be configured
956
to use standard memory allocation functions instead of memory pools by
957
setting the environment variable
958
<code class="literal">GLIBCXX_FORCE_NEW</code>. For more information, see also
959
the <a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt04ch11.html" target="_top">libstdc++
963
<div class="sect2" lang="en">
964
<div class="titlepage"><div><div><h3 class="title">
965
<a name="drd-manual.drd-versus-memcheck"></a>8.2.11.�DRD Versus Memcheck</h3></div></div></div>
967
It is essential for correct operation of DRD that there are no memory
968
errors such as dangling pointers in the client program. Which means that
969
it is a good idea to make sure that your program is memcheck-clean
970
before you analyze it with DRD. It is possible however that some of
971
the memcheck reports are caused by data races. In this case it makes
972
sense to run DRD before memcheck.
975
So which tool should be run first ? In case both DRD and memcheck
976
complain about a program, a possible approach is to run both tools
977
alternatingly and to fix as many errors as possible after each run of
978
each tool until none of the two tools prints any more error messages.
981
<div class="sect2" lang="en">
982
<div class="titlepage"><div><div><h3 class="title">
983
<a name="drd-manual.resource-requirements"></a>8.2.12.�Resource Requirements</h3></div></div></div>
985
The requirements of DRD with regard to heap and stack memory and the
986
effect on the execution time of client programs are as follows:
988
<div class="itemizedlist"><ul type="disc">
990
When running a program under DRD with default DRD options,
991
between 1.1 and 3.6 times more memory will be needed compared to
992
a native run of the client program. More memory will be needed
993
if loading debug information has been enabled
994
(<code class="literal">--var-info=yes</code>).
997
DRD allocates some of its temporary data structures on the stack
998
of the client program threads. This amount of data is limited to
999
1 - 2 KB. Make sure that thread stacks are sufficiently large.
1002
Most applications will run between 20 and 50 times slower under
1003
DRD than a native single-threaded run. Applications such as
1004
Firefox which perform very much mutex lock / unlock operations
1005
however will run too slow to be usable under DRD. This issue
1006
will be addressed in a future DRD version.
1012
<div class="sect2" lang="en">
1013
<div class="titlepage"><div><div><h3 class="title">
1014
<a name="drd-manual.effective-use"></a>8.2.13.�Hints and Tips for Effective Use of DRD</h3></div></div></div>
1016
The following information may be helpful when using DRD:
1018
<div class="itemizedlist"><ul type="disc">
1020
Make sure that debug information is present in the executable
1021
being analysed, such that DRD can print function name and line
1022
number information in stack traces. Most compilers can be told
1023
to include debug information via compiler option
1024
<code class="option">-g</code>.
1027
Compile with flag <code class="option">-O1</code> instead of
1028
<code class="option">-O0</code>. This will reduce the amount of generated
1029
code, may reduce the amount of debug info and will speed up
1030
DRD's processing of the client program. For more information,
1031
see also <a href="manual-core.html#manual-core.started">Getting started</a>.
1034
If DRD reports any errors on libraries that are part of your
1035
Linux distribution like e.g. <code class="literal">libc.so</code> or
1036
<code class="literal">libstdc++.so</code>, installing the debug packages
1037
for these libraries will make the output of DRD a lot more
1042
When using C++, do not send output from more than one thread to
1043
<code class="literal">std::cout</code>. Doing so would not only
1044
generate multiple data race reports, it could also result in
1045
output from several threads getting mixed up. Either use
1046
<code class="function">printf()</code> or do the following:
1048
<div class="orderedlist"><ol type="1">
1049
<li><p>Derive a class from <code class="literal">std::ostreambuf</code>
1050
and let that class send output line by line to
1051
<code class="literal">stdout</code>. This will avoid that individual
1052
lines of text produced by different threads get mixed
1054
<li><p>Create one instance of <code class="literal">std::ostream</code>
1055
for each thread. This makes stream formatting settings
1056
thread-local. Pass a per-thread instance of the class
1057
derived from <code class="literal">std::ostreambuf</code> to the
1058
constructor of each instance. </p></li>
1059
<li><p>Let each thread send its output to its own instance of
1060
<code class="literal">std::ostream</code> instead of
1061
<code class="literal">std::cout</code>.</p></li>
1071
<div class="sect1" lang="en">
1072
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
1073
<a name="drd-manual.Pthreads"></a>8.3.�Using the POSIX Threads API Effectively</h2></div></div></div>
1074
<div class="sect2" lang="en">
1075
<div class="titlepage"><div><div><h3 class="title">
1076
<a name="drd-manual.mutex-types"></a>8.3.1.�Mutex types</h3></div></div></div>
1078
The Single UNIX Specification version two defines the following four
1079
mutex types (see also the documentation of <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_mutexattr_settype.html" target="_top"><code class="function">pthread_mutexattr_settype()</code></a>):
1081
<div class="itemizedlist"><ul type="disc">
1083
<span class="emphasis"><em>normal</em></span>, which means that no error checking
1084
is performed, and that the mutex is non-recursive.
1087
<span class="emphasis"><em>error checking</em></span>, which means that the mutex
1088
is non-recursive and that error checking is performed.
1091
<span class="emphasis"><em>recursive</em></span>, which means that a mutex may be
1095
<span class="emphasis"><em>default</em></span>, which means that error checking
1096
behavior is undefined, and that the behavior for recursive
1097
locking is also undefined. Or: portable code must neither
1098
trigger error conditions through the Pthreads API nor attempt to
1099
lock a mutex of default type recursively.
1105
In complex applications it is not always clear from beforehand which
1106
mutex will be locked recursively and which mutex will not be locked
1107
recursively. Attempts lock a non-recursive mutex recursively will
1108
result in race conditions that are very hard to find without a thread
1109
checking tool. So either use the error checking mutex type and
1110
consistently check the return value of Pthread API mutex calls, or use
1111
the recursive mutex type.
1114
<div class="sect2" lang="en">
1115
<div class="titlepage"><div><div><h3 class="title">
1116
<a name="drd-manual.condvar"></a>8.3.2.�Condition variables</h3></div></div></div>
1118
A condition variable allows one thread to wake up one or more other
1119
threads. Condition variables are often used to notify one or more
1120
threads about state changes of shared data. Unfortunately it is very
1121
easy to introduce race conditions by using condition variables as the
1122
only means of state information propagation. A better approach is to
1123
let threads poll for changes of a state variable that is protected by
1124
a mutex, and to use condition variables only as a thread wakeup
1125
mechanism. See also the source file
1126
<code class="computeroutput">drd/tests/monitor_example.cpp</code> for an
1127
example of how to implement this concept in C++. The monitor concept
1128
used in this example is a well known and very useful concept -- see
1129
also Wikipedia for more information about the <a href="http://en.wikipedia.org/wiki/Monitor_(synchronization)" target="_top">monitor</a>
1133
<div class="sect2" lang="en">
1134
<div class="titlepage"><div><div><h3 class="title">
1135
<a name="drd-manual.pctw"></a>8.3.3.�pthread_cond_timedwait() and timeouts</h3></div></div></div>
1137
Historically the function
1138
<code class="function">pthread_cond_timedwait()</code> only allowed the
1139
specification of an absolute timeout, that is a timeout independent of
1140
the time when this function was called. However, almost every call to
1141
this function expresses a relative timeout. This typically happens by
1143
<code class="computeroutput">clock_gettime(CLOCK_REALTIME)</code> and a
1144
relative timeout as the third argument. This approach is incorrect
1145
since forward or backward clock adjustments by e.g. ntpd will affect
1146
the timeout. A more reliable approach is as follows:
1148
<div class="itemizedlist"><ul type="disc">
1150
When initializing a condition variable through
1151
pthread_cond_init(), specify that the timeout of
1152
pthread_cond_timedwait() will use the clock
1153
<code class="literal">CLOCK_MONOTONIC</code> instead of
1154
<code class="literal">CLOCK_REALTIME</code>. You can do this via
1155
<code class="computeroutput">pthread_condattr_setclock(...,
1156
CLOCK_MONOTONIC)</code>.
1159
When calling <code class="function">pthread_cond_timedwait()</code>, pass
1161
<code class="computeroutput">clock_gettime(CLOCK_MONOTONIC)</code>
1162
and a relative timeout as the third argument.
1167
<code class="computeroutput">drd/tests/monitor_example.cpp</code> for an
1171
<div class="sect2" lang="en">
1172
<div class="titlepage"><div><div><h3 class="title">
1173
<a name="drd-manual.naming-threads"></a>8.3.4.�Assigning names to threads</h3></div></div></div>
1175
Many applications log information about changes in internal or
1176
external state to a file. When analyzing log files of a multithreaded
1177
application it can be very convenient to know which thread logged
1178
which information. One possible approach is to identify threads in
1179
logging output by including the result of
1180
<code class="function">pthread_self()</code> in every log line. However, this approach
1181
has two disadvantages: there is no direct relationship between these
1182
values and the source code and these values can be different in each
1183
run. A better approach is to assign a brief name to each thread and to
1184
include the assigned thread name in each log line. One possible
1185
approach for managing thread names is as follows:
1187
<div class="itemizedlist"><ul type="disc">
1189
Allocate a key for the pointer to the thread name through
1190
<code class="function">pthread_key_create()</code>.
1193
Just after thread creation, set the thread name through
1194
<code class="function">pthread_setspecific()</code>.
1197
In the code that generates the logging information, query the thread
1198
name by calling <code class="function">pthread_getspecific()</code>.
1206
<div class="sect1" lang="en">
1207
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
1208
<a name="drd-manual.limitations"></a>8.4.�Limitations</h2></div></div></div>
1209
<p>DRD currently has the following limitations:</p>
1210
<div class="itemizedlist"><ul type="disc">
1212
DRD has only been tested on the Linux operating system, and not
1213
on any of the other operating systems supported by
1217
Of the two POSIX threads implementations for Linux, only the
1218
NPTL (Native POSIX Thread Library) is supported. The older
1219
LinuxThreads library is not supported.
1222
DRD, just like memcheck, will refuse to start on Linux
1223
distributions where all symbol information has been removed from
1224
ld.so. This is a.o. the case for the PPC editions of openSUSE
1225
and Gentoo. You will have to install the glibc debuginfo package
1226
on these platforms before you can use DRD. See also openSUSE bug
1227
<a href="http://bugzilla.novell.com/show_bug.cgi?id=396197" target="_top">
1228
396197</a> and Gentoo bug <a href="http://bugs.gentoo.org/214065" target="_top">214065</a>.
1231
When DRD prints a report about a data race detected on a stack
1232
variable in a parallel section of an OpenMP program, the report
1233
will contain no information about the context of the data race
1234
location (<code class="computeroutput">Allocation context:
1235
unknown</code>). It's not yet clear whether this
1236
behavior is caused by Valgrind or by gcc.
1239
When address tracing is enabled, no information on atomic stores
1240
will be displayed. This functionality is easy to add
1241
however. Please contact the Valgrind authors if you would like
1242
to see this functionality enabled.
1245
If you compile the DRD source code yourself, you need gcc 3.0 or
1246
later. Gcc 2.95 is not supported.
1250
<div class="sect1" lang="en">
1251
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
1252
<a name="drd-manual.feedback"></a>8.5.�Feedback</h2></div></div></div>
1254
If you have any comments, suggestions, feedback or bug reports about
1255
DRD, feel free to either post a message on the Valgrind users mailing
1256
list or to file a bug report. See also <a href="http://www.valgrind.org/" target="_top">http://www.valgrind.org/</a> for more information.
1261
<br><table class="nav" width="100%" cellspacing="3" cellpadding="2" border="0" summary="Navigation footer">
1263
<td rowspan="2" width="40%" align="left">
1264
<a accesskey="p" href="hg-manual.html"><<�7.�Helgrind: a thread error detector</a>�</td>
1265
<td width="20%" align="center"><a accesskey="u" href="manual.html">Up</a></td>
1266
<td rowspan="2" width="40%" align="right">�<a accesskey="n" href="ms-manual.html">9.�Massif: a heap profiler�>></a>
1269
<tr><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td></tr>