Detect Fortran OpenMP Races

This tutorial shows how to use Coderrect to detect races in a single file multi-threaded Fortran program written with OpenMP.


Prerequisites


Detecting a race

We will be using a benchmark from DataRaceBench, a suite of OpenMP data race benchmarks designed to evaluate the effectiveness of data race detection tools developed by a group at Lawrence Livermore National Lab. DataRaceBench is full of great test cases (try using it to evaluate coderrect!).

We will be using the DRB001-antidep1-orig-yes.f95 case from DataRaceBench version 1.3.0.1. You can get the source code from the DataRaceBench repository on github, but we have included a snippet here for convenience.

!!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!!
!!! Copyright (c) 2017-20, Lawrence Livermore National Security, LLC
!!! and DataRaceBench project contributors. See the DataRaceBench/COPYRIGHT file for details.
!!!
!!! SPDX-License-Identifier: (BSD-3-Clause)
!!!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!!!

!A loop with loop-carried anti-dependence.
!Data race pair: a[i+1]@25:9 vs. a[i]@25:16

program DRB001_antidep1_orig_yes
use omp_lib
    implicit none
    integer :: i, len
    integer :: a(1000)

    len = 1000

    do i = 1, len
        a(i) = i
    end do

    !$omp parallel do
    do i = 1, len-1
        a(i) = a(i+1) + 1
    end do
    !$omp end parallel do

    print 100, a(500)
    100 format ('a(500)=',i3)
end program

Start by checking that the program compiles successfully on your machine. Coderrect works by intercepting compiler calls. If the code cannot be compiled, Coderrect cannot run it’s analysis. The DRB001 benchmark can be built with the following command

gfortran -fopenmp DRB001-antidep1-orig-yes.f95 -o DRB001
./DRB001

You should see output that looks something like:

a(500)=502

Although your results may vary because there is a data race in this code. In the parallel for loop, the value of each iteration i depends on the next iteration i+1.

This means that thread 0 could be executing a[0] = a[1] + 1 at the same time thread 1 is running a[1] = a[2] + 1. Both threads are accessing a[1] in parallel, causing a data race.


Run Coderrect

The easiest way to run the tool is by passing the build command to coderrect:

coderrect -t gfortran -fopenmp DRB001-antidep1-orig-yes.f95 -o DRB001

Remember, the command to build DRB001 was gfortran -fopenmp DRB001-antidep1-orig-yes.f95 -o DRB001.

the -t switch is used to generate a quick summary report in terminal.

Calling coderrect in this way ensures all the required compilation flags can be passed on the command line. For a project using a build system such as make, coderrect tool can be called with the same build command used to build the project. For an example: checkout out detecting races in a Makefile-based project.


Interpret the Results

The coderrect tool reports a quick summary of the most interesting races directly in the terminal for quick viewing. The tool also generates a more comprehensive report that can be viewed in a browser.

Terminal Report

The terminal report for DRB001 should look something like the following:

==== Found a data race between: 
line 25, column 0 in DRB001-antidep1-orig-yes.f95 AND line 25, column 1 in DRB001-antidep1-orig-yes.f95
Shared variable:
 at line 0 of 
 0|
Thread 1:
 23|    !$omp parallel do
 24|    do i = 1, len-1
>25|        a(i) = a(i+1) + 1
 26|    end do
 27|    !$omp end parallel do
>>>Stacktrace:
Thread 2:
 23|    !$omp parallel do
 24|    do i = 1, len-1
>25|        a(i) = a(i+1) + 1
 26|    end do
 27|    !$omp end parallel do
>>>Stacktrace:

Each reported race starts with a summary of where the race was found.

==== Found a race between: 
line 25, column 0 in DRB001-antidep1-orig-yes.f95 AND line 25, column 1 in DRB001-antidep1-orig-yes.f95

Next the report shows the variable name and location on which the race occurs. (Though this is sometimes not present for fortran programs)

Shared variable:
 ...

Going and finding the race location in the code may be a little tedious so the report also shows a preview of the file at that location.

Thread 1:
 23|    !$omp parallel do
 24|    do i = 1, len-1
>25|        a(i) = a(i+1) + 1
 26|    end do
 27|    !$omp end parallel do

The code snippet shows that this racing access is a write to a(i) as part of an OpenMP parallel for loop.

This is the race we expected to find for this DataRaceBench case. You can try running coderrect in the same way on the other DataRaceBench fortran benchmarks at dataracebench/micro-benchmarks-fortran.


HTML Report

The terminal is great to get a quick idea about what races are reported, but the full report can be viewed in a browser.

We can also save the race report to a directory specified via the command option-o <dir>.

coderrect -o report gfortran -fopenmp DRB001-antidep1-orig-yes.f95 -o DRB001

This created a directory named report and a file named index.html within that directory. To view the full report open the index.html file in a browser.