1 / 54

Java Race Finder Checking Java Programs for Sequential Consistency

Java Race Finder Checking Java Programs for Sequential Consistency. Tuba Yavuz-Kahveci Fall 2013. Outline. The Problem: Getting Multithreaded Java Programs Right Java Memory Model Our Solution: Java Race Finder What is model checking anyway? Representing Happens-before

yasuo
Download Presentation

Java Race Finder Checking Java Programs for Sequential Consistency

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Java Race FinderChecking Java Programs for Sequential Consistency Tuba Yavuz-Kahveci Fall 2013

  2. Outline • The Problem: Getting Multithreaded Java Programs Right • Java Memory Model • Our Solution: Java Race Finder • What is model checking anyway? • Representing Happens-before • Heuristic-based Search • Code Modification Suggestions

  3. What is Sequential Consistency? • Program statements are executed according to program order • Each thread’s statements are executed according to the program order in that thread’s code • Write atomicity • Each read operation on a variable sees the most recent write operation on that variable

  4. What is a Memory Model? • Constrains the behavior of memory operations • What value can a read operation see? • Example memory models • Sequential Consistency • Easy to understand • Relaxed Consistency Models • Relaxation of • Program order • Write atomicity

  5. Who Should Care? • Programmers • Understanding how to achieve sequential consistency, if possible • Reasoning about correctness • Compiler writers • Optimizing code within the restrictions of the memory model

  6. Problem: Getting Multi-threaded Java Programs Right • Important Questions Any Java Programmer Should Ask • Is my multithreaded program correctly synchronized? • Beware!!! Sequential consistency is not guaranteed for incorrectly synchronized Java programs! • If my multithreaded program is not correctly synchronized, how can I fix it? • If my multithreaded program is not correctly synchronized for a good reason, should I still be worried? • Automated tool support is needed to answer these nontrivial questions

  7. An Example: Peterson’s Mutual Exclusion Algorithm - Version 1 Initialization: flag[0] = flag[1] = turn = shared = 0 /* all non-volatile */ Thread 2 Thread 1 s1: flag[0] = 1; s6: flag[1] = 1; s2: turn = 1; s7: turn = 0; s3: while (flag[1] == 1 && turn == 1) { /*spin*/} s8: while (flag[0] == 1 && turn == 0) { /*spin*/} s4: shared++; /* critical section */ s9: shared++; /* critical section */ s5: flag[0] = 0; s10: flag[0] = 0;

  8. Outline • The Problem: Getting Multithreaded Java Programs Right • Java Memory Model • Our Solution: Java Race Finder • What is model checking anyway? • Representing Happens-before • Heuristic-based Search • Code Modification Suggestions

  9. What is Java Memory Model (JMM)? • A relaxed memory model • Sequential consistency is guaranteed only for correctly synchronized programs • For programs without data races • Incorrectly synchronized programs can show extra behavior that is not sequentially consistent • Still subject to some safety rules

  10. Synchronization Rules in Java • Some synchronization actions and their relationship in Java: • Unlocking a monitor lock synchronizes with locking that monitor lock. • Writing a volatile variable synchronizes with reading of that variable. • Starting a thread synchronizes with the first action of that thread. • Final action in a thread synchronizes withany action of a thread that detects termination of that thread. • Initialization of a field synchronizes with the first access to the field in every thread. • In general a release actionsynchronizes witha matching acquire action.

  11. Happens-Before Relation • An action a1happens-before action a2, a1 ≤hb a2, due to one of the following: • a1 comes before a2 according to program order: a1 ≤po a2. • a1 synchronizes with a2: a1 ≤swa2. • a1 happens-before a’ that happens-before a2: Exists a’. a1 ≤hba’ and a’ ≤hba2 (transitivity). • Happens-before, ≤hb= ( ≤po U ≤sw)+, is a partial-order on all actions in an execution.

  12. Happens-before Consistency • A read operation r can see results of a write operation w provided that: • r does not happen-before w: not (r≤hbw). • There is no intervening write operation: not (exists w’. w r ≤hbw’ ≤hbr).

  13. Anatomy of a Data Race • Definition: If two actions a1 and a2 from different threads access the same memory location loc,the actions are not ordered by happens-before and if one of the actions is a write, then there is a data race on loc. • Example: Initialization: boolean done = false; /* non-volatile */ ≤hb ≤hb Thread 1 Thread 2 result = compute(); ≤hb Race on done!!! if (done) done = true; ≤hb // use result

  14. A Simple Fix • A write to a volatile variable synchronizes with a read of that variable. • Example: Initialization: volatileboolean done = false; ≤hb ≤hb Thread 1 Thread 2 result = compute(); ≤hb ≤hb ≤hb ≤hb if (done) done = true; ≤hb Not in a race // use result

  15. Outline • The Problem: Getting Multithreaded Java Programs Right • Java Memory Model • Our Solution: Java Race Finder • What is model checking anyway? • Representing Happens-before • Heuristic-based Search • Code Modification Suggestions

  16. Our Solutions/Contributions • Is my multi-threaded program correctly synchronized? Kim K., Yavuz-Kahveci T., Sanders B.PreciseData Race detection in Relaxed Memory Model using Heuristic based Model Checking [ASE Conf. 2009] • If my multi-threaded program is not correctly synchronized, how can I fix it? Kim K., Yavuz-Kahveci T., Sanders B. JRF-E: Using Model Checking to give Advice on Eliminating Memory Model-related Bugs [ASE Conf. 2010, ASE Journal 2012] • If my program is not correctly synchronized for a good reason, should I still be worried? Jin H., Yavuz-Kahveci T., Sanders B. Java Path Relaxer: Extending JPF for JMM-aware model checking [JPF Workshop] Jin H., Yavuz-Kahveci T., Sanders B. Java Memory Model-Aware Model Checking [TACAS 2012]

  17. Outline • The Problem: Getting Multithreaded Java Programs Right • Java Memory Model • Our Solution: Java Race Finder • What is model checking anyway? • Representing Happens-before • Heuristic-based Search • Code Modification Suggestions

  18. State/Snapshot of a Running Java Program JAVA VIRTUAL MACHINE Values of Static Fields Bytecode for the Java program Heap (objects) Thread states

  19. Model Checking Java Programs Values of Static Fields Heap (objects) Thread states Main Thread Thread1 Thread2 Thread3 … Main Thread Thread2 Thread1 Thread3 … Main Thread Thread3 Thread2 Thread1 …

  20. Model Checking for Sequential Consistency Multi-threaded Java application yes Java Race Finder (JRF) Java Path Finder (JPF) Data Race? no • a model-checker for Java • programs • checks for general • correctness properties • assumes sequential • consistency • explores all possible • thread interleaving • extends JPF’s state • representation to detect • data races

  21. Our Approach for Detecting Data Races Algorithm: foreach execution path EPj=<a1, a2, …, an> of program Pdo initialize happens-before relation foreach action ai, i= 1 to n, do let loc be the memory location aiaccesses if (it issafe (without a data race) for ai to access loc) generate DATA RACE error execute ai update happens-before relation

  22. Representing Happens-Before • We define an h-function that captures the happens-before relation in an implicit way. • h: SyncAddr U Thread -> 2Addr . • SyncAddr: Volatile variables and locks • Addr: Non-volatile variables • Is it safe for aj of thread ti to access loc? • does h(ti ) contain loc? • Which variables can be safely accessed if acquire on s (with a matching release on s) is executed? • h(s).

  23. The h-function • Initialization: • At the beginning there is only the main thread: • h0 = λz.if z = main then static(P) else φ • Update: • Executing an action updates the h-function: • action(t, x) h = h’ • h: h-function before executing action • t: the thread the action belongs to • x: synchronization variable (volatile or a lock) • h’: the updated h function

  24. Updating the h-function

  25. Action Semantics • Variables that can be safely accessed from thread t copied to the set for synchronization variable x release(t, x)h = h[x →h(t)∪h(x)] • Variables in the set of synchronization variable x will now be safely accessed by thread t acquire(t, x)h = h[t →h(t)∪h(x)] • Only thread t which changed x can safely access it. invalidate(t, x) h = λz. if (t = z) then h(z) else h(z)\{x} • The non-volatile fields of the newly created object can be safely accessed by the thread who created it. The volatile fields are initialized to refer to empty sets. new(t, fields, volatiles)h =λz. if (t = z) then h(t) ∪ fields else if (z ∈ volatiles) then{} else h(z)

  26. Implementation of the h-function

  27. How JRF extends JPF

  28. Test Programs

  29. Time Overhead of JRF

  30. Space Overhead of JRF

  31. Outline • The Problem: Getting Multithreaded Java Programs Right • Java Memory Model • Our Solution: Java Race Finder • What is model checking anyway? • Representing Happens-before • Heuristic-based Search • Code Modification Suggestions

  32. Finding the data race quickly initial state State space of a program race race race Each path from initial state to a leaf state represents a separate execution.

  33. Finding the data race using DFS initial state State space of a program DFS counter-example race race race Each path from initial state to a leaf state represents a separate execution.

  34. Finding the data race using BFS initial state State space of a program BFS counter-example race race race Each path from initial state to a leaf state represents a separate execution.

  35. Heuristic-Based Data Race Search • Our goal is to reach a state that has a data race as quick as possible. • Assign a traversal priority to each program state based on how close it may be to a racy state. • Writes-First (WF): Prefer write statements to read statements • Watch-Written (WW): Prefer access to memory locations recently written by another thread • Avoid Release/Acquire (ARA): Avoid scheduling threads that perform proper synchronization. • Acquire-First (AF): Prefer acquire operations that do not have a matching release operation.

  36. An Example: Peterson’s Mutual Exclusion Algorithm - Version 1 Initialization: flag[0] = flag[1] = turn = shared = 0 /* all non-volatile */ Thread 2 Thread 1 s1: flag[0] = 1; s6: flag[1] = 1; s2: turn = 1; s7: turn = 0; s3: while (flag[1] == 1 && turn == 1) { /*spin*/} s8: while (flag[0] == 1 && turn == 0) { /*spin*/} s4: shared++; /* critical section */ s9: shared++; /* critical section */ s5: flag[0] = 0; s10: flag[0] = 0;

  37. DFS vs Heuristic Search Thread 1 Heuristic Search Path DFS Search Path Thread 1 s1: flag[0] = 1; s1: flag[0] = 1; s2: turn = 1; s2: turn = 1; s3: while (flag[1] == 1 && turn == 1) { /*spin*/} Thread 2 s4: shared++; /* critical section */ s6: flag[1] = 1; s5: flag[0] = 0; s7: turn = 0; Thread 2 Race! turn not in h(thread2)! s6: flag[1] = 1; s7: turn = 0;

  38. Experimental Results: Heuristic Search *: JPF ran out of memory

  39. Outline • The Problem: Getting Multithreaded Java Programs Right • Java Memory Model • Our Solution: Java Race Finder • What is model checking anyway? • Representing Happens-before • Heuristic-based Search • Code Modification Suggestions

  40. What went wrong? Thread 1 s1: flag[0] = 1; source statement s2: turn = 1; removes turn from h(thread2) Thread 2 s6: flag[1] = 1; manifest statement s7: turn = 0; accesses turn when turn is not in h(thread2)

  41. How to fix it? • Data races are due to absence of happens-before relationship • Suggest code modifications that will create happens-before relationship between the source and manifest statements • Change the variable to volatile • Change the array to an atomic array • Move the source statement to make use of existing happens-before relationships due to transitivity • Perform the same synchronization • Change another variable to volatile to create happens-before relationships due to transitivity

  42. Change to atomic array Thread 1 Peterson’s ME Alg. turn and flag are volatile s1: flag[0] = 1; s2: turn = 1; removes flag[1] from h(thread1) Change flag to atomic array Thread 2 source statement s6: flag[1] = 1; Thread 1 manifest statement s3: while (flag[1] == 1 && turn == 1) { /*spin*/} Accesses flag[1] when flag[1] is not in h(thread1)

  43. An Example for movesource Initialization: goFlag = false; volatile Data publish; Thread 2 Thread 1 s1: r = new Data(); t1: if (publish != null) { s2: publish = r; t2: while (!goFlag); s3: r.setDesc(e); t3: String s = publish.getDesc(); t4: assert(s.equals(“e”); } s4: goFlag = true; • Updates published object • after making the reference • visible • Compiler may reorder s3 • and s4 • May use the published object • when it is in an inconsistent state

  44. Move source statement Thread 1 publish is volatile goFlag is not volatile s1: r = new Data(); s4: goFlag = true; Move s4 before s2 s2: publish = r; removes goFlag from h(thread2) s3: r.setDesc(e); source statement s4: goFlag = true; Thread 2 Accesses goFlag when goFlag is not in h(thread2) t1: if (publish != null) { manifest statement t2: while (!goFlag);

  45. An Example for perform the same synchronization operation Initialization: int data; final Object lock = new Object(); Thread 2 Thread 1 s1: print (data); t1: synchronized (lock) { /*lock*/ t2: data = 1; t3: } /*unlock*/ • For every non-volatile variable v, acquireHistory(v) stores • the set of safe accesses by thread t via a synchronization • operation on s. • Thread2’s safe access on data is noted as an example • behavior.

  46. Perform that synchronized block data is not volatile Thread 2 removes data from h(thread1) t1: synchronized (lock) { /*lock*/ source statement t2: data = 1; Perform synchronized (lock) to access data t3: } /*unlock*/ Thread 1 Accesses data when data is not in h(thread1) s0: synchronized (lock) { /*lock*/ manifest statement s1: print (data); s2: } /*unlock*/

  47. An Example for change another to volatile Initialization: int x; boolean done = false; /* both non-volatile*/ Thread 2 Thread 1 s1: x = 1; t1: while (!done); s2: done = true; t2: assert(x == 1); • Potential data races both on x and done. • Should we really change both to x and done tovolatile? • Can we get away by changing only one?

  48. Change other to volatile removes x from h(thread2) xand done are not volatile Thread 1 source statement s1: x = 1; s2: done = true; Change done to volatile Thread 2 t1: while (!done); manifest statement t2: assert(x == 1); accesses x when x is not in h(thread2)

  49. JRF-E: Eliminating Data Races • JRF is configured to produce threshold # of counter-example paths and write to a file • JRF-E works on the output of JRF and analyzes the counter-example paths to generate code modification suggestions • For each race • reports intersection of suggestions on all the relevant counter-example paths • For each specific code modification suggestion • reports the frequency

  50. How did it happen? JRF-E RESULT ====================================================== data race #1 jrf.hbset.util.HBDataRaceException . . . ______________________________________________________ analyze counter example data race source statement : "putstatic" at simple/SimpleRace.java:64 : "x = 1;" data race manifest statement : "getstatic" at simple/SimpleRace.java:74: "assert (x==1);" Change the field "simple.SimpleRace.x from INITIALIZER" to volatile. Change the field "simple.SimpleRace.done from INITIALIZER" to volatile. ______________________________________________________ advice from acquiring history NONE ====================================================== data race #2 jrf.hbset.util.HBDataRaceException . . . ______________________________________________________ analyze counter example data race source statement : "putstatic" at simple/SimpleRace.java:65 : "done = true;" data race manifest statement : "getstatic" at simple/SimpleRace.java:73: "while(!done) { /*spin*/ }" Change the field "simple.SimpleRace.done from INITIALIZER" to volatile. ______________________________________________________ advice from acquiring history NONE ______________________________________________________ frequency of advice [1times] Change the field "simple.SimpleRace.x from INITIALIZER" to volatile. [2times] Change the field "simple.SimpleRace.done from INITIALIZER" to volatile. ______________________________________________________ statistic JRF takes 0:0:1 to find 2 equivalent races with 9 counterexample traces. JRF-E takes 0:0:0 in 9 races analysis. How to fix it? feedback on a single race feedback on another race How many times a suggestion has been made considering all the races? feedback on all races

More Related