Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Programming with Futures, Lattices, and Quiescence

Philipp Haller
June 16, 2016
760

Programming with Futures, Lattices, and Quiescence

Philipp Haller

June 16, 2016
Tweet

More Decks by Philipp Haller

Transcript

  1. Programming with Futures, Lattices, and Quiescence Philipp Haller KTH Royal

    Institute of Technology Sweden @philippkhaller 1
  2. 2

  3. Programming with Futures, Lattices, and Quiescence — Philipp Haller Have

    we solved concurrent programming, yet? There are promising concurrent programming models and abstractions! 3 • Monitors • Futures, promises • Async/await • STM • Actors • Join-calculus • Agents • CSP • Reactive streams • …
  4. Programming with Futures, Lattices, and Quiescence — Philipp Haller Background

    • Authored or co-authored: – Scala Actors – Scala futures and promises – Scala Async • Contributed to Akka • Akka.js project at Typesafe 4 More proposals and research projects: •Scala Joins •FlowPools •Spores ..
  5. Programming with Futures, Lattices, and Quiescence — Philipp Haller Why

    are there so many? The problem with concurrency: – It’s difficult! – Multiple hazards: • Race conditions • Deadlocks • Livelocks • Violation of fairness 5
  6. Programming with Futures, Lattices, and Quiescence — Philipp Haller Non-Determinism

    • At the root of several hazards • Example 1: 6 @volatile var x = 0 def m(): Unit = { Future { x = 1 } .. // does not access x x = 2 } What’s the value of x • when m returns? • when the future is completed?
  7. Programming with Futures, Lattices, and Quiescence — Philipp Haller Non-Determinism

    • At the root of several hazards • Example 2: 7 @volatile var x = 0 def m(): Unit = { Future { x = 1 } Future { x = 2 } .. // does not access x } What’s the value of x • when m returns? • when the futures are completed?
  8. Programming with Futures, Lattices, and Quiescence — Philipp Haller Reordering

    not always a problem! • Example 3: 8 import scala.collection.concurrent.TrieMap val set = new TrieMap[Int, Int] Future { set.put(1, 0) } set.put(2, 0) Eventually, set contains both 1 and 2, always Bottom line: it depends on the datatype
  9. Programming with Futures, Lattices, and Quiescence — Philipp Haller …

    and its operations! • Example 4: 9 val set = new TrieMap[Int, Int] Future { set.put(1, 0) } Future { if (set.contains(1)) { .. } } set.put(2, 0) Result depends on schedule!
  10. Programming with Futures, Lattices, and Quiescence — Philipp Haller Important

    questions Q1:
 How do we know we have written a deterministic concurrent program? – What about Heisenbugs? • No race in 1’000’000 runs, race in run 1’000’001 10 Goal: simple criteria that guarantee determinism
  11. Programming with Futures, Lattices, and Quiescence — Philipp Haller Important

    questions Q2:
 How do we ensure expressivity while providing determinism? – Draconian restrictions undesired! 11 Goal: reconcile determinism and expressivity
  12. Programming with Futures, Lattices, and Quiescence — Philipp Haller Approach

    • Extend futures and promises with: – Lattice-based operations – Quiescence – Resolution of cyclic dependencies • Evaluation in terms of expressivity and performance – Case study: static analysis of JVM bytecode 12 Crucial for determinism! Increases expressivity!
  13. Programming with Futures, Lattices, and Quiescence — Philipp Haller Enter

    Reactive Async Programming model based on two core abstractions:
 cells and cell completers – Cell[K,V] extends Future[V] – CellCompleter[K,V] extends Promise[V] – V must have an instance of a lattice type class • Monotonic updates 13
  14. Programming with Futures, Lattices, and Quiescence — Philipp Haller Example

    • Given a social graph – vertex = user • Traverse graph and collect IDs of “interesting” users • Graph large => concurrent traversal 14
  15. Programming with Futures, Lattices, and Quiescence — Philipp Haller Solution

    • Collect IDs of interesting users in a cell • Cell contains set of integers 15 OK: subsets of the set of all integers form a lattice
  16. Programming with Futures, Lattices, and Quiescence — Philipp Haller Cell

    with user IDs (code simplified) 16 implicit object IntSetLattice extends Lattice[Set[Int]] { val empty = Set() def join(left: Set[Int], right: Set[Int]) = left ++ right } // add a user ID userIDs.putNext(Set(theUserID)) val userIDs = CellCompleter[Set[Int]] Bounded
 join-semilattice
  17. Programming with Futures, Lattices, and Quiescence — Philipp Haller Reading

    the result • Problem: when reading a cell’s value, how do we know this value is not going to change any more? – There may still be ongoing concurrent activities – Manual synchronization (e.g., latches) error-prone • Solution: 17 Koyaanisqatsi Quiescence
  18. Programming with Futures, Lattices, and Quiescence — Philipp Haller Quiescence

    • Intuitively: situation when values of cells are guaranteed not to change any more • Technically: – No concurrent activities ongoing or scheduled which could change values of cells – Detected by the underlying thread pool 18
  19. Programming with Futures, Lattices, and Quiescence — Philipp Haller Revisiting

    the example 19 // add a user ID userIDs.putNext(Set(theUserID)) .. val pool = new HandlerPool val userIDs = CellCompleter[Set[Int]](pool) // register handler // upon quiescence: read result value of cell pool.onQuiescent(userIDs.cell) { collectedIDs => .. } Safe to read from cell when pool quiescent!
  20. Programming with Futures, Lattices, and Quiescence — Philipp Haller Handler

    pools Execution context with extensions: – Event-driven quiescence API – Resolution of dependencies between cells 20 Dependency resolution?
  21. Programming with Futures, Lattices, and Quiescence — Philipp Haller Expressing

    concurrent dataflow • Cells provide non-blocking interface – Low level: callbacks – High level: combinators • Important purpose: express concurrent dataflow • Problem: 21 What if the dataflow graph is cyclic? Like futures fut fun fut’ pred fut’’ fut.map(fun).filter(pred) Futures
  22. Programming with Futures, Lattices, and Quiescence — Philipp Haller Dataflow

    graphs Example: • Static analysis of JVM bytecode • Task:
 Determine purity of methods • Rules: – A method is impure if it accesses a non-final field – A method is impure if it calls an impure method – … 22 A B C “calls”
  23. Programming with Futures, Lattices, and Quiescence — Philipp Haller Cycle

    resolution • What if upon quiescence cells are empty and there is a dependency cycle? • Idea:
 Pluggable resolution policies • Example:
 Purity analysis should resolve all cells
 in cycle to “pure”, since could not show impurity 23 A B C
  24. Programming with Futures, Lattices, and Quiescence — Philipp Haller Specifying

    resolution policies • Role of the first type parameter of Cell[K,V] • Example: 24 object PurityKey extends Key[Purity] { def resolve[K <: Key[Purity]](cells: Seq[Cell[K, Purity]]) = cells.map(cell => (cell, Pure)) .. } closed strongly- connected component resolve all cells to Pure
  25. Programming with Futures, Lattices, and Quiescence — Philipp Haller Purity

    analysis: set up 25 for { classFile <- project.allProjectClassFiles method <- classFile.methods } { val methodCompleter = CellCompleter(pool, PurityKey) pool.execute { analyze(project, methodCompleter, classFile, method) } } val analysisDoneFuture = pool.quiescentResolveCells()
  26. Programming with Futures, Lattices, and Quiescence — Philipp Haller Evaluation

    • Static analysis of JVM bytecode using the OPAL framework (OPen extensible Analysis Library) – Newly developed, highly adaptable bytecode toolkit – Fully concurrent • Rewrote purity analysis and immutability analysis • Ran analysis on JDK 8 (rt.jar) – 18’591 class files, 163’268 methods, 77’128 fields 26 http://www.opal-project.de
  27. Programming with Futures, Lattices, and Quiescence — Philipp Haller Preliminary

    results • RA’s implementation not yet optimized 27 RA 15% faster than OPAL’s implementation with • code size reduced by a factor of two • determinism properties
  28. Programming with Futures, Lattices, and Quiescence — Philipp Haller Ongoing

    and future work • Benchmarking and optimization • Determinism as an effect – Determinism guaranteed by type checker – Effect system for Dotty • Macro support à la Async? 28
  29. Programming with Futures, Lattices, and Quiescence — Philipp Haller Reactive

    Async: conclusion • New concurrent programming model – Lattices and quiescence for determinism – Resolution of cyclic dependencies • Promising preliminary results • Future: static checking of determinism via effects 29 https://github.com/phaller/reactive-async Thank you!
  30. 30

  31. 31