Presentation is loading. Please wait.

Presentation is loading. Please wait.

Deadlock Detection Nov 26, 2012 CS 8803 FPL 1. Part I Static Deadlock Detection Reference: Effective Static Deadlock Detection [ICSE’09]

Similar presentations


Presentation on theme: "Deadlock Detection Nov 26, 2012 CS 8803 FPL 1. Part I Static Deadlock Detection Reference: Effective Static Deadlock Detection [ICSE’09]"— Presentation transcript:

1 Deadlock Detection Nov 26, 2012 CS 8803 FPL 1

2 Part I Static Deadlock Detection Reference: Effective Static Deadlock Detection [ICSE’09]

3 An unintended condition in a shared-memory, multi- threaded program in which: –a set of threads blocks forever –because each thread in the set waits to acquire a lock being held by another thread in the set This work: ignore other causes (e.g., wait/notify) Example // Thread t1 sync (l1) { sync (l2) { … } // Thread t2 sync (l2) { sync (l1) { … } l1 t1 l2 t2 What is a Deadlock?

4 Today ’ s concurrent programs are rife with deadlocks –6,500/198,000 (~ 3%) of bug reports in Sun ’ s bug database at http://bugs.sun.com are deadlocks Deadlocks are difficult to detect –Usually triggered non-deterministically, on specific thread schedules –Fail-stop behavior not guaranteed (some threads may be deadlocked while others continue to run) Fixing other concurrency bugs like races can introduce new deadlocks –Our past experience with reporting races: developers often ask for deadlock checker Motivation

5 Based on finding cycles in program’s dynamic or static lock order graph Dynamic approaches –Inherently unsound –Inapplicable to open programs –Ineffective without sufficient test input data Static approaches –Type systems (e.g., Boyapati-Lee-Rinard OOPSLA’02) Annotation burden often significant –Model checking (e.g., SPIN) Does not currently scale beyond few KLOC –Dataflow analysis (e.g., Engler & Ashcraft SOSP’03; Williams-Thies-Ernst ECOOP’05) Scalable but highly imprecise l1 t1 l2 t2 Previous Work

6 Deadlock freedom is a complex property –can t1,t2 denote different threads? –can l1,l4 denote same lock? –can t1 acquire locks l1->l2? –some more … l = abstract lock acq. t = abstract thread t1 l1 l2 t1 l1 l2 t2 l4 l3 t2 Challenges to Static Deadlock Detection

7 Deadlock freedom is a complex property –can t1,t2 denote different threads? –can l1,l4 denote same lock? –can t1 acquire locks l1->l2? –some more … t1 l1 l2 t1 l1 l2 t2 l4 l3 t2 Our Rationale

8 t1 l1 l2 t1 l1 l2 t2 l4 l3 t2 Existing static deadlock checkers cannot check all conditions simultaneously and effectively But each condition can be checked separately and effectively using existing static analyses Our Rationale

9 Consider all candidate deadlocks in closed program Check each of six necessary conditions for each candidate to be a deadlock Report candidates that satisfy all six conditions Note: Finds only deadlocks involving 2 threads/locks –Deadlocks involving > 2 threads/locks rare in practice l1 l2 t1 l4 l3 t2 t1 l1 l2 t2... Our Approach may-reach(t1,l1,l2)? may-alias(l1,l4)?

10 class LogManager { static LogManager manager = new LogManager(); 155: Hashtable loggers = new Hashtable(); 280: sync boolean addLogger(Logger l) { String name = l.getName(); if (!loggers.put(name, l)) return false; // ensure l’s parents are instantiated for (...) { String pname =...; 314: Logger.getLogger(pname); } return true; } 420: sync Logger getLogger(String name) { return (Logger) loggers.get(name); } } class Logger { 226: static sync Logger getLogger(String name) { LogManager lm = LogManager.manager; 228: Logger l = lm.getLogger(name); if (l == null) { l = new Logger(...); 231: lm.addLogger(l); } return l; } } class Harness { static void main(String[] args) { 11: new Thread() { void run() { 13: Logger.getLogger(...); }}.start(); 16: new Thread() { void run() { 18: LogManager.manager.addLogger(...); }}.start(); } } t1 t2 l4 l2 l3 l1 Example: jdk1.4 java.util.logging

11 *** Stack trace of thread : LogManager.addLogger (LogManager.java:280) - this allocated at - waiting to lock { } Logger.getLogger (Logger.java:231) - holds lock { } Harness$1.run (Harness.java:13) *** Stack trace of thread : Logger.getLogger (Logger.java:226) - waiting to lock { } LogManager.addLogger (LogManager.java:314) - this allocated at - holds lock { } Harness$2.run (Harness.java:18) Example Deadlock Report

12 Six necessary conditions identified experimentally Checked using four incomplete but sound whole-program static analyses 1.Reachable 2.Aliasing 3.Escaping 4.Parallel 5.Non-reentrant 6.Non-guarded 1.Call-graph analysis 2.May-alias analysis 3.Thread-escape analysis 4.May-happen-in-parallel analysis Relatively language independent Incomplete but sound checks } } Widely-used Java locking idioms Incomplete and unsound checks - sound needs must-alias analysis Our Approach

