E ff ective Concurrency with Algebraic E ff ects Stephen Dolan 1 , - - PowerPoint PPT Presentation

e ff ective concurrency with algebraic e ff ects
SMART_READER_LITE
LIVE PREVIEW

E ff ective Concurrency with Algebraic E ff ects Stephen Dolan 1 , - - PowerPoint PPT Presentation

E ff ective Concurrency with Algebraic E ff ects Stephen Dolan 1 , Leo White 2 , KC Sivaramakrishnan 1 , Jeremy Yallop 1 , Anil Madhavapeddy 1 1 2 Concurrency Parallelism Concurrency Programming technique Overlapped execution of


slide-1
SLIDE 1

Effective Concurrency with Algebraic Effects

Stephen Dolan1, Leo White2, KC Sivaramakrishnan1, Jeremy Yallop1, Anil Madhavapeddy1

1 2

slide-2
SLIDE 2

Concurrency ≠ Parallelism

  • Concurrency
  • Programming technique
  • Overlapped execution of processes
  • Parallelism
  • Performance hack
  • Simultaneous execution of computations
slide-3
SLIDE 3

Concurrency ≠ Parallelism

  • Concurrency
  • Programming technique
  • Overlapped execution of processes
  • Parallelism
  • Performance hack
  • Simultaneous execution of computations

Concurrency ∩ Parallelism ➔ Scalable Concurrency

slide-4
SLIDE 4

Concurrency ≠ Parallelism

  • Concurrency
  • Programming technique
  • Overlapped execution of processes
  • Parallelism
  • Performance hack
  • Simultaneous execution of computations

Concurrency ∩ Parallelism ➔ Scalable Concurrency (Fibers) (Domains)

slide-5
SLIDE 5

Schedulers

  • Multiplexing fjbers over domain(s)
  • Bake scheduler into the runtime system (GHC)
slide-6
SLIDE 6

Schedulers

  • Multiplexing fjbers over domain(s)
  • Bake scheduler into the runtime system (GHC)
  • Allow programmers to describe schedulers!
  • Parallel search —> LIFO work-stealing
  • Web-server —> FIFO runqueue
  • Data parallel —> Gang scheduling
slide-7
SLIDE 7

Schedulers

  • Multiplexing fjbers over domain(s)
  • Bake scheduler into the runtime system (GHC)
  • Allow programmers to describe schedulers!
  • Parallel search —> LIFO work-stealing
  • Web-server —> FIFO runqueue
  • Data parallel —> Gang scheduling
  • Algebraic Effects and Handlers
slide-8
SLIDE 8

Algebraic Effects and Handlers

  • Programming and reasoning about computational effects in a

pure setting.

  • Cf. Monads
  • Effects in practice
  • M Pretnar, A Bauer, “Eff programming language”
  • http://www.eff-lang.org/
  • O Kiselyov, A Sabry, C Swords, B Foppa, “Extensible-effects for Haskell”
  • https://hackage.haskell.org/package/extensible-effects
  • E Brady, “Effects in Idris”
  • http://eb.host.cs.st-andrews.ac.uk/drafus/eff-tutorial.pdf
  • O Kammar, S Lindley, N Oury , “Handlers in Action”

, ICFP ’13

  • dl.acm.org/citation.cfm?id=2500590
slide-9
SLIDE 9

Algebraic Effects: Example

exception Foo of int let f () = 1 + (raise (Foo 3)) let r = try f () with Foo i -> i + 1

val r : int = 4

slide-10
SLIDE 10

Algebraic Effects: Example

exception Foo of int let f () = 1 + (raise (Foo 3)) let r = try f () with Foo i -> i + 1

val r : int = 4

effect Foo : int -> int let f () = 1 + (perform (Foo 3)) let r = try f () (* spawned in a new fiber *) with effect (Foo i) k -> continue k (i + 1)

val r : int = 5

type _ eff += Foo : int -> int eff val perform : 'a eff -> 'a type ('a,'b) continuation val continue : ('a,'b) continuation -> 'a -> 'b

