Institute of Technology Stockholm, Sweden 4th ACM SIGPLAN International Workshop on Software Engineering for Parallel Systems (SEPS '17) Vancouver, Canada, October 23rd, 2017 1
How best to exploit different forms of concurrency and parallelism? Multiple hazards: race conditions, deadlocks, livelocks, etc. Concurrent programming is difficult: Concurrent programming models 3
requires exploration and experimentation Implementing new compilers and runtime environments is expensive. Domain-specific languages (DSLs) to the rescue! 6
a single collection... wiki val wiki: RDD[WikiArticle] = ... wiki.map { article => article.text.toLowerCase } Example: Transform the text of all wiki articles to lowercase. 12
apply def send def persist def unpersist SiloRef. Handle to a Silo. Silo. Typed, stationary data container. User interacts with SiloRef. SiloRefs come with 4 primitive operations. 21
a function that is to be applied to the data in the silo associated with the SiloRef. Creates new silo to contain the data that the user- defined function returns; evaluation is deferred def apply[S](fun: T => SiloRef[S]): SiloRef[S] Enables interesting computation DAGs Deferred def apply def send def persist def unpersist 22
the built-up computation DAG to be sent to the associated node and applied. Future is completed with the result of the computation. def send(): Future[T] EAGER def apply def send def persist def unpersist 23
val param = 42 val log = new Log(...) ... def work(silo: SiloRef[Int]) = { silo.apply(spore { val localParam = this.param x => SiloRef.populate(currentHost, x + localParam) }).send() } } Miller, Haller, and Odersky. Spores: a type-based foundation for closures in the age of concurrency and distribution. ECOOP 2014 Spore header Spore body 31
interesting DAG! Machine 2 persons: val persons: SiloRef[List[Person]] = ... val vehicles: SiloRef[List[Vehicle]] = ... // adults that own a vehicle val owners = adults.apply(spore { val localVehicles = vehicles // spore header ps => localVehicles.apply(spore { val localps = ps // spore header vs => SiloRef.populate(currentHost, localps.flatMap(p => // list of (p, v) for a single person p vs.flatMap { v => if (v.owner.name == p.name) List((p, v)) else Nil } ) adults owners vehicles val adults = persons.apply(spore { ps => val res = ps.filter(p => p.age >= 18) SiloRef.populate(currentHost, res) }) 34
each other by means of lineages, persistent data structures. The lineage is based on the DAG of operations to derive the data of each silo. Since the lineage is composed of spores, it is serializable. This means it can be persisted or transferred to other machines. Putting lineages to work 39
systems communities, in the context of PL. Natural fit in context of functional programming! Intuition: Spores & SiloRefs are safe to serialize. Therefore, we can save entire DAGs, share them, and use them to restart computations. A functional design for fault-tolerance Putting lineages to work Formalization: typed, distributed core language with spores, silos, and futures. 40
of types under reduction, as well as preservation of lineage mobility. Progress theorem guarantees the finite materialization of remote, lineage-based data. First correctness results for a programming model for lineage-based distributed computation. 41
inspired by popular big data frameworks. Apache Spark MBrace Implemented Spark RDD operators in terms of the primitives of Functional Lineages: map, reduce, groupBy, and join Emulated MBrace using the primitives of Functional Lineages. (distributed collections) (F# async for distributing tasks) See https://github.com/heathermiller/f-p 42
within silos is undefined and meaningless. Additional static checking required to prevent undefined accesses. Proposal: objects put into silos must conform to the object capability model. Mark S. Miller. Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control. PhD thesis, 2006 43
first-class continuations) Static checking (e.g., no type system extensions) DSL implementation: Same runtime environment as host language DSLs realized as shallow embeddings limit: "The Next 700 Asynchronous Programming Models", ACM SPLASH-I 2013 https://www.infoq.com/presentations/rx-async 45
DSLs helps identify limitations and discovery of constructs applicable to multiple DSLs. Shown language extensions: Spores: safe, serializable closures Possible approach: extend general-purpose programming languages to improve embedding of concurrency DSLs. Object-capability security 46
Object capabilities and affine types in Scala: Haller, Miller, and Müller. A Programming Model and Foundation for Lineage-Based Distributed Computation. 2017. Draft: https://infoscience.epfl.ch/record/230304 Miller, Haller, and Odersky. Spores: a type-based foundation for closures in the age of concurrency and distribution. ECOOP 2014 Miller, Haller, Müller, and Boullier. Function passing: a model for typed, distributed functional programming. Onward! 2016 Haller and Loiko. LaCasa: lightweight affinity and object capabilities in Scala. OOPSLA 2016 47
DSLs enable experimenting with new programming models and constructs. Language extensions increase expressiveness and safety of DSLs. Extensions should not be DSL-specific. We have seen this at work in an embedded DSL implementing Functional Lineages. 48