13 Property: In some execution: –can a thread abstracted by t1 reach l1 –and after acquiring lock at l1, proceed to reach l2 while holding that lock? –and similarly for t2, l3, l4 Solution: Use call-graph analysis –k-object-sensitive [Milanova-Rountev-Ryder ISSTA ’ 03] t1 l1 l2 t1 l1 l2 l4 l3 t2 l4 l3 t2 Condition 1: Reachable

14 class LogManager { static LogManager manager = new LogManager(); 155: Hashtable loggers = new Hashtable(); 280: sync boolean addLogger(Logger l) { String name = l.getName(); if (!loggers.put(name, l)) return false; // ensure l’s parents are instantiated for (...) { String pname =...; 314: Logger.getLogger(pname); } return true; } 420: sync Logger getLogger(String name) { return (Logger) loggers.get(name); } class Logger { 226: static sync Logger getLogger(String name) { LogManager lm = LogManager.manager; 228: Logger l = lm.getLogger(name); if (l == null) { l = new Logger(...); 231: lm.addLogger(l); } return l; } class Harness { static void main(String[] args) { 11: new Thread() { void run() { 13: Logger.getLogger(...); }}.start(); 16: new Thread() { void run() { 18: LogManager.manager.addLogger(...); }}.start(); } t1 t2 l4 l2 l3 l1 Example: jdk1.4 java.util.logging

15 Property: In some execution: –can a lock acquired at l1 be the same as a lock acquired at l4? –and similarly for l2, l3 Solution: Use may-alias analysis –k-object-sensitive [Milanova-Rountev-Ryder ISSTA ’ 03] l1 l2 t1 l1 l2 l4 l3 t2 Condition 2: Aliasing

16 class LogManager { static LogManager manager = new LogManager(); 155: Hashtable loggers = new Hashtable(); 280: sync boolean addLogger(Logger l) { String name = l.getName(); if (!loggers.put(name, l)) return false; // ensure l’s parents are instantiated for (...) { String pname =...; 314: Logger.getLogger(pname); } return true; } 420: sync Logger getLogger(String name) { return (Logger) loggers.get(name); } class Logger { 226: static sync Logger getLogger(String name) { LogManager lm = LogManager.manager; 228: Logger l = lm.getLogger(name); if (l == null) { l = new Logger(...); 231: lm.addLogger(l); } return l; } class Harness { static void main(String[] args) { 11: new Thread() { void run() { 13: Logger.getLogger(...); }}.start(); 16: new Thread() { void run() { 18: LogManager.manager.addLogger(...); }}.start(); } t1 t2 l4 l2 l3 l1 Example: jdk1.4 java.util.logging

17 Property: In some execution: –can a lock acquired at l1 be thread-shared? –and similarly for each of l2, l3, l4 Solution: Use thread-escape analysis l1 l2 t1 l1 l2 l4 l3 l4 l3 t2 Condition 3: Escaping

18 class LogManager { static LogManager manager = new LogManager(); 155: Hashtable loggers = new Hashtable(); 280: sync boolean addLogger(Logger l) { String name = l.getName(); if (!loggers.put(name, l)) return false; // ensure l’s parents are instantiated for (...) { String pname =...; 314: Logger.getLogger(pname); } return true; } 420: sync Logger getLogger(String name) { return (Logger) loggers.get(name); } class Logger { 226: static sync Logger getLogger(String name) { LogManager lm = LogManager.manager; 228: Logger l = lm.getLogger(name); if (l == null) { l = new Logger(...); 231: lm.addLogger(l); } return l; } class Harness { static void main(String[] args) { 11: new Thread() { void run() { 13: Logger.getLogger(...); }}.start(); 16: new Thread() { void run() { 18: LogManager.manager.addLogger(...); }}.start(); } t1 t2 l4 l2 l3 l1 Example: jdk1.4 java.util.logging

19 Property: In some execution: –can different threads abstracted by t1 and t2 –simultaneously reach l2 and l4? Solution: Use may-happen-in-parallel analysis –Does not model full happens-before relation –Models only thread fork construct –Other conditions model other constructs ≠ t1 l1 l2 t1 l1 l2 l4 l3 t2 l4 l3 t2 Condition 4: Parallel

20 class LogManager { static LogManager manager = new LogManager(); 155: Hashtable loggers = new Hashtable(); 280: sync boolean addLogger(Logger l) { String name = l.getName(); if (!loggers.put(name, l)) return false; // ensure l’s parents are instantiated for (...) { String pname =...; 314: Logger.getLogger(pname); } return true; } 420: sync Logger getLogger(String name) { return (Logger) loggers.get(name); } class Logger { 226: static sync Logger getLogger(String name) { LogManager lm = LogManager.manager; 228: Logger l = lm.getLogger(name); if (l == null) { l = new Logger(...); 231: lm.addLogger(l); } return l; } class Harness { static void main(String[] args) { 11: new Thread() { void run() { 13: Logger.getLogger(...); }}.start(); 16: new Thread() { void run() { 18: LogManager.manager.addLogger(...); }}.start(); } t1 t2 l4 l2 l3 l1 Example: jdk1.4 java.util.logging

21 BenchmarkLOCClassesMethodsSyncsTime moldyn31,91763238124m48s montecarlo157,09850934471907m53s raytracer32,57673287164m51s tsp154,28849533351897m48s sor32,2475720854m48s hedc160,071530355220421m15s weblech184,098656462023832m02s jspider159,494557359520515m34s jigsaw154,584497334618415m23s ftp180,904642438325235m55s dbcp168,018536360222716m04s cache4j34,6037221874m43s logging167,92356338522589m01s collections38,961124712555m42s Benchmarks

22 BenchmarkDeadlocks (0-cfa) Deadlocks (k-obj.) Lock type pairs (total) Lock type pairs (real) moldyn0000 montecarlo0000 raytracer0000 tsp0000 sor0000 hedc7,5522,3582219 weblech4,9697942219 jspider725410 jigsaw231833 ftp16,2593,0203324 dbcp3201643 cache4j0000 logging4,134 9894 collections598 16 Experimental Results

23 Individual Analysis Contributions

24 Novel approach to static deadlock detection for Java –Checks six necessary conditions for a deadlock –Uses four off-the-shelf static analyses Neither sound nor complete, but effective in practice –Applied to suite of 14 multi-threaded Java programs comprising over 1.5 MLOC –Found all known deadlocks as well as previously unknown ones, with few false alarms Conclusion

25 Part II Dynamic Deadlock Detection Reference: An Effective Dynamic Analysis Technique for Detecting Generalized Deadlocks [FSE’10]

26 Motivation Most previous deadlock detection work has focused on resource deadlocks Example // Thread T1 // Thread T2 sync(L1) { sync(L2) { sync(L2) { sync(L1) { …. …. } } L1 T1 L2 T2

27 Motivation Other kinds of deadlocks, e.g. communication deadlocks, are equally notorious Example // Thread T1 // Thread T2 if (!b) { b = true; sync(L) { sync(L) { L.wait(); L.notify(); } } } T2T1 if(!b) wait L b = true notify L b is initially false

28 Goal Build a dynamic analysis based tool that: –detects communication deadlocks –scales to large programs –has low false positive rate

29 Our Initial Effort Take cue from existing dynamic analyses for other concurrency errors Existing dynamic analyses check for violation of a programming idiom –Races: every shared variable is consistently protected by a lock –Resource deadlocks: no cycle in lock ordering graph –Atomicity violations: atomic blocks should have the pattern (R+B)*N(L+B)*

30 Our Initial Effort What programming idiom should we check for communication deadlocks?

31 Our Initial Effort Recommended usage of condition variables // Thread T1 // Thread T2 sync (L) { sync (L) { while (!cond) cond = true; L.wait(); L.notifyAll(); assert (cond == true); } }

32 An Example Recommended usage of condition variables // Thread T1 // Thread T2 sync (L) { sync (L) { while (list.isEmpty()) list.add(...); L.wait(); L.notifyAll(); … = list.remove(); } }

33 Violation of Idiom as Deadlock Example // Thread T1 // Thread T2 if (!b) b = true; sync (L) L.notifyAll(); sync (L) L.wait(); Must use while, not if Accesses to b must be inside sync

34 Satisfaction of Idiom as Deadlock Example // Thread T1 // Thread T2 sync (L1) sync (L2) while (!b) L2.wait(); sync (L1) sync (L2) L2.notifyAll(); => Recommended usage pattern (or idiom) based checking does not work No violation of idiom, but still deadlocks!

35 Revisiting Existing Analyses Relax the dependencies between relevant events from different threads –verify all possible event orderings for errors –use data structures to check idioms (vector clocks, lock- graphs etc.) to implicitly verify all event orderings

36 Revisiting Existing Analyses Programming idiom-based checking does not work for communication deadlocks Nevertheless, we can explicitly verify all orderings of relevant events for deadlocks

37 Trace Program // Thread T1 // Thread T2 if (!b) { b = true; sync (L) { sync (L) { L.wait (); L.notify (); } } } b is initially false lock L wait L unlock L lock L unlock L notify L T1T2

38 Trace Program lock L wait L unlock L lock L unlock L notify L T1T2 Thread T1 { lock L; wait L; unlock L; } Thread T2 { lock L; notify L; unlock L; }

39 Trace Program Thread T1 {Thread T2 { lock L; lock L; wait L; || notify L; unlock L; } lock L wait L unlock L lock L unlock L notify L T1T2

40 Trace Program Built out of only a subset of events –usually much smaller than the original program Throws away a lot of dependencies between threads –could give false positives –but increases coverage

41 // Thread T1 // Thread T2 if (!b) { b = true; sync (L) { sync (L) { L.wait (); L.notify (); } } } b is initially false lock L wait L unlock L lock L unlock L notify L T1T2 if (!b) b = true Trace Program: Add Dependencies

42 lock L wait L unlock L lock L unlock L notify L T1T2 if (!b) b = true Thread T1 { if (!b) { lock L; wait L; unlock L; } Thread T2 { b = true; lock L; notify L; unlock L; } Trace Program: Add Dependencies

43 Trace Program: Add Predictivity Use static analysis to add to the predictive power of the trace program // Thread T1 // Thread T2 @ !b => L.wait() if (!b) { b = true; sync (L) { sync (L) { L.wait (); L.notify (); } } } b is initially false Thread T1 { if (!b) { lock L; wait L; unlock L; }

44 Effective for concurrency errors that cannot be detected using a programming idiom –communication deadlocks, deadlocks due of exceptions, … // Thread T1 // Thread T2 while (!b) { try { sync (L) { foo(); L.wait(); b = true; } sync (L) { L.notify(); } } } catch (Exception e) {…} b is initially false can throw an exception Trace Program: Other Errors

45 Implemented for deadlock detection –both communication and resource deadlocks Built a prototype tool for Java called CHECKMATE Applied to several Java libraries and applications –log4j, pool, felix, lucene, jgroups, jruby.... Found both previously known and unknown deadlocks (17 in total) Implementation and Evaluation

46 Conclusion CHECKMATE is a novel dynamic analysis for finding deadlocks –both resource and communication deadlocks Effective on several real-world Java benchmarks Trace program based approach is generic –can be applied to other errors, e.g. deadlocks because of exceptions

47 Did Not Cover Today … Deadlock Detection in Message-Passing Programs –must model many variants of message sends/receives Dynamic Deadlock Avoidance –unique to deadlock errors (cannot, e.g., “avoid” buffer overruns) –see Dimmunix OSDI’08 paper (http://dimmunix.epfl.ch/) Dynamic Deadlock Detection by Controlling Thread Schedules –CHESS (http://research.microsoft.com/en-us/projects/chess/) –CalFuzzer (http://srl.cs.berkeley.edu/~ksen/calfuzzer/) Type-based Deadlock Detection –statically check lock-order graph (see OOPSLA’02 paper)


Download ppt "Deadlock Detection Nov 26, 2012 CS 8803 FPL 1. Part I Static Deadlock Detection Reference: Effective Static Deadlock Detection [ICSE’09]"

Similar presentations


Ads by Google