1 of 52

HPC Concurrency Verification Tools

2 of 52

Project Discussions

  • Rust verification resources + tools being discovered
    • Creosot, Prusti, …
  • Go verification
    • MPI analysis
      • Message-matching non-determinism
        • Hard-to-force schedules
          • Race coverage can be lower
      • Expanding feasible schedules
        • Koushik Sen Berkeley
          • Globals → enhance coverage
  • Non-blocking data structure analysis
    • Frama-C
      • Prefer faking non-blk d.s.
    • Viktor Vaefadis has any tools? MPI
    • CSeq
      • Can do context-bounding-based verification
    • PlusCal
      • Can model anything that can be put into a model-checker - YMMV
  • Probabilistic model-checkers
    • Prism
    • Storm
  • Probabilistic Programming
    • Todd Millstein, UCLA
      • BDD-based tools

3 of 52

Overview of what you'll learn today

  • HPC uses many concurrency models
    • MPI
    • OpenMP
    • CUDA
  • These will remain separate for some time to come
    • Attempts to unify exist
      • DataParallel C++
      • OneAPI
  • In this lecture, we will obtain a taste of formally analyzing
    • MPI
    • OpenMP
  • What is formal
    • MPI
      • Some measurable notion of schedule-coverage
    • OpenMP
      • Ability to detect data races
        • for specific schedules
        • and to guarantee that the report races are not false-alarms

4 of 52

Keep in mind that

  • Race-checking is now built-in as part of compilation
    • as flags
    • just add -fsanitize=thread to the clang compiler command and it finds
      • the race when you run it
      • -fsanitize=address cannot be used at the same time as thread
        • but can be used separately
  • Go also uses similar race-checking
  • These flags are now available during GCC compilation also

5 of 52

Overview of what you'll learn today

6 of 52

What are observable effects of data races?

I'm sure the term "data race" is not new to most of you.

What do you understand by it?

Most would say "introduces nondeterminism"

7 of 52

What are observable effects of data races?

Most would say "introduces nondeterminism"

Well, if the desired behavior is deterministic, then seeing

nondeterminstic outcomes is bad

NOT TRUE!

Many programs are supposed to produce nondeterministic outputs!

8 of 52

Example

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

9 of 52

Example

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

Notice that there is nondeterminism!

Even if we put a "lock / unlock" surrounding each statement (which eliminates all races), this can be observed!

10 of 52

Example

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

Thus, please don't hereafter say that "when there is a data race, the results will be nondeterminstic" and pretend that that's it, and that's bad!

Because that may be what the final semantics requires (to see all these values) … as in an OS

11 of 52

Example : one more twist

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

x == 5 ? How can this be seen?

12 of 52

Example : one more twist

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

x == 5 ?

Answer: When the compiler moves the

y := y + 1 before the x := z + 2

13 of 52

Background on Compilers

  • Compilers can freely move and combine instructions within one thread, provided it does not alter the dependencies
  • In a single serial program, we pretty much only have the flow dependency

14 of 52

Example : one more twist

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

x == 5 is NEVER possible under sequential consistency! (What is it ??)

15 of 52

Sequential Consistency (defined by Lamport)

https://en.wikipedia.org/wiki/Sequential_consistency

https://en.wikipedia.org/wiki/Leslie_Lamport

16 of 52

Example : one more twist

This program has a data race

Initially globals x == y == z == 0

P1 || P2

---------- ------------

y := 1 y := 2

x := z + 2

y := y + 1

z := y + x

Finally x == ?

x == 2 ? How ?

x == 3 ? How ?

x == 4 ? How ?

x == 5 is NEVER possible under sequential consistency!

Programmers (subconsciously ascribe the SC semantics to all concurrent programs)!

17 of 52

Summary

Data races can introduce behaviors outside of those formally specified for the program in question!

This may (for instance) variables reading values that were never written!

18 of 52

One more example

initially, globals x == 0, y == 0

