Debugging Threading Errors with Intel Inspector and Coderrect

Akhil Robertson Cutinha
5 min readAug 21, 2020

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 &lt; 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.

output of pi.c

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.

Summary of Coderrect Analysis

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.

Inspector analyzing the program

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.

Detailed HTML analysis report from coderrect

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.

Shows the error type and the location
The exe code and the source code where the data race occurs

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.

--

--