KISS: Keep it Simple and Sequential A tool for finding bugs in - - PowerPoint PPT Presentation

kiss keep it simple and sequential
SMART_READER_LITE
LIVE PREVIEW

KISS: Keep it Simple and Sequential A tool for finding bugs in - - PowerPoint PPT Presentation

KISS: Keep it Simple and Sequential A tool for finding bugs in concurrent programs Steffen Juilf Smolka Technische Universitt Mnchen 17. Juli 2012 S. Smolka (TUM) KISS: Keep it Simple and Sequential 17. Juli 2012 1 Overview Motivation


slide-1
SLIDE 1

KISS: Keep it Simple and Sequential

A tool for finding bugs in concurrent programs Steffen Juilf Smolka

Technische Universität München

  • 17. Juli 2012
  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

1

slide-2
SLIDE 2

Overview

1

Motivation and Intuition behind KISS

2

The Transformation

3

Analysis and Conclusion

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

2

slide-3
SLIDE 3

Motivation

Gordan E. Moore, Intel Co-Founder, 1965 "The Free Lunch Is Over", Herb Sutter, 2005 increasing number of transistors now manifests itself in an increasing number of cores performant software relies on concurrency

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

3

slide-4
SLIDE 4

Challenges of Concurrent Programs

Difficult to get right

access to shared variables has to be synchronized sometimes counter-intuitive

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

4

slide-5
SLIDE 5

Challenges of Concurrent Programs

Difficult to get right

access to shared variables has to be synchronized sometimes counter-intuitive

Difficult to debug

nondeterministic in nature combinatorical explosion in number of possible schedules "Heisenbugs"

1 → 1 → 3 → 1 → 2 → 3

  • 3 → 1 → 3 → 1 → 2 → 1
  • 3 → 2 → 1 → 3 → 1 → 1

× ⇒ Testing is no longer an effective method for finding bugs ⇒ Tools for finding bugs are invaluable

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

4

slide-6
SLIDE 6

Traditional Approach

Define safety properties

assertions reachability, race conditions

Explore all possible thread interleavings

forbidding complexity, exponential in # threads Problem is undecidable [Ramalingam]

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

5

slide-7
SLIDE 7

Example

Main Thread

// global variables usb_driver driver; boolean is_running; boolean is_in_use; void main () { driver = init (); is_running = true; is_in_use = false; async(thrA ); async(thrB ); }

Thread A