(Let's use Hex)

P1 || P2 || P3

---------- ------------ -----------

x := DEAD x := BEEF y := x

Finally y == ?

y == DEAD how?

y == BEEF how?

y == DEEF how?

y == BEAD how?

19 of 52

One more example

initially, globals x == 0, y == 0

(Let's use Hex)

P1 || P2 || P3

---------- ------------ -----------

x := DEAD x := BEEF y := x

Finally y == ?

y == DEAD how?

y == BEEF how?

y == DEEF how? word tearing!

y == BEAD how? word tearing!

Hilarious example courtesy of Prof. John Regeher https://gcc.godbolt.org/z/dY4Pc1oxY

20 of 52

One more example

initially, globals x == 0, y == 0

(Let's use Hex)

P1 || P2 || P3

---------- ------------ -----------

x := DEAD x := BEEF y := x

Finally y == ?

y == DEAD how?

y == BEEF how?

y == DEEF how? word tearing!

y == BEAD how? word tearing!

Hilarious example courtesy of Prof. John Regeher https://gcc.godbolt.org/z/dY4Pc1oxY

21 of 52

One more example

initially, globals x == 0, y == 0

(Let's use Hex)

P1 || P2 || P3

---------- ------------ -----------

x := DEAD x := BEEF y := x

Finally y == ?

y == DEAD how?

y == BEEF how?

y == DEEF how? word tearing!

y == BEAD how? word tearing!

Hilarious example courtesy of Prof. John Regeher https://gcc.godbolt.org/z/dY4Pc1oxY

YET, we see abusive use of deprecated "volatile" in CUDA in the hopes of preventing tearing

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html

22 of 52

One more example

initially, globals x == 0, y == 0

(Let's use Hex)

P1 || P2 || P3

---------- ------------ -----------

x := DEAD x := BEEF y := x

Finally y == ?

y == DEAD how?

y == BEEF how?

y == DEEF how? word tearing!

y == BEAD how? word tearing!

Hilarious example courtesy of Prof. John Regeher https://gcc.godbolt.org/z/dY4Pc1oxY

YET, we see abusive use of deprecated "C volatiles" in CUDA in the hopes of preventing tearing (see C-standards committee document that deprecates volatiles)

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1152r0.html

23 of 52

Terminology Warning

  • C volatiles (yuck!) are
  • Completely different from Java volatiles (yum!)

24 of 52

Purpose of this lecture

  • How this meaning changes is often not taught in depth
    • teaching the existence of the danger is one thing (and might be taught)
      • teaching tools that check for these dangers is what we aim here
  • In short
    • Compilers such as for OpenMP or CUDA can happily compile racy programs
      • They don't check the races for you !!
    • The onus is on the user to ensure that there aren't any data races
  • Tools that catch data races do exist but they do not provide full guarantees
      • in principle the program must be run across
        • all inputs
        • all schedules
    • Impossible!
  • But at least how to do this to the extent feasible is important!

25 of 52

Purpose of this lecture

  • To expose you to dynamic data race checkers
  • To tell you that a program with data races is broken!
    • As broken as a program that seg-faults

  • YET
    • There are no usable data race checkers for CUDA that catch important subsets of races
    • For example
      • CUDA MemCheck does not catch global memory data races

Thus, all CUDA programs are suspect, and potentially broken!

(unless you can somehow check via manual reasoning…)

26 of 52

Organization

  • Let us understand the scope and extent of this problem
  • Discuss what can be done to make progress

27 of 52

Overview: Input space of a program

  • All inputs you can provide to a program
  • For a linear solver that solves Ax = B, it is
    • all the A matrices
    • all the b vectors
  • For an A matrix of 1K x 1K and b vector of 1K, this space is
    • 2^{billion}
    • Just remember for comparison….
      • there are 2^{200} atoms in the universe

28 of 52

Overview: Schedule-space of a program

  • All concurrent interleavings you have among N threads
    • If there are N threads
    • with k instructions each
      • There are (N . k) ! / (k!) ^ N schedules
      • For N = 5 threads and k = 5 instructions in them, we have
        • (25!) / (5!)^5
        • = 623 trillion schedules
      • This is like
        • riffle-shuffling 5 decks of 5 cards
  • For a program with 10 threads and 10 instructions,
    • 2.35 * 10^{92} schedules!

29 of 52

Overview: You cannot exhaust input and schedule spaces

  • One cannot cover all inputs and schedules
  • Static analysis?
    • It can cover any input- and schedule-space
    • Unfortunately
      • Static-analysis based data race detectors give too many false positives
  • So we will learn about dynamic data race checking today

Before we do that, let's "see some races" that have arisen in the field

30 of 52

Races in OpenMP

  • Can lead to inexplicable bugs

31 of 52

Races in GPU Codes

32 of 52

Races in GPU Codes

33 of 52

(Background: 10-min Video - on Java Memory Models)

This video of 10 minutes

is done remarkably well!

In 10 minutes, it explains

  • the basics of JMM
  • many pitfalls

34 of 52

Example of a non-racy Java program (see gist next slide)

  • race prevented by using volatile declarations
  • These are Java volatiles !!!
  • Basically they arrange for memory fences and also prevent word tearing

35 of 52

Gist of a non-racy Java program easily made racy

  • If req and ack are volatile, the 4-cycle handshake proceeds smoothly
  • If you don't use "volatile", the program deadlocks which is one consequence of a a data race in this program
  • But this deadlock is very sporadic (have to run the right number of iterations)

(DEMO)

OR they are held in the cache and not flushed

Hard to debug (hard to even see the assembly code…)

36 of 52

Other Race Scenarios: affected by compiler optimizations

37 of 52

Other Race Scenarios: affected by compiler optimizations

38 of 52

Bugs Related to Races

  • Lost atomicity + racs

39 of 52

Photoshop Bug

40 of 52

Photoshop Bug

41 of 52

To understand how to analyze programs, we need the notion of memory models

i.e. shared memory consistency models

not just memory organization models

  • A memory model specifies the happens-before relation
  • which expresses the logical order in which
    • all operations appear to have happened
  • and every read returns the latest write in the HB predecessor chain
  • The "happens before" is a relation PER INTERLEAVING of threads
    • That defines the LOGICAL ORDER in which the code may be found to be executed
    • We will provide examples of HB soon (not formally define it here)
      • But, please remember that the newer C and C++ ("c11") memory models
        • Start with sequential C
        • Define its HB
        • Nicely lift it thru parallel programs
        • A MUST READ BECAUSE OpenMP and CUDA are going this way!

42 of 52

Great examples from the JMM tutorial

There are HB edges from the assignments

to a,b,c and the write to x in writerThread

One can replace int r2 = x in readerThread()

with a while (x==0) { /* wait */ } loop

Then it is guaranteed that a,b,c will be 1 in

readerThread()

43 of 52

Great examples from the JMM tutorial

There are HB edges from the assignments

to a,b,c and the synchronized block in the writer

If x==1 in readerThread(), then

it guaranteed that a,b,c will be 1

44 of 52

Great examples from the JMM tutorial

Without the

volatile

declaration,

the readerThread()

need not exit

volatile inserts

fences

and also forces

stores

45 of 52

Gist of how dynamic race checkers check races

  • Run all possible interleavings
  • Build the happens-before relation per interleaving
    • Yes, HB is a function of interleavings!
  • If there is at least one HB where
    • there is a read or a write from some thread T1 ("action 1")
    • and a write from some thread T2 ("action 2")
    • where there is no HB ordering between "action 1" and "action 2"
    • then
      • THERE IS A DATA RACE!

46 of 52

The importance of running sufficient # of interleavings

This slide also provides the only real portrayal of HB in some detail! Study it carefully!

47 of 52

Race Checking Concepts

Talk by Simone Atzeni

https://drive.google.com/drive/u/1/folders/16dqtgiRK-hjQnejWOEWJYM5NvSiWejk9

48 of 52

Race Examples from OMP

Slides by Simone Atzeni

https://drive.google.com/drive/u/1/folders/16dqtgiRK-hjQnejWOEWJYM5NvSiWejk9

49 of 52

Example of GPU (CUDA) Races

These slides present short GPU race scenarios and how our former GKLEE tool used to spot them

https://drive.google.com/drive/u/1/folders/1VMg3mWxxG1HsBeyroKpAXUoUVa9bPKPM

50 of 52

Example of Running Archer

Show demo using

docker pull tanmaytirpankar/openmpracechecker:1.0

and run Archer

(Class demo)

51 of 52

Race checking for PThreads, etc.

Many types of checks; see here (many are GCC / Clang flags)

https://github.com/google/sanitizers/wiki/

Most of these were created using the ideas in Flanagan's "FastTrack" which were made even more efficient by Google scientists Serebranyay and Vyukov

�These power Archer and Go's race checker as well

Our tool Sword uses a different approach

Static analysis based race checking of OMP : LLOV tool

52 of 52

Concluding Remarks

  • Realize the danger of races
  • Look for a race checking tool
  • Check for races
  • Keep striving for more coverage
  • Help develop faster race checkers