Effects interface

slide-11
SLIDE 11

Algebraic Effects: Example

exception Foo of int let f () = 1 + (raise (Foo 3)) let r = try f () with Foo i -> i + 1

val r : int = 4

effect Foo : int -> int let f () = 1 + (perform (Foo 3)) let r = try f () (* spawned in a new fiber *) with effect (Foo i) k -> continue k (i + 1)

val r : int = 5

type _ eff += Foo : int -> int eff val perform : 'a eff -> 'a type ('a,'b) continuation val continue : ('a,'b) continuation -> 'a -> 'b

Effects interface

slide-12
SLIDE 12

Algebraic Effects: Example

exception Foo of int let f () = 1 + (raise (Foo 3)) let r = try f () with Foo i -> i + 1

val r : int = 4

effect Foo : int -> int let f () = 1 + (perform (Foo 3)) 4 let r = try f () (* spawned in a new fiber *) with effect (Foo i) k -> continue k (i + 1)

val r : int = 5

type _ eff += Foo : int -> int eff val perform : 'a eff -> 'a type ('a,'b) continuation val continue : ('a,'b) continuation -> 'a -> 'b

Effects interface

slide-13
SLIDE 13

Handlers are Deep!

effect Foo : int -> int let f () = (perform (Foo 3)) (* 3 + 1 *) + (perform (Foo 3)) (* 3 + 1 *) let r = try f () (* spawned in a new fiber *) with effect (Foo i) k -> (* continuation called outside try/with *) continue k (i + 1)

val r : int = 8

slide-14
SLIDE 14

Handlers are Deep!

effect Foo : int -> int let f () = (perform (Foo 3)) (* 3 + 1 *) + (perform (Foo 3)) (* 3 + 1 *) let r = try f () (* spawned in a new fiber *) with effect (Foo i) k -> (* continuation called outside try/with *) continue k (i + 1)

val r : int = 8

slide-15
SLIDE 15

Handlers are Deep!

effect Foo : int -> int let f () = (perform (Foo 3)) (* 3 + 1 *) + (perform (Foo 3)) (* 3 + 1 *) let r = try f () (* spawned in a new fiber *) with effect (Foo i) k -> (* continuation called outside try/with *) continue k (i + 1)

val r : int = 8

slide-16
SLIDE 16

Scheduler Demo1

[1] https://github.com/kayceesrk/ocaml15-eff/tree/master/chameneos-redux

slide-17
SLIDE 17
  • Fibers: Heap allocated, dynamically resized stacks
  • ~10s of bytes
  • No unnecessary closure allocation costs unlike CPS

Implementation

slide-18
SLIDE 18
  • Fibers: Heap allocated, dynamically resized stacks
  • ~10s of bytes
  • No unnecessary closure allocation costs unlike CPS
  • One-shot delimited continuations
  • Simplifjes reasoning about resources - sockets, locks, etc.

Implementation

slide-19
SLIDE 19
  • Fibers: Heap allocated, dynamically resized stacks
  • ~10s of bytes
  • No unnecessary closure allocation costs unlike CPS
  • One-shot delimited continuations
  • Simplifjes reasoning about resources - sockets, locks, etc.
  • Handlers —> Linked-list of fjbers

Implementation

slide-20
SLIDE 20
  • Fibers: Heap allocated, dynamically resized stacks
  • ~10s of bytes
  • No unnecessary closure allocation costs unlike CPS
  • One-shot delimited continuations
  • Simplifjes reasoning about resources - sockets, locks, etc.
  • Handlers —> Linked-list of fjbers

Implementation

handle / continue

handler sp

call chain reference

slide-21
SLIDE 21

Implementation

handle / continue handle / continue

sp handler

call chain reference

  • Fibers: Heap allocated, dynamically resized stacks
  • ~10s of bytes
  • No unnecessary closure allocation costs unlike CPS
  • One-shot delimited continuations
  • Simplifjes reasoning about resources - sockets, locks, etc.
  • Handlers —> Linked-list of fjbers
slide-22
SLIDE 22

