Skip Navigation Links | |
Exit Print View | |
![]() |
Oracle Solaris Studio 12.3: Thread Analyzer User's Guide Oracle Solaris Studio 12.3 Information Library |
1. What is the Thread Analyzer and What Does It Do?
2.1 Data Race Tutorial Source Files
2.1.1 Getting the Data Race Tutorial Source Files
2.1.2 Source Code for prime_omp.c
2.1.3 Source Code for prime_pthr.c
2.1.3.1 Effect of Data Races in prime_omp.c and prime_pthr.c
2.2 How to Use the Thread Analyzer to Find Data Races
2.2.1.1 To Instrument Source Code
2.2.1.2 To Instrument Binary Code
2.2.2 Create a Data Race Detection Experiment
2.2.3 Examine the Data Race Detection Experiment
2.2.3.1 Using Thread Analyzer to View the Data Race Experiment
2.3 Understanding the Experiment Results
2.3.1 Data Races in prime_omp.c
2.3.2 Data Races in prime_pthr.c
2.3.3 Call Stack Traces of Data Races
2.4 Diagnosing the Cause of a Data Race
2.4.1 Check Whether or Not the Data Race is a False Positive
2.4.2 Check Whether or Not the Data Race is Benign
2.4.3 Fix the Bug, Not the Data Race
2.4.3.1 Fixing Bugs in prime_omp.c
2.4.3.2 Fixing Bugs in prime_pthr.c
2.5.1 User-Defined Synchronizations
2.5.2 Memory That is Recycled by Different Threads
2.6.1 A Program for Finding Primes
2.6.2 A Program that Verifies Array-Value Types
2.6.3 A Program Using Double-Checked Locking
The Thread Analyzer follows the same “collect-analyze” model that the Oracle Solaris Studio Performance Analyzer uses.
There are three steps involved in using the Thread Analyzer:
In order to enable data race detection in a program, the code must first be instrumented to monitor memory accesses at runtime. The instrumentation can be done on application source code, or on application binaries that have been compiled with certain Oracle compiler optimization flags. The tutorial shows how to use both methods of instrumenting the programs.
To instrument the source code, you must compile the application with the special compiler option -xinstrument=datarace. This option instructs the compiler to instrument the generated code for data race detection.
Add the -xinstrument=datarace compiler option to the existing set of options you use to compile your program.
Note - Be sure to also specify the -g option when you compile your program with -xinstrument=datarace to generate additional information to enable the Analyzer's full capabilities. Do not specify a high level of optimization when compiling your program for race detection. Compile an OpenMP program with -xopenmp=noopt. The information reported, such as line numbers and call stacks, may be incorrect when a high optimization level is used.
You can use the following commands for instrumenting the source code for the tutorial:
% cc -xinstrument=datarace -g -xopenmp=noopt -o prime_omp_inst prime_omp.c -lm
% cc -xinstrument=datarace -g -o prime_pthr_inst prime_pthr.c -lm
Notice that in the example, the output file is specified with _inst at the end so that you can tell that the binary is the instrumented binary. This is not required.
To instrument a program's binary code instead of the source code, you need to use the discover tool, which is included in Oracle Solaris Studio and is documented in the discover(1) man page and Oracle Solaris Studio 12.3: Discover and Uncover User’s Guide.
See Binary-level Instrumentation for more information about requirements for binary instrumentation.
For the tutorial examples, type the following command to compile the code with optimization level 3 to create binaries that can be used by discover.
% cc -xopenmp=noopt -g -o prime_omp_opt prime_omp.c -lm
% cc -g -O3 -o prime_pthr_opt prime_pthr.c -lm
Then run discover on the prime_omp_opt and prime_pthr_opt optimized binaries that you created:
% discover -i datarace -o prime_omp_disc prime_omp_opt
% discover -i datarace -o prime_pthr_disc prime_pthr_opt
These commands create instrumented binaries, prime_omp_disc and prime_pthr_disc that you can use with collect to create experiments that you can examine with the Thread Analyzer.
Use the collect command with the -r race flag to run the program and create a data race detection experiment during the execution of the process. For OpenMP programs, make sure that the number of threads used is larger than one. In the tutorial samples, four threads are used.
To create experiments from the binaries that you created by instrumenting the source code:
% collect -r race -o prime_omp_inst.er prime_omp_inst
% collect -r race -o prime_pthr_inst.er prime_pthr_inst
To create experiments from the binaries that you created by using the discover tool:
% collect -r race -o prime_omp_disc.er prime_omp_disc
% collect -r race -o prime_pthr_disc.er prime_pthr_disc
To increase the likelihood of detecting data races, it is recommended that you create several data race detection experiments using collect with the -r race flag. Use a different number of threads and different input data for each experiment.
For example, in prime_omp.c, the number of threads is set by the following line:
#define THREADS 4
The number of threads can be changed by changing 4 in the above to some other integer larger than 1, for example 8.
The following line in prime_omp.c limits the program to look for prime numbers between 2 and 3000:
#define N 3000
You can provide different input data by changing the value of N to make the program do more or less work.
You can examine a data race detection experiment with the Thread Analyzer, the Performance Analyzer, or the er_print utility. Both the Thread Analyzer and the Performance Analyzer present a GUI interface; the Thread Analyzer presents a simplified set of default tabs, but is otherwise identical to the Performance Analyzer.
To start the Thread Analyzer, type the following command:
% tha
The Thread Analyzer GUI has a menu bar, a tool bar, and a split pane that contains tabs for the various displays.
On the left-hand pane, the following three tabs are shown by default:
The Races tab shows a list of data races detected in the program, and associated call stack traces. This tab is selected by default.
The Dual Source tab shows the two source locations corresponding to the two accesses of a selected data race. The source line where a data race access occurred is highlighted.
The Experiments tab shows the load objects in the experiment, and lists error and warning messages.
On the right-hand pane of the Thread Analyzer display, the following two tabs are shown:
The Summary tab shows summary information about a data race access selected from the Races tab.
The Race Details tab shows detailed information about a data race or call stack trace selected from the Races tab.
The er_print utility presents a command-line interface. You can use the er_print utility in an interactive session and specify sub-commands during the session. You can also use command-line options to specify sub-commands non-interactively.
The following sub-commands are useful for examining races with the er_print utility:
-races
This reports any data races revealed in the experiment. Specify races at the (er_print) prompt or -races on the er_print command line.
-rdetail race_id
This displays detailed information about the data race with the specified race_id. Specify rdetail at the (er_print) prompt or -rdetail on the er_print command line. If the specified race_id is all, then detailed information about all data races will be displayed. Otherwise, specify a single race number such as 1 for the first data race.
-header
This displays descriptive information about the experiment, and reports any errors or warnings. Specify header at the (er_print) prompt or -header on the command line.
Refer to the collect(1), tha(1), analyzer(1), and er_print(1) man pages for more information.