1 / 38

Poirot – A Concurrency Sleuth

Poirot – A Concurrency Sleuth. Shaz Qadeer Research in Software Engineering Microsoft Research . C oncurrent programming is difficult. IO_REQUEST_PACKET * irp ; irp ->Cancel = FALSE; irp -> CancelRoutine = NULL;. Normal. Cancellation. … if ( i rp ->Cancel) { IoCompleteIrp ( i rp );

shay
Download Presentation

Poirot – A Concurrency Sleuth

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. Poirot – A Concurrency Sleuth Shaz Qadeer Research in Software Engineering Microsoft Research

  2. Concurrent programming is difficult

  3. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); }

  4. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); }

  5. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); }

  6. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); }

  7. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); }

  8. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); }

  9. IO_REQUEST_PACKET *irp; irp->Cancel = FALSE; irp->CancelRoutine = NULL; Normal Cancellation … if (irp->Cancel) { IoCompleteIrp(irp); } else { IoSetCancelRoutine(irp, CancelRoutine); IoMarkIrpPending(irp); } … … irp->Cancel = TRUE; fn = IoSetCancelRoutine(Irp, NULL); if (fn) { fn(irp); } … void CancelRoutine(IRP *irp) { IoCompleteIrp(irp); } Fatal error!

  10. Concurrent programming is difficult • Multiple loci of control resulting in non-local control flow • Code difficult to understand and review

  11. What about verification? • Assertion-based modular reasoning becomes complicated due to non-local interactions • Floyd-Hoare morphs into Owicki-Gries • Even with simple (finite) abstractions, the presence of concurrency makes the analysis computationally very expensive

  12. What about testing? Thread 1 Thread n x = 1; … … … … … x= k; x = 1; … … … … … x= k; • Scheduling nondeterminism • Uncontrollable • Unobservable • Exponential … Number of executions = O( nnk) Exponential in both n and k

  13. Concurrency is important • More than ever before • Increasing importance of communicating systems • networked devices • cyber-physical systems • Distributed programs running on the cloud • EC2, Azure, AppEngine, … • Parallel programs running on multicores and GPUs • TBB, TPL, CUDA, AMP, …

  14. Concurrency testing with CHESS • Deterministic scheduling • make scheduling choices observable and controllable • Search prioritization • combating the combinatorial explosion of possible schedules

  15. Deterministic scheduling Program Tester Provides a Test Scenario While(not done){ TestScenario() } CHESS TestScenario(){ … } CHESS runs the scenario in a loop • Each run is a different interleaving • Each run is repeatable Win32 API Kernel: Threads, Scheduler, Synchronization Objects

  16. Search prioritization (I) • Given p ≥ 0, generate all schedules with up to p preemptions • Pseudo-polynomial number of schedules • polynomial in preemption bound and schedule points • exponential in number of threads • Many bugs with fewer than 2 preemptions • Simple error traces for easier debugging

  17. Search prioritization (II) • Given p ≥ 0 and deterministic schedulers S0, …, Sp-1, schedule according to S0, …, Sp-1 in sequence moving from one to next nondeterministically • e.g., round-robin non-preemptive scheduling with p different round-robin orders • Polynomial number of schedules • Testers can innovate by designing domain-specific deterministic schedulers

  18. CHESS is available • Used internally by Microsoft product groups and externally by Microsoft customers • Binary and source code available at: • http://chesstool.codeplex.com

  19. Limitations of CHESS • Exposing and gaining control of scheduling choices is difficult • most implementation effort and user frustration due to this problem • Testing components that interact extensively with the environment is difficult • Input coverage is not addressed

  20. Static program exploration with Poirot • Symbolic instead of concrete execution • C: Source code for software component • E: Model for environment and scheduler • Explore behaviors of C+E • for all symbolic inputs • for all scheduling choices

  21. Disk Demo: Asynchronous File I/O Request queue In-memory cache tail head cache cacheSize DiskReader(…) { } DiskReader(…) { } AsyncRead(…) { }

  22. Poirot architecture C  Boogie Concurrent C Program Trace Viewer .NET Boogie Corral Concurrent .NET Program Concurrent Boogie Program Coverage Report

  23. Searching with Corral Abstraction Sequentialization Stratified Search Error Trace Concurrent Boogie Program Sequential Boogie Program Concurrent Boogie Program Refinement Coverage Report

  24. Abstraction • Set of global variables G • Set of tracked variables T • Drop writes to variables in G-T • Replace reads to variables in G-T with nondeterministic values

  25. Searching with Corral Abstraction Sequentialization Stratified Search Error Trace Concurrent Boogie Program Sequential Boogie Program Concurrent Boogie Program Refinement Coverage Report

  26. Refinement • Path p • feasible if only variables in T are tracked • infeasible if all variables in G are tracked • Expand tracked set T to U such that p infeasible while tracking only variables in U • Naïve algorithm: linear scan of G-T • New divide-and-conquer algorithm • best case log(|G-T|) • worst case 2*|G-T|

  27. Searching with Corral Abstraction Sequentialization Stratified Search Error Trace Concurrent Boogie Program Sequential Boogie Program Concurrent Boogie Program Refinement Coverage Report

  28. Sequentialization (I) • Given a concurrent program P, construct a sequential program Q such that Q  P • Drop each occurrence of async-call • Convert each occurrence of async-call to call

  29. Sequentialization(II) • Given a concurrent program P, construct a family of programs Qi such that • Q0 Q1  Q2  …  P • iQi= P • Even better if interesting behaviors of P manifest in Qi for low values of i

  30. Context-bounding • Under-approximation parameterized by K ≥ 0 • executions in which each thread gets at most K contexts to execute • As K  , we get all behaviors • Can we create sequentializations for context-bounding?

  31. Sequentializing context switches s2 (s2, l2) l2 Shared Memory T1 T2 Local Memory Local Memory Execution: T1 T2 T1 T2 T1 T2 T1 (s1, l1) T1

  32. Guess and verify • Make copies of global variables • Source-to-source translation • linear in program size and K • Generalizes to dynamically-created threads T1 (s2, l2) (s3, l2) (s1, l1) T1 T2 Guess the effect of T2 Verify the guess

  33. Searching with Corral Abstraction Sequentialization Stratified Search Error Trace Concurrent Boogie Program Sequential Boogie Program Concurrent Boogie Program Refinement Coverage Report

  34. Stratified search Convert loops to recursive calls Call tree given recursion bound r assert no bug main T L assert no bug Summaries(L) VC(p) VC(T) …

  35. Poirot status • Medium-sized C programs • up to 20K low-level systems code • reports precise traces at scale • Small .NET programs • bytecode to Boogie translator in progress • Try: http://www.rise4fun.com/Poirot • Downloadavailable

  36. Why bounded search? Data: Boolean, Integers, Arrays Control: Sequencing, Choice, Iteration, Call, Async-Call Sequencing Choice Iteration Call Async-call Sequencing Choice Iteration Call Async-call + bound Sequencing Choice NP-complete Decidable PSPACE-hard Undecidable Advances in SAT/SMT-solvers have made this problem tractable HAVOC verifier deployed for security analysis in Windows/IE Rationale: It is better to fail at the simpler problem!

  37. Poirot collaborators Akash Lal, MSR Bangalore Shuvendu Lahiri, MSR Redmond

  38. Questions

More Related