COLT: Effective Testing of Concurrent Collection Usage Alex Aiken Nathan Bronson Stanford University Martin Vechev Eran Yahav IBM Research Mooly Sagiv.

Slides:



Advertisements
Similar presentations
Dataflow Analysis for Datarace-Free Programs (ESOP 11) Arnab De Joint work with Deepak DSouza and Rupesh Nasre Indian Institute of Science, Bangalore.
Advertisements

Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Shape Analysis for Fine-Grained Concurrency using Thread Quantification Josh Berdine Microsoft Research Joint work with: Tal Lev-Ami, Roman Manevich, Mooly.
IBM T. J. Watson Research Center Conditions for Strong Synchronization Maged Michael IBM T J Watson Research Center Joint work with: Martin Vechev, Hagit.
Guy Golan-GuetaTel-Aviv University Nathan Bronson Stanford University Alex Aiken Stanford University G. Ramalingam Microsoft Research Mooly Sagiv Tel-Aviv.
Hongjin Liang and Xinyu Feng
The complexity of predicting atomicity violations Azadeh Farzan Univ of Toronto P. Madhusudan Univ of Illinois at Urbana Champaign.
A Program Transformation For Faster Goal-Directed Search Akash Lal, Shaz Qadeer Microsoft Research.
Interprocedural Analysis Mooly Sagiv Tel Aviv University Sunday Scrieber 8 Monday
An Case for an Interleaving Constrained Shared-Memory Multi-Processor Jie Yu and Satish Narayanasamy University of Michigan.
Architecture-aware Analysis of Concurrent Software Rajeev Alur University of Pennsylvania Amir Pnueli Memorial Symposium New York University, May 2010.
Reduction, abstraction, and atomicity: How much can we prove about concurrent programs using them? Serdar Tasiran Koç University Istanbul, Turkey Tayfun.
Abstract Transformers for Thread Correlation Analysis Michal Segalov, TAU Tal Lev-Ami, TAU Roman Manevich, TAU G. Ramalingam, MSR India Mooly Sagiv, TAU.
Runtime checking of expressive heap assertions Greta Yorsh, Martin Vechev, Eran Yahav, Bard Bloom.
A Randomized Dynamic Program Analysis for Detecting Real Deadlocks Koushik Sen CS 265.
Data Abstraction II SWE 619 Software Construction Last Modified, Spring 2009 Paul Ammann.
© 2004 Goodrich, Tamassia Hash Tables1  
On-the-Fly Garbage Collection: An Exercise in Cooperation Edsget W. Dijkstra, Leslie Lamport, A.J. Martin and E.F.M. Steffens Communications of the ACM,
1 Beyond Reduction Busy Acquire atomic void busy_acquire() { while (true) { if (CAS(m,0,1)) break; } } if (m == 0) { m = 1; return true; } else.
Asynchronous Assertions Eddie Aftandilian and Sam Guyer Tufts University Martin Vechev ETH Zurich and IBM Research Eran Yahav Technion.
Maps. Hash Tables. Dictionaries. 2 CPSC 3200 University of Tennessee at Chattanooga – Summer 2013 © 2010 Goodrich, Tamassia.
ADVERSARIAL MEMORY FOR DETECTING DESTRUCTIVE RACES Cormac Flanagan & Stephen Freund UC Santa Cruz Williams College PLDI 2010 Slides by Michelle Goodstein.
Deriving Linearizable Fine-Grained Concurrent Objects Martin Vechev Eran Yahav IBM T. J. Watson Research Center Martin Vechev Eran Yahav IBM T. J. Watson.
1 Martin Vechev IBM T.J. Watson Research Center Joint work with: Hagit Attiya, Rachid Guerraoui, Danny Hendler, Petr Kuznetsov, Maged Michael.
1 Eran Yahav and Mooly Sagiv School of Computer Science Tel-Aviv University Verifying Safety Properties.
Modular Shape Analysis for Dynamically Encapsulated Programs Noam Rinetzky Tel Aviv University Arnd Poetzsch-HeffterUniversität Kaiserlauten Ganesan RamalingamMicrosoft.
Semantics with Applications Mooly Sagiv Schrirber html:// Textbooks:Winskel The.
Thread-Modular Verification Shaz Qadeer Joint work with Cormac Flanagan Stephen Freund Shaz Qadeer Joint work with Cormac Flanagan Stephen Freund.
Verifying Commit-Atomicity Using Model Checking Cormac Flanagan University of California, Santa Cruz.
Testing Atomicity of Composed Concurrent Operations Ohad Shacham Tel Aviv University Nathan Bronson Stanford University Alex Aiken Stanford University.
Modular Shape Analysis for Dynamically Encapsulated Programs Noam Rinetzky Tel Aviv University Arnd Poetzsch-HeffterUniversität Kaiserlauten Ganesan RamalingamMicrosoft.
Comparison Under Abstraction for Verifying Linearizability Daphna Amit Noam Rinetzky Mooly Sagiv Tom RepsEran Yahav Tel Aviv UniversityUniversity of Wisconsin.
Thread Quantification for Concurrent Shape Analysis Josh BerdineMSR Cambridge Tal Lev-AmiTel Aviv University Roman ManevichTel Aviv University Mooly Sagiv.
1 The Map ADT © Rick Mercer. 2 The Map ADT  A Map is an abstract data type where a value is "mapped" to a unique key  Also known as Dictionary  Need.
Runtime Refinement Checking of Concurrent Data Structures (the VYRD project) Serdar Tasiran Koç University, Istanbul, Turkey Shaz Qadeer Microsoft Research,
Verifying Atomicity via Data Independence Ohad Shacham Yahoo Labs, Israel Eran Yahav Technion, Israel Guy Gueta Yahoo Labs, Israel Alex Aiken Stanford.
Testing and Verifying Atomicity of Composed Concurrent Operations Ohad Shacham Tel Aviv University Nathan Bronson Stanford University Alex Aiken Stanford.
D ESIGN & A NALYSIS OF A LGORITHM 07 – M AP Informatics Department Parahyangan Catholic University.
“Software” Esterel Execution (work in progress) Dumitru POTOP-BUTUCARU Ecole des Mines de Paris
A Consistency Framework for Iteration Operations in Concurrent Data Structures Yiannis Nikolakopoulos A. Gidenstam M. Papatriantafilou P. Tsigas Distributed.
Chameleon Automatic Selection of Collections Ohad Shacham Martin VechevEran Yahav Tel Aviv University IBM T.J. Watson Research Center Presented by: Yingyi.
Inferring Synchronization under Limited Observability Martin Vechev, Eran Yahav, Greta Yorsh IBM T.J. Watson Research Center (work in progress)
Eran Yahav 1. Previously…  An algorithmic view  Abstract data types (ADT)  Correctness Conditions  Sequential consistency  Linearizability  Treiber’s.
Concurrent Linked Lists and Linearizability Proofs Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified.
Automated and Modular Refinement Reasoning for Concurrent Programs Shaz Qadeer.
A Simple Optimistic skip-list Algorithm Maurice Herlihy Brown University & Sun Microsystems Laboratories Yossi Lev Brown University & Sun Microsystems.
Motivation  Parallel programming is difficult  Culprit: Non-determinism Interleaving of parallel threads But required to harness parallelism  Sequential.
Model Checking Linearizability via Refinement 1 ICFEM 2008 Model Checking Linearizability via Refinement Yang LIU, Wei CHEN, Yanhong A. LIU, and Jun SUN.
CSV 889: Concurrent Software Verification Subodh Sharma Indian Institute of Technology Delhi State merging, Concolic Execution.
Data Representation Synthesis PLDI’2011, ESOP’12, PLDI’12 Peter Hawkins, Stanford University Alex Aiken, Stanford University Kathleen Fisher, Tufts Martin.
Sai Zhang Michael D. Ernst Google Research University of Washington
Specifying Multithreaded Java semantics for Program Verification Abhik Roychoudhury National University of Singapore (Joint work with Tulika Mitra)
A Calculus of Atomic Actions Tayfun Elmas, Shaz Qadeer and Serdar Tasiran POPL ‘ – Seminar in Distributed Algorithms Cynthia Disenfeld 27/05/2013.
An algorithm of Lock-free extensible hash table Yi Feng.
Program Analysis and Verification
Soyeon Park, Shan Lu, Yuanyuan Zhou UIUC Reading Group by Theo.
Simplifying Linearizability Proofs Using Reduction and Abstraction Serdar Tasiran Koc University, Istanbul, Turkey Tayfun Elmas, Ali Sezgin, Omer Subasi.
Testing Concurrent Programs Sri Teja Basava Arpit Sud CSCI 5535: Fundamentals of Programming Languages University of Colorado at Boulder Spring 2010.
Maps Rem Collier Room A1.02 School of Computer Science and Informatics
Healing Data Races On-The-Fly
Verification for Concurrent Programs
Design & Analysis of Algorithm Map
Lazy Diagnosis of In-Production Concurrency Bugs
Specifying Multithreaded Java semantics for Program Verification
Maps.
Over-Approximating Boolean Programs with Unbounded Thread Creation
Synthesis of Memory Fences via Refinement Propagation
Foundations and Definitions
Abstraction-Guided Synthesis of synchronization
Program Analysis and Verification
Presentation transcript:

