Slide 1

Slide 1 text

Programming with Futures, Lattices, and Quiescence Philipp Haller KTH Royal Institute of Technology Sweden @philippkhaller 1

Slide 2

Slide 2 text

2

Slide 3

Slide 3 text

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 • …

Slide 4

Slide 4 text

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 ..

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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?

Slide 7

Slide 7 text

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?

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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!

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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!

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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!

Slide 20

Slide 20 text

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?

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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”

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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()

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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!

Slide 30

Slide 30 text

30

Slide 31

Slide 31 text

31