Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Golang race detection – Neven Miculinić

Golang race detection – Neven Miculinić

GopherCon Russia

April 13, 2019
Tweet

More Decks by GopherCon Russia

Other Decks in Programming

Transcript

  1. Counter example var Cnt int func Run(amount int) { for

    i := 0; i < amount; i++ { Cnt++ } }
  2. Counter example func main() { wg := &sync.WaitGroup{} for i

    := 0; i < 10; i++ { wg.Add(1) go func() { Run(1000); wg.Done() }() } wg.Wait(); fmt.Println(Cnt) }
  3. Therac-25 • Radiotherapy machine • Race condition between user input

    and system state • Consequences: 6+ accidents, 2+ deaths
  4. Happens before G1: 0 G2: 0 G1: 1 G1: 2

    G2: 3 G2: 1 G2: 2 G1: 3 G2: 4 CHAN RECV CHAN SEND
  5. Happens before G1: 0 G2: 0 G1: 1 G1: 2

    G2: 3 G2: 1 G2: 2 G1: 3 G2: 4 MUTEX LOCK MUTEX UNLOCK
  6. Race on loop counter func main() { var wg sync.WaitGroup

    wg.Add(5) for i := 0; i < 5; i++ { go func() { fmt.Println(i) // Not the 'i' you are looking for. wg.Done() }() } wg.Wait() }
  7. Race on loop counter func main() { var wg sync.WaitGroup

    wg.Add(5) for i := 0; i < 5; i++ { go func(j int) { fmt.Println(j) wg.Done() }(i) } wg.Wait() }
  8. Unprotected global var Cnt int func Inc(amount int) { Cnt

    += amount } func main() { go Inc(10) go Int(100) }
  9. Unprotected global var Cnt int var m = &sync.Mutex{} func

    Inc(amount int) { m.Lock() defer m.Unlock() Cnt += amount }
  10. Violating go memory model (aka being smart) var a string

    var done bool func setup() { a = "hello, world" done = true } func main() { go setup() for !done { } fmt.Print(a) }
  11. ThreadSanitizer v2 • Battle proven library • Runtime slowdown 2x-20x.

    • Memory overhead 5x-10x. • Requires CGO, 64bit OS • No false positives
  12. func Inc(x *int) { *x++ } Compiler instrumentation movq "".x+32(SP),

    AX movq AX, (SP) call runtime.raceread(SB) movq "".x+32(SP), AX movq (AX), CX movq CX, ""..autotmp_4+8(SP) movq AX, (SP) call runtime.racewrite(SB) incq AX movq "".x+32(SP), CX movq AX, (CX)
  13. func Inc(x *int) { *x++ } Compiler instrumentation ... call

    runtime.raceread(SB) ... call runtime.racewrite(SB) ...
  14. Vector clocks G1: 0 G2: 0 G1: 0 G2: 0

    G1: 1 G2: 0 G1: 2 G2: 0 G1: 0 G2: 3 G1: 0 G2: 1 G1: 0 G2: 2
  15. Vector clocks G1: 0 G2: 0 G1: 0 G2: 0

    G1: 1 G2: 0 G1: 2 G2: 0 G1: 0 G2: 3 G1: 0 G2: 1 G1: 0 G2: 2 G1: 3 G2: 3 G1: 0 G2: 4 MUTEX LOCK MUTEX UNLOCK
  16. Vector clocks • Partially ordered set • (4, 11) <

    (10, 12) → happens before • (12, 5) is concurrent to (7, 12)
  17. DJIT+ We remember vector clocks for: • Each lock release

    L m = (t 0 , ... , t n ) • Last memory read, R x = (t 0 , …, t n ) • Last memory write W x = (t 0 , …, t n ) • Goroutine vector clock, C x = (t 0 , …, t n )
  18. DJIT+ 4 0 4 0 5 0 5 0 5

    0 0 8 0 8 0 8 4 8 4 8 0 0 0 0 4 0 4 0 4 0 0 0 4 0 4 0 4 0 4 8 C 0 C 1 L m W x w(x) w(x) unlock (m) lock (m)
  19. DJIT+ 4 0 4 0 4 0 4 0 4

    0 0 8 0 8 0 8 0 8 0 8 0 0 0 0 0 0 0 0 0 0 0 0 4 0 4 0 4 0 RACE C 0 C 1 L m W x w(x) w(x)
  20. FastTrack 4 0 4 0 5 0 5 0 5

    0 0 8 0 8 0 8 4 8 4 8 0 0 0 0 4 0 4 0 4 0 0@0 C 0 C 1 L m W x w(x) w(x) unlock (m) lock (m) 4@0 4@0 4@0 8@1
  21. FastTrack 4 0 4 0 4 0 4 0 4

    0 0 8 0 8 0 8 4 8 4 8 0 0 0 0 0 0 0 0 0 0 0@0 C 0 C 1 L m R x r(x) r(x) 4@0 4@0 4@0 4 8
  22. Shadow word pool Write goroutine 1 10@1 0:2 W 10

    0 0 Memory mapped Fixed size pool 64 bits
  23. Shadow word pool Read goroutine 3 10@1 0:2 W 20@2

    4:8 R 40@3 0:4 R RACE found 5 0 40
  24. Summary var Cnt int64 func Run(amount int) { for i

    := 0; i < amount; i++ { val := atomic.LoadInt64(&Cnt) val ++ atomic.StoreInt64(&Cnt, val) } }
  25. References • https://github.com/google/sanitizers/wiki/ThreadSanitizerAlgorithm • https://golang.org/doc/articles/race_detector.html • https://golang.org/ref/mem • ""go test

    -race" Under the Hood" by Kavya Joshi • https://blog.golang.org/race-detector • https://danluu.com/concurrency-bugs/ • ThreadSanitizer – data race detection in practice google paper • FastTrack: Efficient and Precise Dynamic Race Detection • AddressSanitizer/ThreadSanitizer for Linux Kernel and userspace. • [DJIT+ algo] MultiRace: efficient on-the-fly data race detection in multithreaded C++ programs • On the Complexity of Event Ordering for Shared-Memory Parallel Program Executions (Netzer, Miller, 1990)
  26. Appendix A - go -race tunables From: https://golang.org/doc/articles/race_detector.html#Options GORACE="option1=val1 option2=val2"

    The options are: • log_path (default stderr): • exitcode (default 66): • strip_path_prefix (default ""): • history_size (default 1). • halt_on_error (default 0):
  27. Appendix C - Shared-Variable Shenanigans From: Is Parallel Programming Hard,

    And, If So, What Can You Do About It?, Paul E. McKenney • Load/Store tearing • Load/Store fusing • Code reordering • Invented stores/loads