COLT: Effective Testing of Concurrent Collection Usage Alex Aiken Nathan Bronson Stanford University Martin Vechev Eran Yahav IBM Research Mooly Sagiv Ohad Shacham Tel Aviv University

Concurrent Data Structures Writing highly concurrent data structures is complicated Efficient concurrent collections with atomic operations provided by libraries Atomic and efficient composition of several library operations often needed by the client –Efficiency and correctness are client responsibility atomic V put(K,V) {…} atomic V get(K) {…} atomic V putIfAbsent(K,V) {…} atomic V remove(K) {…} atomic boolean remove (K,V) {…} atomic V replace(K,V) {…} atomic boolean replace (K,V, V’) {…} atomic boolean contains(V) {…} atomic boolean containsKey(K) {…} V foo (key K) { Object val = m.get(K) ; if (val != null) { val = m.remove(K); } return val; }

Question How can we write an atomic operation composed from a few libraries operations?

TOMCAT Motivating Example Attribute removeAttribute(String name) { Attribute val = null; synchronized(attr) { found = attr.containsKey(name) ; if (found) { val = attr.get(name); attr.remove(name); } return val; }  Coarse-Grain (TOMCAT 5.*) Fine-Grain (TOMCAT 6.*) Attribute removeAttribute(String name) { Attribute val = null; /* synchronized(attr) { */ found = attr.containsKey(name) ; if (found) { val = attr.get(name); attr.remove(name); } /* } */ return val; } Invariant: removeAttribute(name) returns the value it removes from attr or null

Attribute removeAttribute(String name) { Attribute val = null; found = attr.containsKey(name) ; if (found) { val = attr.get(name); attr.remove(name); } return val; } removeAttribute(“A”) { Attribute val = null; found = attr.containsKey(“A”) ; if (found) { val = attr.get(“A”); attr.remove(“A”); } return val; removeAttribute(“A”) { Attribute val = null; found = attr.containsKey(“A”) ; if (found) { val = attr.get(“A”); attr.remove(“A”); T1 T2 attr Φ { } Breaking the invariant: removeAttribute(name) returns the value it removes from attr or null T1.val o null

 TOMCAT Fix Attribute removeAttribute(String name) { Attribute val = null; synchronized(attr) { found = attr.containsKey(name) ; if (found) { val = attr.get(name); attr.remove(name); } return val; } Coarse-Grain (Before)Fine-Grain (After) Attribute removeAttribute(String name) { Attribute val = attr.get(name) ; if (val != null) { val = attr.remove(name); } return val; }

Very hard to reconstruct in TOMCAT –Specific thread interleaving –Same input key removeAttribute(“A”) { Attribute val = null; found = attr.containsKey(“A”) ; if (found) { val = attr.get(“A”); attr.remove(“A”); } return val; removeAttribute(“A”) { Attribute val = null; found = attr.containsKey(“A”) ; if (found) { val = attr.get(“A”); attr.remove(“A”); T1 T2 attr Φ { } T1.val o null

TOMCAT Motivating Example Attribute removeAttribute(String name) { Attribute val = null; found = attr.containsKey(name) ; if (found) { val = attr.get(name); attr.remove(name); } return val; }

TOMCAT Motivating Example removeAttribute is a new operation of attr composed by attr’s operations Should be atomic in any client environment Resilient for future client changes Backed up by our experimental results Attribute removeAttribute(String name) { Attribute val = null; found = attr.containsKey(name) ; if (found) { val = attr.get(name); attr.remove(name); } return val; } No operation on attr attr atomic V put(K,V) {…} atomic V get(K) {…} atomic V putIfAbsent(K,V) {…} atomic V remove(K) {…} atomic boolean remove (K,V) {…} atomic V replace(K,V) {…} atomic boolean replace (K,V, V’) {…} atomic boolean contains(V) {…} atomic boolean containsKey(K) {…}.

Challenge Checking atomicity of composed operations in any client environment

Memoization Example V compute(K) { synchronized(m) { val = m.get(K); if (val == null) { val = calculateVal(K); m.put (K, val); } return val; } Coarse-Grain

Fine-Grained Concurrent Clients Concurrent collections provide basic operations for fine- grained concurrency ( read-check-modify, CAS like) V putIfAbsent(K, V) –Store and return null or return the current value if K already exists boolean replace(K, V, V’) –Replace by if already exists –Return true on success and false on failure boolean remove(K, V) –Remove if its exists –Return true on success and false on failure

Memoization Example V compute(K) { val = m.get(K); if (val == null) { val = calculateVal(K); m.putIfAbsent(K, val); } return m.get(K); } V compute(K) { synchronized(m) { val = m.get(K); if (val == null) { val = calculateVal(K); m.put (K, val); } return val; }  m.remove(K ) Coarse-Grain (Before)Fine-Grain (After)

Memoization Fix What do we mean by atomic? // atomic V compute(K) { val = m.get(K); if (val == null) { val = calculateVal(K); tmpVal = m.putIfAbsent(K, val); if (tmpVal != null) val = tmpVal; } return val; } atomic implementation of compute

Linearizability [Herlihy and Wing, TOPLAS'90] V compute(K) { val = m.get(K); val != null if (val == null) { val = calculateVal(K); tmpVal = m.putIfAbsent(K, val); if (tmpVal != null) val = tmpVal; } return val; } val=m.get(7)compute(7) {…tmpVal=m.putIfAbsent(7,8) if (tmpVal != null) return val; { } val=m.get(7)compute(7) { if (tmpVal != null) return val;

Thread Modular Linearizability ConcurrentHashMap MUT atomic V put(K,V) {…} atomic V get(K) {…} atomic V putIfAbsent(K,V) {…} atomic V remove(K) {…} atomic boolean remove (K,V) {…} atomic V replace(K,V) {…} atomic boolean replace (K,V, V’) {…} atomic boolean contains(V) {…} atomic boolean containsKey(K) {…}. V compute(K) { val = m.get(K); if (val == null) { val = calculateVal(K); m.putIfAbsent(K, val); } return m.get(K); }

Thread Modular Linearizability atomic V put(K,V) {…} atomic V get(K) {…} atomic V putIfAbsent(K,V) {…} atomic V remove(K) {…} atomic boolean remove (K,V) {…} atomic V replace(K,V) {…} atomic boolean replace (K,V, V’) {…} atomic boolean contains(V) {…} atomic boolean containsKey(K) {…}. V compute(K) { val = m.get(K); if (val == null) { val = calculateVal(K); m.putIfAbsent(K, val); } return m.get(K); }

val=m.get(7)compute(7) {…tmpVal=m.putIfAbsent(7,8)return m.get(7) val=m.get(8)compute(8) {…tmpVal=m.putIfAbsent(8,8)return m.get(8)m.put(9,10) val=m.get(12)compute(12) {…tmpVal=m.putIfAbsent(12,8)return m.get(12)m.put(19,12) val=m.get(5)compute(5) {…tmpVal=m.putIfAbsent(5,13)return m.get(5) m.put(5,12) val=m.get(20)compute(20) {…return m.get(20)m.put(20,10) val=m.get(2)compute(2) {…tmpVal=m.putIfAbsent(2,8)return m.get(2) m.put(30,12) m.remove(20) val=m.get(14)compute(14) {…tmpVal=m.putIfAbsent(14,8)return m.get(14) m.remove(14) val=m.get(20)compute(20) {…return m.get(20) m.remove(14) m.put(9,10)... Thread Modular Linearizability

val=m.get(7)compute(7) {…tmpVal=m.putIfAbsent(7,8)return m.get(7) val=m.get(8)compute(8) {…tmpVal=m.putIfAbsent(8,8)return m.get(8)m.put(9,10) val=m.get(12)compute(12) {…tmpVal=m.putIfAbsent(12,8)return m.get(12)m.put(19,12) val=m.get(5)compute(5) {…tmpVal=m.putIfAbsent(5,13)return m.get(5) m.put(5,12) val=m.get(20)compute(20) {…return m.get(20)m.put(20,10) val=m.get(2)compute(2) {…tmpVal=m.putIfAbsent(2,8)return m.get(2) m.put(30,12) m.remove(20) val=m.get(14)compute(14) {…tmpVal=m.putIfAbsent(14,8)return m.get(14) m.remove(14) val=m.get(20)compute(20) {…return m.get(20) m.remove(14) m.put(9,10)... Hard to test even when modular  Large number of interleavings Bug exhibited very infrequently

val=m.get(7)compute(7) {…tmpVal=m.putIfAbsent(7,8)return m.get(7) val=m.get(8)compute(8) {…tmpVal=m.putIfAbsent(8,8)return m.get(8)m.put(9,10) val=m.get(12)compute(12) {…tmpVal=m.putIfAbsent(12,8)return m.get(12)m.put(19,12) val=m.get(5)compute(5) {…tmpVal=m.putIfAbsent(5,13)return m.get(5) m.put(5,12) val=m.get(20)compute(20) {…return m.get(20)m.put(20,10) val=m.get(2)compute(2) {…tmpVal=m.putIfAbsent(2,8)return m.get(2) m.put(30,12) m.remove(20) val=m.get(14)compute(14) { … tmpVal=m.putIfAbsent(14,8)return m.get(14) m.remove(14) val=m.get(20)compute(20) {…return m.get(20) m.remove(14) m.put(9,10)... Hard to test even when modular

Leveraging Commutativity Operations on different keys are guaranteed to commute Cannot lead to linearizability violation No need to try such interleavings Use commutatively for partial order reduction at the library level val=m.get(8)compute(8) {…tmpVal=m.putIfAbsent(8,8)return m.get(8)m.put(9,10) m.put(9,10) val=m.get(8)… tmpVal=m.putIfAbsent(8,8)return m.get(8) Compute (8) { m.put(9,10) val=m.get(8) … tmpVal=m.putIfAbsent(8,8)return m.get(8) compute(8) { val=m.get(8)compute(8) {…tmpVal=m.putIfAbsent(8,8)return m.get(8)m.put(9,10) val=m.get(8)compute(8) {…tmpVal=m.putIfAbsent(8,8) return m.get(8) m.put(9,10)

Leveraging Commutativity To expose bugs, try operations that do not commute Execute thread in adversarial environment –Adversarial environment picks non-commutative operations –Adversarial scheduler uses non-commutative No bugs are lost due to the reduction MUT OperationConditionAdversarial Action get(k)get(k) == nullput(k,*) get(k)get(k) != nullremove(k), put(k,v) | v!=get(k) putIfAbsent(k,v)get(k) == nullput(k,*) putIfAbsent(k,v)get(k) != nullremove(k) replace(k,oldV,v)get(k) == oldVremove(k) put(k,v’)| v’!= oldV,v replace(k,oldV,v)get(k) != oldVput(k,oldV)

Implementing Dynamic Modular Analyzer Compare concurrent execution to a specific sequential execution Concurrent execution emulated using an adversary Check that every concurrent operation returns the same result as its sequential counterpart Potential linearization point operation MUT Reference Method compare results... Adversary Potential linearization point compare results operation

Running Example V compute(K) { val = m.get(K); val != null if (val == null) { val = calculateVal(K); m.putIfAbsent(K, val); } return m.get(K); }

MUT Adversary Reference Method Map (m) op op Map (refM) Φ compute(7) { Φ val = m.get(7) if (val == null) val = calculateVal(7) {(7,12)} m.put(7,12) != refM.put(7,12) {(7,12)} m.putIfAbsent(7, 14) compute(7) { val = refM.get(7) if (val == null) return refM.get(7) Φ m.remove(7) != refM.remove(7) Φ return m.get(7) MUT OperationConditionAdversarial Action get(k)get(k) == nullput(k,*) get(k)get(k) != nullremove(k), put(k,v) | v!=get(k) putIfAbsent(k,v)get(k) == nullput(k,*) putIfAbsent(k,v)get(k) != nullremove(k) replace(k,oldV,v)get(k) == oldVremove(k), put(k,v’)| v’!= oldV,v replace(k,oldV,v)get(k) != oldVput(k,oldV) V compute(K) { val = m.get(K); val != null if (val == null) { val = calculateVal(K); m.putIfAbsent(K, val); } return m.get(K); } != 12 null

Benchmark Tested 89 MUTs from 48 applications –Apache’s Tomcat, Derby, Cassandra, My Faces – Trinidad, etc…

Results Tested 89 MUTs from 48 applications –Apache’s Tomcat, Derby, Cassandra, My Faces – Trinidad, etc… Discovered 56 linearizability violations 6 reports were proved as linearizable and the adversary refined accordingly Other MUTs were manually proved linearizable Filed bug reports; many already fixed Random adversary failed to find even a single violation –in 10 hours

Reasons For Success Deterministic MUTs For most MUTS –A bug exists for a key iff a bug exists for every key –Control influences by collection’s operation result Does not value dependant V compute(K) { val = m.get(K); if (val == null) { val = calculateVal(K); tmpVal = m.putIfAbsent(K, val); if (tmpVal != null) val = tmpVal; } return val; }

Future Work Verify thread modular linearizability –Small MUT –Use ADT semantics to remove implementation –Small model verification

Summary Fine-grained concurrency is hard Employing atomic library operations is error prune Leverage commutativy Sweet spot –Identify important bugs –Hard to find –Simple and efficient technique