200 likes | 326 Views
Practical Lock/Unlock Pairing for Concurrent Programs. Hyoun Kyu Cho 1 , Yin Wang 2 , Hongwei Liao 1 , Terence Kelly 2 , St é phane Lafortune 1 , Scott Mahlke 1. 1 University of Michigan 2 Hewlett-Packard Labs. Parallel Programming.
E N D
Practical Lock/Unlock Pairing for Concurrent Programs HyounKyu Cho1, Yin Wang2, Hongwei Liao1, Terence Kelly2, Stéphane Lafortune1, Scott Mahlke1 1University of Michigan 2Hewlett-Packard Labs 1
Parallel Programming • Industry wide move to multicores forces parallel programming • Inherently difficult • Concurrency bugs • Non-determinism Intel 4 Core Nehalem AMD 4 Core Shanghai Sun Niagara 2 IBM Cell 2
Tools for Parallel Programs • Concurrency bug detection tools • To statically infer concurrency • ex) RacerX[Engler`03] • Automated bug fix tools • To avoid deadlocks • ex) AFix[Jin`11], Gadara[Wang`08] • Optimizing compilers • Accurate synchronization information can enable more aggressive optimizations 3
Examples 1 : intwork_on_tree(…) 2 : { 3 : Node *ptr1, *ptr2; 4 : … 5 : lock( ptr->mutex ); 6 : while( ptr != NULL ) { 7 : … 8 : ptr2 = iterate_next( ptr1 ); 9 : ptr1 = ptr1; 10: } 11: unlock( ptr->mutex ); 12: } 13: Node* iterate_next(Node *current) 14: { 15: Node *next = find(current); 16: … 17: lock(next->mutex); 18: unlock(current->mutex); 19: … 20: return next; 21: } public class Counter { … public void increment() { synchronized (this) { ++count; } } … } 4
Unpaired Locks and Unlocks • Challenges • Infeasible paths 5
Unpaired Locks Due To Infeasible Paths • Example if (x) void foo(x, A) { if (x) lock(A); … if (x) unlock(A); } true lock(A); false … if(x) true unlock(A); false Feasible Infeasible 6
Unpaired Locks and Unlocks • Challenges • Infeasible paths • Spanning function boundaries • Pointers • Impacts • False positives • Need programmers’ annotation • Conservative, less efficient 7
Practical Lock/Unlock Pairing • For a lock, give a set of pairing unlocks and check if the mutex would be released by them for all feasible paths • Path-sensitive analysis using a SAT solver • Use heuristics based on likely assumptions • Instrument code for dynamic checking 8
Static Analysis Mapping Lock to Set of Corresponding Unlocks Path Condition Calculation Checking Lock/Unlock Pairing 9
Lock/Unlock Pairing Example 01: intfoo(struct Task *job) { 02: … 03: if(job->hasMutex) 04: lock(job->mutex); //(1) 05: if(job->isSpecial) { 06: // Do some special work 07: if(job->hasMutex) 08: unlock(job->mutex); //(2) 09: return result; 10: } 11: // Do normal work 12: if(job->hasMutex) 13: unlock(job->mutex); //(3) 14: return result; 15: } 1. Map set of corresponding unlocks (1) → { (2), (3) } 10
Lock/Unlock Pairing Example 01: intfoo(struct Task *job) { 02: … 03: if(job->hasMutex) 04: lock(job->mutex); //(1) 05: if(job->isSpecial) { 06: // Do some special work 07: if(job->hasMutex) 08: unlock(job->mutex); //(2) 09: return result; 10: } 11: // Do normal work 12: if(job->hasMutex) 13: unlock(job->mutex); //(3) 14: return result; 15: } 2. Calculate Boolean expressions (1): (2): (3): (1): (2): (3): 11
Path Condition Calculation • Recursively calculate path conditions that decide execution of each lock and unlock • Join Point • Disjunction (OR) • Consecutive conditions in a path • Conjunction (AND) src x=true x=false child1 child2 dest • Assign same Boolean variable to Branch conditions that should have same value 12
Lock/Unlock Pairing Example Examine pairing (1) is paired up with { (2), (3) }. If (1) is executed, (2) or (3) is executed. 01: intfoo(struct Task *job) { 02: … 03: if(job->hasMutex) 04: lock(job->mutex); //(1) 05: if(job->isSpecial) { 06: // Do some special work 07: if(job->hasMutex) 08: unlock(job->mutex); //(2) 09: return result; 10: } 11: // Do normal work 12: if(job->hasMutex) 13: unlock(job->mutex); //(3) 14: return result; 15: } 13
CFG Pruning 1 1 2 3 3,5,6 5 6 4 7 7 8 9 9 10 2,4,8,10,11 11 14
Inter-procedural Analysis • Observations • Corresponding unlocks share lowest common ancestor (LCA) in the callgraph • Depths from locks and unlocks to LCA relatively small • Proximity-based Callgraph Partitioning • Extend pairing analysis with context 15
Dynamic Checking • Checking Lock-to-Unlocks Mapping • Keeps a map structure from mutex to acquired LOCK_ID • When released, check if UNLOCK_ID is in corresponding unlock set of LOCK_ID • Checking Semiflow Property • Keeps a map structure from function to mutex • When function returns, check if holding a mutex that should not be held 16
Experimental Setup • Implemented pairing in LLVM compiler infrastructure • Benchmarks • Apache 2.2.11 web server • MySQL 5.0.91 database server • OpenLDAP 2.4.19 lightweight directory access protocol server • pbzip2 1.1.4 • pfscan 1.0 • aget 0.4 • On an Intel Core 2 Quad Q8300 @2.50GHz w/ 8GB MEM 17
Conclusion • Practical Lock/Unlock Pairing • Combines static analysis and dynamic checking • Infeasible path analysis using path conditions • Makes likely assumptions and check at runtime • Overall, pairs up 98.2% of all locks including 7.1% of them paired speculatively • Negligible runtime overhead of 3.4% at most 20