reagents lock free programming for the masses
play

Reagents: lock-free programming for the masses KC Sivaramakrishnan - PowerPoint PPT Presentation

Reagents: lock-free programming for the masses KC Sivaramakrishnan University of OCaml Cambridge Labs Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Compiler 2 Multicore OCaml Concurrency Parallelism


  1. Reagents: lock-free programming for the masses “KC” Sivaramakrishnan University of OCaml Cambridge Labs

  2. Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Compiler 2

  3. Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Compiler 2

  4. Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Compiler Fibers 2

  5. Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Compiler • 12M fibers/s on 1 core Fibers • 30M fibers/s on 4 cores 2

  6. Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Compiler • 12M fibers/s on 1 core Fibers Domains • 30M fibers/s on 4 cores 2

  7. Multicore OCaml Concurrency Parallelism Libraries Language + Stdlib Effects Domain API Compiler • 12M fibers/s on 1 core Fibers Domains • 30M fibers/s on 4 cores 2

  8. Multicore OCaml Concurrency Parallelism Libraries Cooperative threading libraries Language + Stdlib Effects Domain API Compiler • 12M fibers/s on 1 core Fibers Domains • 30M fibers/s on 4 cores 2

  9. Multicore OCaml Concurrency Parallelism Libraries Cooperative Reagents : lock- threading libraries free programming Language + Stdlib Effects Domain API Compiler • 12M fibers/s on 1 core Fibers Domains • 30M fibers/s on 4 cores 2

  10. JVM: java.util.concurrent .Net: System.Concurrent.Collections 3

  11. JVM: java.util.concurrent .Net: System.Concurrent.Collections Synchronization Data structures Reentrant locks Queues Semaphores Nonblocking R/W locks Blocking (array & list) Reentrant R/W locks Synchronous Condition variables Priority, nonblocking Countdown latches Priority, blocking Cyclic barriers Deques Phasers Sets Exchangers Maps (hash & skiplist) 3

  12. JVM: java.util.concurrent .Net: System.Concurrent.Collections Synchronization Data structures Reentrant locks Queues Not Composable Semaphores Nonblocking R/W locks Blocking (array & list) Reentrant R/W locks Synchronous Condition variables Priority, nonblocking Countdown latches Priority, blocking Cyclic barriers Deques Phasers Sets Exchangers Maps (hash & skiplist) 3

  13. How to build composable lock-free programs? 4

  14. lock-free 5

  15. lock-free Under contention, at least 1 thread makes progress 5

  16. lock-free Under contention, at least 1 thread makes progress obstruction-free Single thread in isolation makes progress 5

  17. wait-free Under contention, each thread makes progress lock-free Under contention, at least 1 thread makes progress obstruction-free Single thread in isolation makes progress 5

  18. Compare-and-swap (CAS) module CAS : sig val cas : 'a ref -> expect:'a -> update:'a -> bool end = struct (* atomically... *) let cas r ~expect ~update = if !r = expect then (r:= update; true) else false end 6

  19. Compare-and-swap (CAS) module CAS : sig val cas : 'a ref -> expect:'a -> update:'a -> bool end = struct (* atomically... *) let cas r ~expect ~update = if !r = expect then (r:= update; true) else false end • Implemented atomically by processors • x86: CMPXCHG and friends • arm: LDREX, STREX, etc. • ppc: lwarx, stwcx, etc. 6

  20. Head 3 2 7

  21. Head 3 2 7 7

  22. Head 3 2 CAS attempt 7 7

  23. Head 5 3 2 CAS attempt 7 7

  24. Head 5 3 2 CAS fail 7 7

  25. Head 5 3 2 7 7

  26. Head 5 3 2 7 8

  27. module type TREIBER_STACK = sig type 'a t val push : 'a t -> 'a -> unit ... end module Treiber_stack : TREIBER_STACK = struct type 'a t = 'a list ref let rec push s t = let cur = !s in if CAS.cas s cur (t::cur) then () else (backoff (); push s t) end 9

  28. module type TREIBER_STACK = sig type 'a t val push : 'a t -> 'a -> unit val try_pop : 'a t -> 'a option end module Treiber_stack : TREIBER_STACK = struct type 'a t = 'a list ref let rec push s t = ... let rec try_pop s = match !s with | [] -> None | (x::xs) as cur -> if CAS.cas s cur xs then Some x else (backoff (); try_pop s) end 10

  29. let v = Treiber_stack.pop s1 in Treiber_stack.push s2 v is not atomic 11

  30. The Problem: Concurrency libraries are indispensable, but hard to build and extend let v = Treiber_stack.pop s1 in Treiber_stack.push s2 v is not atomic 11

  31. Reagents Scalable concurrent algorithms can be built and extended using abstraction and composition Treiber_stack.pop s1 >>> Treiber_stack.push s2 is atomic 12

  32. PLDI 2012 13

  33. PLDI 2012 Sequential >>> — Software transactional memory Parallel <*> — Join Calculus Selective <+> — Concurrent ML 13

  34. PLDI 2012 Sequential >>> — Software transactional memory Parallel <*> — Join Calculus Selective <+> — Concurrent ML still lock-free! 13

  35. Design 14

  36. Lambda: the ultimate abstraction 'a 'b 'b 'c f g val f : 'a -> 'b val g : 'b -> 'c 15

  37. Lambda: the ultimate abstraction 'a 'b 'c f g (compose g f): 'a -> 'c 16

  38. 'a 'b Lambda abstraction: f 17

  39. 'a 'b Lambda abstraction: f 'a 'b Reagent abstraction: R ('a,'b) Reagent.t 17

  40. 'a 'b Lambda abstraction: f 'a 'b Reagent abstraction: R ('a,'b) Reagent.t val run : ('a,'b) Reagent.t -> 'a -> ‘b 17

  41. Thread Interaction module type Reagents = sig type ('a,'b) t (* shared memory *) module Ref : Ref.S with type ('a,'b) reagent = ('a,'b) t (* communication channels *) module Channel : Channel.S with type ('a,'b) reagent = ('a,'b) t ... end 18

  42. module type Channel = sig type ('a,'b) endpoint type ('a,'b) reagent val mk_chan : unit -> ('a,'b) endpoint * ('b,'a) endpoint val swap : ('a,'b) endpoint -> ('a,'b) reagent end

  43. module type Channel = sig type ('a,'b) endpoint type ('a,'b) reagent val mk_chan : unit -> ('a,'b) endpoint * ('b,'a) endpoint val swap : ('a,'b) endpoint -> ('a,'b) reagent end c : ('a,'b) endpoint 'a 'b swap c

  44. module type Channel = sig type ('a,'b) endpoint type ('a,'b) reagent val mk_chan : unit -> ('a,'b) endpoint * ('b,'a) endpoint val swap : ('a,'b) endpoint -> ('a,'b) reagent end c : ('a,'b) endpoint 'a 'b swap c c swap 'b 'a

  45. c : ('a,'b) endpoint 'b 'a swap c

  46. type 'a ref val upd : 'a ref Message passing -> f:(‘a -> 'b -> ('a * ‘c) option) -> ('b, 'c) Reagent.t swap 21

  47. type 'a ref val upd : 'a ref Message passing -> f:(‘a -> 'b -> ('a * ‘c) option) -> ('b, 'c) Reagent.t upd 'b 'c swap f r 'a 'a 21

  48. Message passing Shared state upd swap f 22

  49. Message passing Shared state upd swap f 'a 'b R 'a 'b S 22

  50. Message passing Shared state upd swap f R 'a 'b <+> S 22

  51. Message passing Shared state upd swap f Disjunction R <+> S 23

  52. Message passing Shared state upd swap f Disjunction 'a 'b R R <+> 'a 'c S S 23

  53. Message passing Shared state upd swap f Disjunction R R ' a ('b * 'c) <+> <*> S S 23

  54. Message passing Shared state upd swap f Conjunction Disjunction R R <+> <*> S S 24

  55. module type TREIBER_STACK = sig type 'a t val create : unit -> 'a t val push : 'a t -> ('a, unit) Reagent.t val pop : 'a t -> (unit, 'a) Reagent.t ... end module Treiber_stack : TREIBER_STACK = struct type 'a t = 'a list Ref.ref let create () = Ref.ref [] let push r x = Ref.upd r (fun xs x -> Some (x::xs,())) let pop r = Ref.upd r (fun l () -> match l with | [] -> None (* block *) | x::xs -> Some (xs,x)) ... end 25

  56. Composability Transfer elements atomically Treiber_stack.pop s1 >>> Treiber_stack.push s2 26

  57. Composability Transfer elements atomically Treiber_stack.pop s1 >>> Treiber_stack.push s2 Consume elements atomically Treiber_stack.pop s1 <*> Treiber_stack.pop s2 26

  58. Composability Transfer elements atomically Treiber_stack.pop s1 >>> Treiber_stack.push s2 Consume elements atomically Treiber_stack.pop s1 <*> Treiber_stack.pop s2 Consume elements from either Treiber_stack.pop s1 <+> Treiber_stack.pop s2 26

  59. Composability Transform arbitrary blocking reagent to a non-blocking reagent 27

  60. Composability Transform arbitrary blocking reagent to a non-blocking reagent val lift : ('a -> 'b option) -> ('a,'b) t val constant : 'a -> ('b,'a) t 27

  61. Composability Transform arbitrary blocking reagent to a non-blocking reagent val lift : ('a -> 'b option) -> ('a,'b) t val constant : 'a -> ('b,'a) t let attempt (r : ('a,'b) t) : ('a,'b option) t = (r >>> lift (fun x -> Some (Some x))) <+> (constant None) 27

  62. Composability Transform arbitrary blocking reagent to a non-blocking reagent val lift : ('a -> 'b option) -> ('a,'b) t val constant : 'a -> ('b,'a) t let attempt (r : ('a,'b) t) : ('a,'b option) t = (r >>> lift (fun x -> Some (Some x))) <+> (constant None) let try_pop stack = attempt (pop stack) 27

Recommend


More recommend