perform

sp

handle / continue

Implementation

handler

call chain reference

  • Fibers: Heap allocated, dynamically resized stacks
  • ~10s of bytes
  • No unnecessary closure allocation costs unlike CPS
  • One-shot delimited continuations
  • Simplifjes reasoning about resources - sockets, locks, etc.
  • Handlers —> Linked-list of fjbers
slide-23
SLIDE 23

Performance : Chameneos-Redux

Time (S) 2.5 5 7.5 10 Iterations (X100,000) 1 2 3 4 5 6 7 8 9 10

Lwt (bytecode) Fibers (bytecode) Concurrency Monad (bytecode)

slide-24
SLIDE 24

Performance : Chameneos-Redux

Time (S) 0.45 0.9 1.35 1.8 Iterations (X100,000) 1 2 3 4 5 6 7 8 9 10

Lwt (native) Fibers (bytecode) Concurreny Monad (native) GHC (native)

slide-25
SLIDE 25

Generator from Iterator1

[1] https://github.com/kayceesrk/ocaml15-eff/blob/master/generator.ml

let rec iter f = function | Leaf -> () | Node (l, x, r) -> iter f l; f x; iter f r type 'a t = | Leaf | Node of 'a t * 'a * 'a t

slide-26
SLIDE 26

Generator from Iterator1

[1] https://github.com/kayceesrk/ocaml15-eff/blob/master/generator.ml

(* val to_gen : 'a t -> (unit -> 'a option) *) let to_gen (type a) (t : a t) = let module M = struct effect Next : a -> unit end in let open M in let step = ref (fun () -> assert false) in let first_step () = try iter (fun x -> perform (Next x)) t; None with effect (Next v) k -> step := continue k; Some v in step := first_step; fun () -> !step () let rec iter f = function | Leaf -> () | Node (l, x, r) -> iter f l; f x; iter f r type 'a t = | Leaf | Node of 'a t * 'a * 'a t

slide-27
SLIDE 27

Performance : Generator

Time (S) 1 2 3 4 Binary tree depth 15 16 17 18 19 20 21 22 23 24 25

Iterator Fiber Generator H/W Generator

slide-28
SLIDE 28

Concerns

  • Unchecked effects
  • Risks ~= exceptions
  • Effect inference in Eff1

[1] Matija Pretnar, “Inferring Algebraic Effects” , http://arxiv.org/abs/1312.2334

slide-29
SLIDE 29

Concerns

  • Unchecked effects
  • Risks ~= exceptions
  • Effect inference in Eff1
  • Interfacing with monadic code (Lwt, Async)
  • Use monadic refmection to recover direct-style code2

[1] Matija Pretnar, “Inferring Algebraic Effects” , http://arxiv.org/abs/1312.2334 [2] https://github.com/kayceesrk/ocaml15-eff/blob/master/reify_refmect.ml

slide-30
SLIDE 30

Concerns

  • Unchecked effects
  • Risks ~= exceptions
  • Effect inference in Eff1
  • Interfacing with monadic code (Lwt, Async)
  • Use monadic refmection to recover direct-style code2
  • Compilation to other backends (JS, Java?)
  • ES6 generators, ES7 async/await
  • Selective-CPS transform3

[1] Matija Pretnar, “Inferring Algebraic Effects” , http://arxiv.org/abs/1312.2334 [2] https://github.com/kayceesrk/ocaml15-eff/blob/master/reify_refmect.ml [3] T Rompf et al., “Implementing fjrst-class polymorphic delimited continuations by a type-directed selective CPS-transform” , ICFP ‘09

slide-31
SLIDE 31

Status

  • Bytecode only. Todo Native.
  • Several opportunities for optimisation
  • Continuations invoked at tail position
  • Dynamic search for effect handler
  • Code
  • Multicore OCaml: https://github.com/ocamllabs/ocaml-multicore
  • Stand-alone effects: https://github.com/kayceesrk/ocaml/tree/effects
  • Effects examples: https://github.com/kayceesrk/ocaml-eff-example