490 likes | 675 Views
RADAR: Dataflow Analysis for Concurrent Programs using Datarace Detection. Ravi Chugh, Jan Voung , Ranjit Jhala, Sorin Lerner {rchugh, jvoung, jhala, lerner} @ cs.ucsd.edu UC San Diego. Studying Concurrency is Important. Studying Concurrency is Important. Studying Concurrency is Important.
E N D
RADAR: Dataflow Analysis for Concurrent Programs using Datarace Detection Ravi Chugh, Jan Voung, Ranjit Jhala, Sorin Lerner {rchugh, jvoung, jhala, lerner} @ cs.ucsd.edu UC San Diego
Studying Concurrency is Important • A “counting argument” • > wget http://pldi2008.cs.ucr.edu/program_schedule.html • > grep –i “concurr” program_schedule.html | wc –l • 6
All Jokes Aside… Architectural Trends Pressing Issue Devilish Bugs
Our Approach Leverage sequential work Sequential Dataflow Analysis Concurrent Dataflow Analysis
Sequential Reasoning is Incorrect p = new_or_die(); p != null x = compute(); p != null *p = x; if (p != null) { use(p); p = null; }
Sequential Optimization is Incorrect flag = 0; while (flag == 0) { /* spin */ } use(g); Constant propagation would be incorrect g = compute(); flag = 1; 0 • Compilers forced to be conservative • Optimization opportunities missed
Our Approach Concurrent Dataflow Analysis RADAR Sequential Dataflow Analysis
Our Approach Sequential Dataflow Analysis Concurrent Dataflow Analysis RADAR Concurrency Analysis Race Detector
Modular Framework Sequential Non-Null Analysis Sequential Constant Analysis Sequential Dataflow Analysis Concurrent Dataflow Analysis Concurrent Non-Null Analysis Concurrent Constant Analysis RADAR Race Detector
Modular Framework Sequential Constant Analysis RADAR Concurrent Constant Analysis Race Detector precise scalable
RADAR: Results • Concurrent non-null analysis • Scales to: • Apache (~130 KLOC) • OpenSSL (~210 KLOC) • subset of Linux kernel (~830 KLOC)
Example with Locks lock(l); p = new_or_die(); x = compute(); *p = x; unlock(l); lock(l); if (p != null) { use(p); p = null; } unlock(l);
Can this be Optimized? lock(l); p = new_or_die(); unlock(l); x = compute(); lock(l); *p = x; unlock(l); lock(l); if (p != null) { use(p); p = null; } unlock(l);
Optimized Version is Race-free lock(l); p = new_or_die(); unlock(l); x = compute(); lock(l); *p = x; unlock(l); lock(l); if (p != null) { use(p); p = null; } unlock(l);
Oops… lock(l); p = new_or_die(); unlock(l); x = compute(); lock(l); *p = x; unlock(l); lock(l); if (p != null) { use(p); p = null; } unlock(l);
Sequential Non-Null Analysis lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; p != null unlock(l); lock(l); if (p != null) { p != null use(p); p != null p = null; p != null } unlock(l);
RADAR on Example lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; p != null unlock(l); lock(l); if (p != null) { p != null use(p); p != null p = null; p != null } unlock(l);
RADAR on Example lock(l); p = new_or_die(); p != null unlock(l); x = compute(); lock(l); *p = x; unlock(l); Can fact be invalidated by concurrent thread? Can p be written by a concurrent thread?
RADAR on Example lock(l); p = new_or_die(); p != null unlock(l); x = compute(); lock(l); *p = x; unlock(l); Race Detector No Race pseudo-read(p) Race Can p be written by a concurrent thread?
RADAR on Example lock(l); p = new_or_die(); p != null unlock(l); x = compute(); lock(l); *p = x; unlock(l); Race Detector No Race pseudo-read(p) Race Can p be written by a concurrent thread?
RADAR on Example lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); lock(l); *p = x; unlock(l); Race Detector No Race Race pseudo-read(p)
RADAR on Example lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; unlock(l); UNSAFE
RADAR on Safe Example lock(l); p = new_or_die(); p != null x = compute(); *p = x; unlock(l); Race Detector No Race pseudo-read(p) Race
RADAR on Safe Example lock(l); p = new_or_die(); p != null x = compute(); p != null *p = x; unlock(l); Race Detector No Race Race pseudo-read(p)
RADAR on Safe Example lock(l); p = new_or_die(); p != null x = compute(); p != null *p = x; unlock(l); SAFE
More on RADAR • Round trip queries to race detector • Inter-procedural analysis
(1) Round-trip Queries lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; p != null unlock(l); Race Detector No Race pseudo-read(p) Race Possible Race pseudo-read(p) Allow sequential analysis to run Get superset of (concurrent) facts
(1) Round-trip Queries lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; p != null unlock(l); Insert all pseudo-reads at once pseudo-read(p) Race Detector pseudo-read(p) pseudo-read(p) pseudo-read(p) Send whole program to race detector pseudo-read(p)
(1) Round-trip Queries lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; p != null unlock(l); pseudo-read(p) Get results back from Race Detector pseudo-read(p) pseudo-read(p) pseudo-read(p) pseudo-read(p)
(1) Round-trip Queries lock(l); p = new_or_die(); unlock(l); x = compute(); lock(l); *p = x; unlock(l); pseudo-read(p) Get results back from Race Detector pseudo-read(p) pseudo-read(p) Rerun analysis using race results pseudo-read(p) pseudo-read(p)
(1) Round-trip Queries lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); lock(l); *p = x; unlock(l); Rerun analysis using race results
(1) Round-trip Queries lock(l); p = new_or_die(); p != null unlock(l); p != null x = compute(); p != null lock(l); p != null *p = x; unlock(l); UNSAFE
(2) Handling Procedures void foo() { if (*) { unlock(l); compute(); lock(l); } } lock(l); if (p != null) { foo(); *p = 10; } unlock(l); lock(l); p = null; unlock(l); Unlock in foo allows interference Want to summarize effect of calling foo
(2) Handling Procedures void foo() { if (*) { unlock(l); compute(); lock(l); } } lock(l); if (p != null) { foo(); *p = 10; } unlock(l); lock(l); p = null; unlock(l);
(2) Handling Procedures lock(l); if (p != null) { foo(); *p = 10; } unlock(l); pseudo-unlock(l); pseudo-read(p); pseudo-lock(l); • In the caller, RADAR inserts: • pseudo-unlock for every unlock in foo • pseudo-reads
Evaluation • Is RADAR scalable? • Is RADAR precise? • Where can we do better?
Experiments: Benchmarks • Apache 2.2.6 (130 KLOC) • worker threads + modules (e.g., caches) • OpenSSL 0.9.8g (210 KLOC) • model a multi-threaded client • Linux 2.6.15 (830 KLOC) • subset from RELAY experiments
Sequential Race Detector + = Non-Null Escapes ⇒ race Conservative Non-Null Non-Null Optimistic (sequential) Never race Non-Null
GAP Sequential Race Detector + = Non-Null Escapes ⇒ race Conservative Shared ⇒ race Non-Null No locks ⇒race Non-Null Optimistic (sequential) Never race Non-Null
Sequential Race Detector + = Non-Null Escapes ⇒ race Conservative Shared ⇒ race Non-Null No locks ⇒race Non-Null Optimistic (sequential) Never race Non-Null
Sources of Imprecision • Alias analysis • affects sequential dataflow and race detection • Lockset-based race analysis • ignores fork, join, condition variables • RADAR framework • pseudo-read (for non-null fact) races with • “x = NonNullAddress;”
Related Work • Programming-model-based approaches • [Knoop et al 96], [Grunwald et al 93], … • par-begin / par-end • handles introduction of facts between threads • Thread-modular • [Owicki et al 76], [Jones 83], [Flanagan et al 03], … • more precise (use environment assumption) • inference not as scalable
Conclusion Sequential Dataflow Analysis RADAR Concurrent Dataflow Analysis Race Detector precise scalable
What is filtered for non-null? if (a->f != null) { b->f = null; deref(a->f); //filter if warned deref(b->f); //don’t filter }