Slide 1

Slide 1 text

Deterministic Concurrency and Large-Scale Static Analysis Philipp Haller KTH Royal Institute of Technology Stockholm, Sweden Joint work with: Simon Geries, Michael Eichberg, Guido Salvaneschi, and Alexandre Loiko

Slide 2

Slide 2 text

Reactive Async: Expressive Deterministic Concurrency — Philipp Haller Have we solved concurrent programming, yet? The problem with concurrency: – It’s difficult: • Race conditions • Deadlocks • Livelocks • Fairness violations • … 2

Slide 3

Slide 3 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Non-determinism • At the root of several hazards • Example 1: 3 @volatile var x = 0 def m(): Unit = { Future { x = 1 } Future { x = 2 } .. // does not access x } What’s the value of x when an invocation of m returns?

Slide 4

Slide 4 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Reordering not always a problem! • Example 2: 4 val set = Set.empty[Int] Future { set.put(1) } set.put(2) Eventually, set contains both 1 and 2, always Bottom line: it depends on the datatype

Slide 5

Slide 5 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller … and its operations! • Example 3: 5 val set = Set.empty[Int] Future { set.put(1) } Future { if (set.contains(1)) { .. } } set.put(2) Result depends on schedule!

Slide 6

Slide 6 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Goal • Programming model providing static determinism guarantees • Starting from imperative, object-oriented language – pervasive aliasing – global state • Important concerns: expressivity and performance 6

Slide 7

Slide 7 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Approach • Extend a future-style programming model with: – Lattice-based datatypes – Quiescence – Resolution of cyclic dependencies • Extend Scala's type system for static safety 7 Crucial for determinism! Increases expressivity!

Slide 8

Slide 8 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Programming model Programming model based on two core abstractions:
 cells and cell completers – Cell = shared “variable” – Cell[K,V]: read-only interface; read values of type V – CellCompleter[K,V]: write values of type V to its associated cell – V must have an instance of a lattice type class 8 Monotonic updates

Slide 9

Slide 9 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Example • Given a social graph – vertex = user • Traverse graph and collect IDs of “interesting” users • Graph large => concurrent traversal 9

Slide 10

Slide 10 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Cell with user IDs (code simplified) 10 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 [1] Oliveira, Moors, and Odersky. Type classes as objects and implicits. OOPSLA 2010

Slide 11

Slide 11 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Reading results • 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 11

Slide 12

Slide 12 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Freeze • Introduce operation to freeze cells • Attempting to mutate a frozen cell results in a failure • May only read from frozen cells – Ensures only unchangeable values are read – Weakens determinism guarantee 12 "All non-failing executions compute the same cell values." "Quasi- determinism"

Slide 13

Slide 13 text

Reactive Async: Expressive Deterministic Concurrency — Philipp Haller Reading results: alternative approach • 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 • Alternative solution: Quiescence • Stronger than quasi-determinism 13

Slide 14

Slide 14 text

Deterministic Concurrency and Large-Scale Static Analysis — 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 14

Slide 15

Slide 15 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Revisiting the example 15 // 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 16

Slide 16 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Reactive threshold reads* 16 cell2.whenNext(cell1, Set(v1, v2, v3)) { v => // compute update for cell2 } • When value of a cell "crosses" a threshold set: update another cell – "Crosses" = new value greater than one of the values in the threshold set * non-reactive threshold reads:
 [2] Kuper, Turon, Krishnaswami, and Newton. Freeze after writing: Quasi-deterministic parallel programming with LVars. POPL 2014

Slide 17

Slide 17 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Reactive threshold reads 17 cell2.whenNext(cell1, Set(Set(2), Set(2, 5))) { v => NextOutcome(v) } • Determinism requires restricting the threshold set • Example: powerset lattice Init state: cell1 = Set(0), cell2 = Set(0) • Permits non-deterministic executions cell1.putNext(Set(2)) cell1.putNext(Set(2, 5)) => handler sees Set(2) cell1.putNext(Set(2, 5)) cell1.putNext(Set(2)) => handler sees Set(2, 5)

Slide 18

Slide 18 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Reactive threshold reads 18 • Determinism requires restricting the threshold set • Restriction:
 Incompatibility of elements of threshold set – v1, v2 incompatible iff LUB(v1, v2) = Top • Concurrent crossings of threshold set due to different elements yield failed executions – Turn potential non-determinism into failure, thus preserving quasi-determinism

Slide 19

Slide 19 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Source of data races: variable capture 19 var x = 0 cell2.whenNext(cell1, Set(1)) { v => NextOutcome(x) } cell3.whenNext(cell1, Set(1)) { v => x = 1 NoOutcome } cell1.putNext(1) [3] Miller, Haller, and Odersky. Spores: a type-based foundation for closures in the age of concurrency and distribution. ECOOP 2014 Solution: use spores [2] to prevent • re-assigning captured variables • capturing mutable, shared data structures

Slide 20

Slide 20 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Other sources of data races 20 class C { def set(x: Int): Unit = Global.f = x def get: Int = Global.f } object Global { var f: Int = 0 } cell2.whenNext(cell1, Set(1)) { v => val c = new C NextOutcome(c.get) } cell3.whenNext(cell1, Set(1)) { v => val c = new C c.set(1) NoOutcome } cell1.putNext(1)

Slide 21

Slide 21 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Solution 21 • Restrict instantiation within whenNext closures to classes conforming to the object capability model [3] • A class is conformant* ("ocap") iff – its methods only access parameters and this – its methods only instantiate ocap classes – types of fields and method parameters are ocap * simplified [4] Mark S. Miller. Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control. PhD thesis, 2006

Slide 22

Slide 22 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller How practical is the object capability requirement? 22 • How common is object-capability safe code in Scala? • Empirical study of >75,000 SLOC of open-source code

Slide 23

Slide 23 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller How practical is the object capability requirement? 23 • Results:

Slide 24

Slide 24 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller In the paper 24 • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions • CLC3: concurrent extension • Soundness proof • Isolation theorem for processes with shared heap [5] Haller and Loiko. LaCasa: Lightweight affinity and object capabilities in Scala. OOPSLA 2016

Slide 25

Slide 25 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Dependency 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 – … 25 A B C “calls”

Slide 26

Slide 26 text

Deterministic Concurrency and Large-Scale Static Analysis — 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 no evidence of impurity 26 A B C

Slide 27

Slide 27 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Specifying resolution policies • Role of the first type parameter of Cell[K,V] • Example: 27 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 28

Slide 28 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Evaluation • Static analysis of JVM bytecode using the OPAL framework (OPen extensible Analysis Library) – New Scala-based, extensible bytecode toolkit – Fully concurrent • Rewrote purity analysis and immutability analysis • Ran analysis on JDK 8 update 45 (rt.jar) – 18’591 class files, 163’268 methods, 77’128 fields 28 http://www.opal-project.de

Slide 29

Slide 29 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Results: immutability analysis • RA about 10x faster than FPCF • RA = 294 LOC, FPCF = 424 LOC (1.44x) 29 FPCF (secs.) 1.0 1.5 2.0 2.5 Reactive-Async (secs.) 0.1 0.2 0.3 1 Thread 2 Threads 4 Threads 8 Threads 16 Threads 2.15 2.20 2.25 2.30 2.35 1.15 1.20 1.25 1.30 1.35 0.290 0.295 0.300 0.105 0.110 0.115 box plot: whiskers = min/max
 top/bottom of box = 
 1st and 3rd quartile band in box: median FPCF = OPAL’s fixed point computation framework

Slide 30

Slide 30 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Results: purity analysis • Best configs. (FPCF: 4 thr, RA: 16 thr): RA 1.75x faster • RA = 113 LOC, FPCF = 166 LOC (1.47x) 30 FPCF (secs.) 0.15 0.20 0.25 0.30 0.35 Reactive-Async (secs.) 0.1 0.2 0.3 0.4 0.5 1 Thread 2 Threads 4 Threads 8 Threads 16 Threads 0.43 0.44 0.45 0.09 0.10 0.11 0.335 0.340 0.345 0.165 0.170 0.175 0.180 0.185 0.18 0.19 0.20

Slide 31

Slide 31 text

Reactive Async: Expressive Deterministic Concurrency — Philipp Haller Benchmarks: Monte Carlo simulation • Compute Net Present Value • 14-16 threads: Scala futures 23-36% faster than RA 31 Sequential Reactive Async Scala Futures 2.11.7 Runtime (ms) 0 1000 2000 3000 4000 5000 6000 Number of Threads 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 400 500 600 700 14 15 16

Slide 32

Slide 32 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Benchmarks: parallel sum • Parallel sum of large collection of random ints • Performance competitive with Scala’s futures 32 Sequential Reactive Async Scala Futures 2.11.7 Runtime (ms) 0 50 100 150 200 250 300 Number of Threads 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Slide 33

Slide 33 text

Deterministic Concurrency and Large-Scale Static Analysis — Philipp Haller Reactive Async: Conclusion • Deterministic concurrent programming model – Extension of imperative, object-oriented base language – Lattices and quiescence for determinism – Resolution of cyclic dependencies – Type system for object capabilities for safety • First experimental results • Ongoing and future work: – Complete formal development – Implement state-of-the-art static analyses 33 Thank you!