Development/Valgrind
Description | Content |
---|---|
module load | devel/valgrind |
Availability | bwUniCluster | BwForCluster_Chemistry |
License | GPL |
Citing | n/a |
Links | Valgrind Homepage |
Graphical Interface | No |
Introduction
Valgrind is an instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. You can also use Valgrind to build new tools.
About Valgrind
Commands
Valgrind ships with various tools, some of them are described in the following table.
Tool | Description |
---|---|
memcheck | Detects heap array overruns, memory leaks and incorrect freeing of heap memory. |
exp-sgcheck | Detects stack and global array overruns. |
callgrind | Profiler. Helps finding bottlenecks. |
helgrind | Detects race conditions and deadlocks. |
drd | Detects race conditions. Does not detect deadlocks but needs less memory than helgrind. |
Versions and Availability
A list of versions currently available on all bwHPC-C5-Clusters can be obtained from the
Cluster Information System CIS
{{#widget:Iframe |url=https://cis-hpc.uni-konstanz.de/prod.cis/bwUniCluster/devel/valgrind |width=99% |height=120 }} On the command line interface of any bwHPC cluster you'll get a list of available versions by using the command 'module avail devel/valgrind'.
$ module avail devel/valgrind # bwForCluster (Justus) ------------------------ /opt/bwhpc/common/modulefiles ------------------------- devel/valgrind/3.10.1
Attention!
The default Linux Valgrind debugger may be a different version (if installed).
Check the default version by: 'valgrind --version' without loaded valgrind-module (if available).
$ valgrind --version # bwUniCluster valgrind-3.8.1
Documentation
Online
Local
$ man valgrind
Usage
To simulate your program and gather information about it using a specific tool, valgrind can be called like this
$ valgrind --tool=<tool> --log-file=<logfile> ./example
For example to check for race conditions the command would look like this:
$ valgrind --tool=drd --log-file=log.mem ./example
Beware that the simulation via valgrind can take much longer and can consume much more memory compared to a normal execution.
Furthermore the tools can give false positives, i.e. they report errors even though the are none.
Example for helgrind and drd
This small program demonstrates how to detect data races in parallel programs. Both helgrind and drd support POSIX Threads (Pthreads) but not OpenMP so prepare to get many false positives when using these tools with OpenMP.
/* pthreads.c */
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#define NUM_THREADS 2
int v = 0;
void* f(void* x)
{
int j = 0;
int k = *(int*)x;
for(j = 0; j < 100; j++)
v += sin(j) + 1 + k;
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int idx[NUM_THREADS];
int t;
for(t=0; t<NUM_THREADS; t++) {
idx[t] = t;
pthread_create(&threads[t], NULL, f, (void*)&idx[t]);
}
for(t=0; t<NUM_THREADS; t++)
pthread_join(threads[t], NULL);
printf("%i\n", v);
pthread_exit(NULL);
return 0;
}
The program can be compiled with
$ gcc -Wall pthreads.c -o pthreads -pthread -lm -O2
where -pthread tells the compiler to link against the Pthreads library and -lm is needed for linking against the math library. This program has a race condition, consecutive executions can give different outputs. Such errors are hard to find because they can show up very rarely. Helgrind can tell you the problematic part of your code:
$ valgrind --tool=helgrind ./pthreads ... ==29237== ---------------------------------------------------------------- ==29237== ==29237== Possible data race during read of size 4 at 0x600C78 by thread #3 ==29237== Locks held: none ==29237== at 0x4007BC: f(void*) (in /pfs/data2/home/xx/xxxx/xxxx/pthreads) ==29237== by 0x4A0C0D4: mythread_wrapper (hg_intercepts.c:219) ==29237== by 0x3EDA6079D0: start_thread (in /lib64/libpthread-2.12.so) ==29237== by 0x3ED9AE8B6C: clone (in /lib64/libc-2.12.so) ==29237== ==29237== This conflicts with a previous write of size 4 by thread #2 ==29237== Locks held: none ==29237== at 0x4007FB: f(void*) (in /pfs/data2/home/xx/xxxx/xxxx/pthreads) ==29237== by 0x4A0C0D4: mythread_wrapper (hg_intercepts.c:219) ==29237== by 0x3EDA6079D0: start_thread (in /lib64/libpthread-2.12.so) ==29237== by 0x3ED9AE8B6C: clone (in /lib64/libc-2.12.so) ==29237== ==29237== ---------------------------------------------------------------- ...
Now we know that we have to check the function f for a possible data race. A similar output can be achieved using drd with the following command:
$ valgrind --tool=drd ./pthreads
Valgrind can give even better hints when compiled with debug information (helgrind produces similar output):
$ gcc -g -Wall pthreads.c -o pthreads -pthread -lm $ valgrind --tool=drd ./pthreads ... ==604== Thread 3: ==604== Conflicting load by thread 3 at 0x00600cc0 size 4 ==604== at 0x400749: f(void*) (pthreads.c:17) ==604== by 0x4A128B4: vgDrd_thread_wrapper (drd_pthread_intercepts.c:355) ==604== by 0x3EDA6079D0: start_thread (in /lib64/libpthread-2.12.so) ==604== by 0x3ED9AE8B6C: clone (in /lib64/libc-2.12.so) ==604== Allocation context: BSS section of fs/data2/home/xx/xxxx/xxxx/pthreads ==604== Other segment start (thread 2) ==604== (thread finished, call stack no longer available) ==604== Other segment end (thread 2) ==604== (thread finished, call stack no longer available) ...
The execution can take longer but now we know that the problem is most likely in line 17 (which is correct).