COORDINATION 2018

2df7339e6f646abdc75d6fe1e954814a?s=47 Kiko
June 20, 2018

COORDINATION 2018

2df7339e6f646abdc75d6fe1e954814a?s=128

Kiko

June 20, 2018
Tweet

Transcript

  1. Forward to a Promising Future Kiko Fernandez-Reyes, Dave Clarke, Elias

    Castegren and Huu Phuc-Vo Uppsala University, Sweden
  2. Active object B Active object A Concurrent & Parallel Programming

    • Active Objects have existed since mid-80 s = future Abbreviation: active object = actor
  3. Active object B Active object A Concurrent & Parallel Programming

    • Active Objects have existed since mid-80 s = future Abbreviation: active object = actor
  4. Active object B Active object A Concurrent & Parallel Programming

    • Active Objects have existed since mid-80 s Value = future Abbreviation: active object = actor
  5. Active object B Active object A Concurrent & Parallel Programming

    • Active Objects have existed since mid-80 s = future Abbreviation: active object = actor
  6. Motivation Many computations block on a future to get its

    result only to return that result immediately
  7. Motivation Many computations block on a future to get its

    result only to return that result immediately
  8. Motivation Many computations block on a future to get its

    result only to return that result immediately
  9. Motivation Many computations block on a future to get its

    result only to return that result immediately
  10. 1. get 2. await Motivation Many computations block on a

    future to get its result only to return that result immediately
  11. 1. get 2. await Motivation Many computations block on a

    future to get its result only to return that result immediately
  12. 1. get 2. await Motivation Many computations block on a

    future to get its result only to return that result immediately
  13. 1. get 2. await Motivation Many computations block on a

    future to get its result only to return that result immediately Interesting for behavioural design patterns:
  14. 1. get 2. await Motivation Many computations block on a

    future to get its result only to return that result immediately Interesting for behavioural design patterns: Broker Mediator Chain of responsibility PubSub
  15. Deep dive into the problem

  16. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET Responders
  17. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET Responders
  18. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 Responders
  19. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 Responders
  20. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders
  21. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET Value 1 2 Responders
  22. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders
  23. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders
  24. Broker Requesters broker!run( ) new Job(1) active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) return get(future) end end 2 1 Problem GET 1 2 Responders
  25. Broker Requesters broker!run( ) new Job(1) Problem Nothing active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders
  26. Broker Requesters broker!run( ) new Job(1) Problem Nothing active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders
  27. Broker Requesters broker!run( ) new Job(1) Problem Nothing active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders
  28. Broker Requesters broker!run( ) new Job(1) Problem Nothing active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders
  29. Broker Requesters broker!run( ) new Job(1) Problem Nothing active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders 1
  30. Broker Requesters broker!run( ) new Job(1) Problem Nothing active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): Fut int val worker = this.workers[++this.current % workers.size()] return worker!start(job) end end 1 Responders 1
  31. Broker Requesters broker!run( ) new Job(1) Problem AWAIT active class

    Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) await(future) return get(future) end end 2 1 Responders
  32. Alternatives?

  33. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 2
  34. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2
  35. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2
  36. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2
  37. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 3
  38. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 3
  39. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 3
  40. Broker Requesters broker!run(new Job(1),p) Problem Promise active class Broker val

    workers: Buffered[Worker] var current: uint def run(job: Job, prom: Promise[int]): unit val worker = this.workers[++this.current % workers.size()] worker!start(job, prom) end end 3 Responders let p = new Prom() 1 1 2 2 Value Value 3
  41. Alternatives Comparison Futures Promises Pros Static fulfilment guarantees Flexibility Cons

    Rigid No fulfilment guarantees Fulfilled multiple times?
  42. Main idea • Write future-based code with static fulfilment guarantees

    with the flexibility of promises Main idea
  43. Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(

    ) new Job(1) active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders
  44. Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(

    ) new Job(1) active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders
  45. Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(

    ) new Job(1) active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders
  46. Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(

    ) new Job(1) 1 active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders
  47. Broker Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run(

    ) new Job(1) 1 active class Broker val workers: Buffered[Worker] var current: uint def run(job: Job): int val worker = this.workers[++this.current % workers.size()] val future : Fut[int] = worker!start(job) forward(future) end end 1 Responders
  48. Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run( )

    new Job(1) Value Responders forward(x!run(..)) forward(y!run(..)) forward(z!run(..))
  49. Requesters broker.run( ) new Job(1) Explore Forward Broker broker!run( )

    new Job(1) Value Responders forward(x!run(..)) forward(y!run(..)) forward(z!run(..))
  50. Contributions • High-level (future) task-based language • Low-level promise-based language

    • Compilation strategy from high- to low-level language (proof that translation is semantics preserving) • Implementation and microbenchmarks The formalisation captures the essence of the implementation
  51. High-Level Language

  52. High-level Language g

  53. Typing rules

  54. Typing rules return type of a task • forbids the

    use of forward in contexts where the expected task type is not clear closure can be passed between tasks and run in a context different from their defining contexts
  55. Broker Runtime semantics f h

  56. Broker Runtime semantics f h

  57. Low-Level Language

  58. Low-level Language

  59. Low-level Language Forward expressed using low-level expressions

  60. Static & Dynamic rules Reduction intuition: *

  61. Static & Dynamic rules Reduction intuition: *

  62. Static & Dynamic rules Reduction intuition: *

  63. Static & Dynamic rules Reduction intuition: *

  64. Static & Dynamic rules Reduction intuition: *

  65. Static & Dynamic rules Reduction intuition: *

  66. Compilation Strategy

  67. Compilation Strategy • Inductive compilation of: 1. configurations 2. expressions

    and values 3. types
  68. Compilation Strategy Compilation of: • configurations • expressions and values

    • types
  69. Compilation Strategy Compilation of: • configurations • expressions and values

    • types
  70. Compilation Strategy Compilation of: • configurations • expressions and values

    • types e =future
  71. Compilation Strategy Compilation of: • configurations • expressions and values

    • types e =future
  72. Compilation Strategy Compilation of: • configurations • expressions and values

    • types e =future Bisimulation up-to expansion to proof that it is semantics preserving
  73. Implementation

  74. Implementation • Encore actor-based language • Compiled from Encore to

    C • Microbenchmarks Broker pattern: • get • await + get • forward
  75. Benchmark Performance (lower is better)

  76. Benchmark Performance (lower is better)

  77. Benchmark Performance (lower is better) Why?

  78. Benchmark Performance (lower is better) Why? Blocking

  79. Benchmark Performance (lower is better) Why? Blocking Context switch &

    creates more futures
  80. (lower is better) Benchmark Memory Saves the whole stack on

    each context switch Creates more futures than the forwarding version Why?
  81. More goodies in the paper

  82. More goodies in paper Standard reduction rules Optimised reduction rules

    In-depth explanation of bisimulation using a LTS More examples of: • Reduction rules • Compilation strategy • etc
  83. Conclusion

  84. Conclusion Main idea • Forward fixes: • get-and-return and •

    await-get-return Write high-level future-based code & Output low-level promise-based code with static fulfilment guarantees