void thrA () { if(is_running ){ is_in_use = true; // use driver ... . . . is_in_use = false; } }

Thread B

void thrB () { assume (! is_in_use ); is_running = false; // clean up ... free(driver ); . . . }

What assumptions are we making?

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

6

slide-8
SLIDE 8

Example

Main Thread

// global variables usb_driver driver; boolean is_running; boolean is_in_use; void main () { driver = init (); is_running = true; is_in_use = false; async(thrA ); async(thrB ); }

Thread A

void thrA () { if(is_running ){ is_in_use = true; // use driver ... . . . assert( is_running ); is_in_use = false; } }

Thread B

void thrB () { assume (! is_in_use ); is_running = false; // clean up ... free(driver ); . . . assert (! is_in_use ); }

What assumptions are we making?

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

7

slide-9
SLIDE 9

Example

Main Thread

// global variables usb_driver driver; boolean is_running; boolean is_in_use; void main () { driver = init (); is_running = true; is_in_use = false; async(thrA ); async(thrB ); }

Thread A

void thrA () { if(is_running ){ is_in_use = true; // use driver ... . . . assert( is_running ); is_in_use = false; } }

Thread B

void thrB () { assume (! is_in_use ); is_running = false; // clean up ... free(driver ); . . . assert (! is_in_use ); }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

8

slide-10
SLIDE 10

The Kiss Aproach

Idea: Transform concurrent program P to nondeterministic, sequential program Pseq , which simulates subset of possbile executions of P. Pseq

      

1 → 1 → 3 → 1 → 2 → 3 3 → 1 → 3 → 1 → 2 → 1 3 → 2 → 1 → 3 → 1 → 1 Pseq is a nondeterministic scheduler executing P.

Motivation

Semantics of sequential program are easier Make problem decidable Maybe we can avoid exponential complexity . . . Keep it Simple and Sequential!

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

9

slide-11
SLIDE 11

Properties of Pseq

Pseq satisfies = ⇒ P satisfies safety property ⇐ = safety property

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

10

slide-12
SLIDE 12

Properties of Pseq

DECIDABLE UNDECIDABLE Pseq satisfies

  • =

⇒ P satisfies safety property ⇐ = safety property

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

10

slide-13
SLIDE 13

Properties of Pseq

DECIDABLE UNDECIDABLE Pseq satisfies

  • =

⇒ P satisfies safety property ⇐ = safety property Pseq violates = ⇒ P violates safety property

= safety property

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

10

slide-14
SLIDE 14

The KISS architecture

KISS Sequential Checker No error found KISS Error trace for P Concurrent program P Sequential program Pseq Error trace for Pseq

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

11

slide-15
SLIDE 15

1

Motivation and Intuition behind KISS

2

The Transformation

3

Analysis and Conclusion

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

12

slide-16
SLIDE 16

Execution of Concurrent Programs

Basically, we want to implement a nondeterministic scheduler. Problem: We need to manage n PCs and n Stacks, all with one Stack! Thread 1

1 void

main1 () {

2

f();

3

exit (0);

4 } 5 6 void f() { 7

g();

8

return;

9 } 10 11 void g() { 12

return;

13 }

PC1 = 2 main1 Stack 1 Thread n

1 void

mainN () {

2

foo;

3

bar;

4

foobar;

5 }

PCn = 2 mainN Stack n

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

13

slide-17
SLIDE 17

Execution of Concurrent Programs

Basically, we want to implement a nondeterministic scheduler. Problem: We need to manage n PCs and n Stacks, all with one Stack! Thread 1

1 void

main1 () {

2

f();

3

exit (0);

4 } 5 6 void f() { 7

g();

8

return;

9 } 10 11 void g() { 12

return;

13 }

PC1 = 7 main1 f Stack 1 Thread n

1 void

mainN () {

2

foo;

3

bar;

4

foobar;

5 }

PCn = 2 mainN Stack n

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

13

slide-18
SLIDE 18

Execution of Concurrent Programs

Basically, we want to implement a nondeterministic scheduler. Problem: We need to manage n PCs and n Stacks, all with one Stack! Thread 1

1 void

main1 () {

2

f();

3

exit (0);

4 } 5 6 void f() { 7

g();

8

return;

9 } 10 11 void g() { 12

return;

13 }

PC1 = 12 main1 f g Stack 1 Thread n

1 void

mainN () {

2

foo;

3

bar;

4

foobar;

5 }

PCn = 2 mainN Stack n

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

13

slide-19
SLIDE 19

Execution of Concurrent Programs

Basically, we want to implement a nondeterministic scheduler. Problem: We need to manage n PCs and n Stacks, all with one Stack! Thread 1

1 void

main1 () {

2

f();

3

exit (0);

4 } 5 6 void f() { 7

g();

8

return;

9 } 10 11 void g() { 12

return;

13 }

PC1 = 8 main1 f Stack 1 Thread n

1 void

mainN () {

2

foo;

3

bar;

4

foobar;

5 }

PCn = 2 mainN Stack n

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

13

slide-20
SLIDE 20

Execution of Concurrent Programs

Basically, we want to implement a nondeterministic scheduler. Problem: We need to manage n PCs and n Stacks, all with one Stack! Thread 1

1 void

main1 () {

2

f();

3

exit (0);

4 } 5 6 void f() { 7

g();

8

return;

9 } 10 11 void g() { 12

return;

13 }

PC1 = 3 main1 Stack 1 Thread n

1 void

mainN () {

2

foo;

3

bar;

4

foobar;

5 }

PCn = 2 mainN Stack n

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

13

slide-21
SLIDE 21

Execution of Concurrent Programs

Basically, we want to implement a nondeterministic scheduler. Problem: We need to manage n PCs and n Stacks, all with one Stack! Thread 1

1 void

main1 () {

2

f();

3

exit (0);

4 } 5 6 void f() { 7

g();

8

return;

9 } 10 11 void g() { 12

return;

13 }

PC1 = 3 main1 Stack 1 Thread n

1 void

mainN () {

2

foo;

3

bar;

4

foobar;

5 }

PCn = 2 mainN Stack n Naive Solution: Store information in global variables. But: Sequential model checking is exponential in # global variables!

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

13

slide-22
SLIDE 22

Scheduling with (almost) no Global Variables

Idea: Think of Threads as Functions! At any point during execution we may nondeterministically Schedule a new thread by calling its starting function

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

14

slide-23
SLIDE 23

Scheduling with (almost) no Global Variables

Idea: Think of Threads as Functions! At any point during execution we may nondeterministically Schedule a new thread by calling its starting function thr1 1 → 1 → 1 →

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

14

slide-24
SLIDE 24

Scheduling with (almost) no Global Variables

Idea: Think of Threads as Functions! At any point during execution we may nondeterministically Schedule a new thread by calling its starting function thr1 thr3 1 → 1 → 1 → 3 → 3 →

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

14

slide-25
SLIDE 25

Scheduling with (almost) no Global Variables

Idea: Think of Threads as Functions! At any point during execution we may nondeterministically Schedule a new thread by calling its starting function Continue a thread already running by popping the current stack frame (return ;) thr1 1 → 1 → 1 → 3 → 3 → 1 →

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

14

slide-26
SLIDE 26

Scheduling with (almost) no Global Variables

Idea: Think of Threads as Functions! At any point during execution we may nondeterministically Schedule a new thread by calling its starting function Continue a thread already running by popping the current stack frame (return ;) thr1 thr2 1 → 1 → 1 → 3 → 3 → 1 → 2 →

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

14

slide-27
SLIDE 27

Scheduling with (almost) no Global Variables

Idea: Think of Threads as Functions! At any point during execution we may nondeterministically Schedule a new thread by calling its starting function Continue a thread already running by popping the current stack frame (return ;) thr1 1 → 1 → 1 → 3 → 3 → 1 → 2 → 1

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

14

slide-28
SLIDE 28

Scheduling with (almost) no Global Variables (2)

thr1 . . . thri Schedule new Thread Schedule

  • ld Thread
  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

15

slide-29
SLIDE 29

Example

Main Thread

Set ts = Set.init (); usb_driver driver; boolean is_running ; boolean is_in_use; void main () { driver = init (); is_running = true; is_in_use = false; async(thrA ); async(thrB ); }

Thread A

void thrA () { if(is_running ){ is_in_use = true; . . . is_in_use = false; } } CODE sched_nondet_nr_of_thrs (); if($) return ;~0@

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

16

slide-30
SLIDE 30

Example

Main Thread

Set ts = Set.init (); usb_driver driver; boolean is_running ; boolean is_in_use; void main () { driver = init (); is_running = true; is_in_use = false; async(thrA ); async(thrB ); }

Thread A

void thrA () { if(is_running ){ is_in_use = true; . . . is_in_use = false; } } CODE sched_nondet_nr_of_thrs (); if($) return ;~0@

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

16

slide-31
SLIDE 31

Example

Main Thread

Set ts = Set.init (); usb_driver driver; boolean is_running ; boolean is_in_use; void main () { CODE driver = init (); CODE is_running = true; CODE is_in_use = false; CODE ts.add(thrA ); CODE ts.add(thrA ); }

Thread A

void thrA () { CODE if(is_running ){ CODE is_in_use = true; . . . CODE is_in_use = false; } } CODE ≡ sched_nondet_nr_of_thrs (); if($) return;

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

17

slide-32
SLIDE 32

Example

Main Thread

Set ts = Set.init (); usb_driver driver; boolean is_running ; boolean is_in_use; void main () { CODE driver = init (); CODE is_running = true; CODE is_in_use = false; CODE ts.add(thrA ); CODE ts.add(thrA ); }

Thread A

void thrA () { CODE if(is_running ){ CODE is_in_use = true; . . . CODE is_in_use = false; } } CODE ≡ sched_nondet_nr_of_thrs (); if($) return;

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

17

slide-33
SLIDE 33

Example

Main Thread

Set ts = Set.init(k); usb_driver driver; boolean is_running ; boolean is_in_use; void main () { CODE driver = init (); CODE is_running = true; CODE is_in_use = false; CODE if(ts.size <k) ts.add(thrA ); else thrA (); CODE if(ts.size <k) ts.add(thrB ); else thrB (); }

Thread A

void thrA () { CODE if(is_running ){ CODE is_in_use = true; . . . CODE is_in_use = false; } } CODE ≡ sched_nondet_nr_of_thrs (); if($) return;

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

18

slide-34
SLIDE 34

Observations

The currently executed thread is always on top of the stack ⇒ the stack can grow without problems By exploiting the function concept, we can manage n PCs and n Stacks for free! We cannot simulate all possible executions: 1

1

− → 2

2

− → 1 3 − → 2 Between any two threads, we can simulate at most 2 interleavings k = ts.max is “turning knob” for the number of executions we can simulate

k = 0 : async(f ); f ();

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

19

slide-35
SLIDE 35

Nondeterministic Returns

. . . . . . g() h() Thread i Thread k

void g() { . . . x = h(); sched_nondet_nr_of_thrs (); . . . } void h() { . . . sched_nondet_nr_of_thrs (); if($) return; foo; . . . }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

20

slide-36
SLIDE 36

Nondeterministic Returns

. . . . . . g() Thread i Thread k

void g() { . . . x = h(); sched_nondet_nr_of_thrs (); . . . } void h() { . . . sched_nondet_nr_of_thrs (); if($) return; foo; . . . }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

20

slide-37
SLIDE 37

Nondeterministic Returns

. . . . . . g() h() Thread i Thread k

bool raise = false; void g() { . . . x = h(); if(raise) return; sched_nondet_nr_of_thrs (); . . . } void h() { . . . sched_nondet_nr_of_thrs (); if($) { raise = true; return; } foo; . . . }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

21

slide-38
SLIDE 38

Nondeterministic Returns

. . . . . . g() Thread i Thread k

bool raise = false; void g() { . . . x = h(); if(raise) return; sched_nondet_nr_of_thrs (); . . . } void h() { . . . sched_nondet_nr_of_thrs (); if($) { raise = true; return; } foo; . . . }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

21

slide-39
SLIDE 39

Nondeterministic Returns

. . . . . . Thread k

bool raise = false; void g() { . . . x = h(); if(raise) return; sched_nondet_nr_of_thrs (); . . . } void h() { . . . sched_nondet_nr_of_thrs (); if($) { raise = true; return; } foo; . . . }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

21

slide-40
SLIDE 40

Scheduling Function

void sched_nondet_nr_of_thrs () { var f ; while ( $ ) { i f ( t s . s ize >0) { f = t s . get ( ) ; f ( ) ; r a i s e = f a l s e ; } } }

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

22

slide-41
SLIDE 41

1

Motivation and Intuition behind KISS

2

The Transformation

3

Analysis and Conclusion

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

23

slide-42
SLIDE 42

Complexity

Sequential program with boolean variables: O(|C| · 2g+l)

|C| = size of the control flow graph g = number of global variables l = maximum number of local variables in scope at any time

Complexity of KISS

small blow up of |C| by constant factor added small constant # global variables ⇒ the complexity of using KISS on a concurrent program of a certain size is about the same as analyzing a sequential program of the same size (small constant factor)

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

24

slide-43
SLIDE 43

Conclusion

Pros

Low complexity, not exponential in # threads “Turning knob” ts .max ⇒ good scalability No false-positives Model checker only has to understand semantics of sequential programs Easy to implement

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

25

slide-44
SLIDE 44

Conclusion

Pros

Low complexity, not exponential in # threads “Turning knob” ts .max ⇒ good scalability No false-positives Model checker only has to understand semantics of sequential programs Easy to implement

Cons

Simulates executions with a maximum of 2 interleavings between any two threads May miss errors

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

25

slide-45
SLIDE 45

Thank you for listening!

Any Questions?

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

26

slide-46
SLIDE 46

Bibliography

[1] Quadeer, Shaz ; Wu, Dinghao: KISS: Keep it simple and sequential. In: ACM SIGPLAN Conference on Programming Language Design and Implementation (2004) [2] Ramalingam, G.: Context-sensitive synchronization-sensitive analysis is undecidable. In: ACM Transactions on Programming Languages and Systems 22 (2000), March, Nr. 2, S. 413–430 [3] Reps, T. ; Horwitz, S. ; Sagiv, M.: Precise interprocedural dataflow analysis via graph reachability. In: Proceedings of the 22nd ACM SIGPLAN-SIGACT Symposium on Principles of Software Engineering (2003), S. 267–276 [4] Sharir, M. ; Pnueli, A.: Two approaches to interprocedural data flow analysis. In: Program Flow Analysis: Theory and Applications (1981), S. 189–233

  • S. Smolka (TUM)

KISS: Keep it Simple and Sequential

  • 17. Juli 2012

27