Debugging Threading Errors with Intel Inspector and Coderrect
Modern computers contain multiple processors, multi-core processors, or hyperthreading processes that can run several simultaneous threads. Parallel processing using many threads can greatly improve program performance, but it may also make debugging more difficult because you’re tracking many threads at a time. Multithreading can also introduce new types of potential bugs like a data race or a deadlock condition which are often hard to identify.
Data Race
It is an error that arises during the execution of a multi-threaded program. A data race occurs when:
- multiple threads in a single process access the same memory location concurrently, and
- at least one of the accesses is for writing, and
- the threads are not using any exclusive locks to control their accesses to that memory.
This condition causes the same program to return different outputs on each execution.
Deadlock
Some sort of mutual exclusion mechanism is used to handle data races in multi-threaded programs. However, incorrect implementation of mutual exclusion can create a deadlock condition. A deadlock is a situation in which two threads sharing the same resource effectively prevent each other from accessing the resource, resulting in both threads ceasing to function and eventually stopping the program. Deadlocks are often a hard problem to debug.
Debugging Tools:
The two popular debugging tools used to tackle such errors are;
Let’s use the tools on a simple program designed to compute pi=3.1415926….
#include <omp.h>;
#include <std.h>;
#include <stdlib.h>;
#define MAX_THREADS 4
static long steps = 1000000000;
double step;
int main (int argc, const char *argv[]) {
int i,j;
double x;
double pi, sum = 0.0;
double start, delta;
step = 1.0/(double) steps;
// Compute parallel compute times for 1-MAX_THREADS
for (j=1; j<= MAX_THREADS; j++) {
printf(" running on %d threads: ", j);
// This is the beginning of a single PI computation
omp_set_num_threads(j);
sum = 0.0;
double start = omp_get_wtime();
#pragma omp parallel for reduction(+:sum)
for (i=0; i < steps; i++) {
x = (i+0.5)*step;
sum += 4.0 / (1.0+x*x);
}
// Out of the parallel region, finialize computation
pi = step * sum;
delta = omp_get_wtime() - start;
printf("PI = %.12g computed in %.4g seconds\n", pi, delta);
}
}
This simple program computes the value of Pi on 1,2,3, and 4 threads respectively.
It is clear that there is a data race in our program. Running on different number of threads generated different values of Pi, indicating the existence of a concurrency bug. Let’s use the tools to debug our program.
Setup
Coderrect
Coderrect has a simple installation process. After downloading the latest version of the software from www.coderrect.com, you need to follow the simple installation guide.
Note: Coderrect only works on Linux OS
Intel Inspector
After choosing and downloading your selection from https://software.intel.com/content/www/us/en/develop/tools/inspector.html, go through the setup guide provided in the download. Inspector is available through different interfaces and on multiple operating systems. To keep the comparison fair, we will be using Inspector on Linux OS.
Working
Coderrect
Coderrect can be operated through the command-line (CL) interface that can be accessed with the ‘coderrect’ command. It does not have a Graphical User Interface (GUI). Coderrect generates an intermediate representation of the source code in the form of LLVM bitcode (BC) files and then performs sophisticated static analyses based on them to find potential race conditions. Though it intercepts the build commands it does not change the build targets.
After each analysis, it creates an HTML report named index.html. By default, it is stored in a directory named report. However, the destination folder can be specified using ‘-o <directory>’ and if specified using the command ‘-t’ it outputs a brief report to the terminal window.
Intel Inspector
Inspector includes both a GUI and a CL interface that can be accessed with the ‘inspxe-gui’ and ‘inspxe-cl’ commands, respectively. Inspector works by performing a dynamic analysis (that is, instrumenting and analyzing execution at run time). It can detect intermittent and non-deterministic errors, even if the errors do not manifest themselves.
Before getting started, compile your application in the debug mode (‘-g’ for GCC compiler) to get the debug information. When running the GUI, begin by creating a new project, entering the executable path, arguments, environment variables, and set other options.
After the analysis completes, the GUI will bring up the Summary view. The Problems pane lists all of the potential errors that the Inspector found. Click on a specific problem to display the corresponding source code for the selected problem in the Code Locations panel.
Report
Coderrect
Running coderrect on our code produces the following output.
Coderrect has caught the 2 threads that were causing a data race, which resulted in producing ambiguous outputs. Using this information, we could edit the source code probably using a locking mechanism to rectify the error and eliminate the data race.
Intel Inspector
Once Inspector finishes analyzing our code, it displays the following summary highlighting the code snippets where the threads try to increment the shared variable.
We could then edit our code in the GUI or outside inspector.
Conclusion
As seen above, both the tools were able to detect the data race and help us locate the part of the program that caused it.
Intel Inspector
Pros
- Performs an intensive analysis
- Has a nice interactive GUI that is easy to use
- Can also detect memory leaks
Cons
- Time-consuming and memory-intensive
- The application must be developed in debugging mode
- Can work only on an executable code
Coderrect
Pros
- Easy to use and implement
- Quick and memory-efficient
- HTML report that can be transferred
Cons
- Lacks a GUI
- Works only on Linux
Though there are many more constraints to be considered while choosing one of the tools for your project, I hope this article has helped you gain a better understanding of the two tools.