Share
Embed
Transcript
55 slides
-
• Speculative, parallel abstractions: Problem • Easy to create parallelisation
points • Hard to kill speculative computations (based on ParT) -
Problem { } { } (based on ParT) { _
} :: t → Par[t] Types -
Problem { } { } (based on ParT) { _
} :: t → Par[t] >> :: Par[t] → (t → t’)→ Par[t’] Types >> λ >> λ λ = (fun social => findUser(social, user)) -
Problem { } { } parFb parTw (based on ParT)
{ _ } :: t → Par[t] >> :: Par[t] → (t → t’)→ Par[t’] Types >> λ >> λ λ = (fun social => findUser(social, user)) -
Problem || { } { } parFb parTw (based on
ParT) { _ } :: t → Par[t] || :: Par[t] → Par[t] → Par[t] >> :: Par[t] → (t → t’)→ Par[t’] Types >> λ >> λ λ = (fun social => findUser(social, user)) -
Problem || phoneNumber << { } { } parFb parTw
(based on ParT) { _ } :: t → Par[t] || :: Par[t] → Par[t] → Par[t] >> :: Par[t] → (t → t’)→ Par[t’] Types >> λ >> λ λ = (fun social => findUser(social, user)) ≪ :: (t → Par[t’]) → Par[t] → Par[t’] -
Problem >> updateDB || phoneNumber << { } { }
parFb parTw (based on ParT) { _ } :: t → Par[t] || :: Par[t] → Par[t] → Par[t] >> :: Par[t] → (t → t’)→ Par[t’] Types >> λ >> λ λ = (fun social => findUser(social, user)) ≪ :: (t → Par[t’]) → Par[t] → Par[t’] -
Problem { } val parTw = >> (fun x =>
findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (based on ParT) -
Problem val parInf = parTw || parFb { } val
parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (based on ParT) -
Problem val parInf = parTw || parFb parTw >> updateDB
{ } val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (based on ParT) -
Problem getPhoneNumber ≪ parInf val parInf = parTw || parFb
parTw >> updateDB { } val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (based on ParT) -
Problem getPhoneNumber ≪ parInf val parInf = parTw || parFb
parTw >> updateDB { } val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (based on ParT) Aliasing prevents killing unfinished computations -
Problem getPhoneNumber ≪ parInf val parInf = parTw || parFb
parTw >> updateDB { } val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (based on ParT) When is it safe to kill computations? How to do it efficiently? Aliasing prevents killing unfinished computations -
Solution 1. Kill using thread-local reasoning 2. Leverage static information
from type system 3. No manual introduction of killing points 4. Integrated in the actor-based Encore language Limitation: Computations must be free of side effects -
Affine type system val parInf = parTw || parFb {
} val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) (parTw >> updateDB) -
Affine type system val parInf = parTw || parFb {
} val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) modes read ≊ shared lin ≊ affine fun findUser(social : lin Twitter, user : read User): read Info … end (parTw >> updateDB) -
Affine type system val parInf = parTw || parFb {
} val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) modes read ≊ shared lin ≊ affine fun findUser(social : lin Twitter, user : read User): read Info … end >> :: mode1 Par[mode2 t] → (mode2 t → mode2’ t’) → mode1’ Par[mode2’ t’] (parTw >> updateDB) -
Affine type system val parInf = parTw || parFb {
} val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) modes read ≊ shared lin ≊ affine fun findUser(social : lin Twitter, user : read User): read Info … end read Par[read Info] >> :: mode1 Par[mode2 t] → (mode2 t → mode2’ t’) → mode1’ Par[mode2’ t’] (parTw >> updateDB) -
Affine type system val parInf = parTw || parFb {
} val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) modes read ≊ shared lin ≊ affine fun findUser(social : lin Twitter, user : read User): read Info … end lin Par[read Info] read Par[read Info] >> :: mode1 Par[mode2 t] → (mode2 t → mode2’ t’) → mode1’ Par[mode2’ t’] (parTw >> updateDB) -
Affine type system val parInf = parTw || parFb {
} val parTw = >> (fun x => findUser(social, user)) { } val parFb = >> (fun x => findUserFb(social, user)) modes read ≊ shared lin ≊ affine fun findUser(social : lin Twitter, user : read User): read Info … end lin Par[read Info] read Par[read Info] lin Par[read Info] >> :: mode1 Par[mode2 t] → (mode2 t → mode2’ t’) → mode1’ Par[mode2’ t’] (parTw >> updateDB) -
>> updateDB phoneNumber << parTw { }>> λ || parFb
{ }>> λ read linear Kill using thread-local reasoning -
>> updateDB phoneNumber << parTw { }>> λ || parFb
{ }>> λ read linear Kill using thread-local reasoning -
>> updateDB phoneNumber << parTw { }>> λ || parFb
{ }>> λ read linear Kill using thread-local reasoning parTw Information from Twitter available -
>> updateDB phoneNumber << parTw { }>> λ || read
linear Kill using thread-local reasoning parTw Information from Twitter available -
>> updateDB phoneNumber << parTw { }>> λ || parFb
{ }>> λ read linear Kill using thread-local reasoning -
>> updateDB phoneNumber << parTw { }>> λ || parFb
{ }>> λ read linear Kill using thread-local reasoning parFb Information from Facebook available -
>> updateDB phoneNumber << parTw { }>> λ || parFb
{ }>> λ read linear Kill using thread-local reasoning parFb Information from Facebook available No operation -
>> updateDB λ << >> λ || read Kill using
thread-local reasoning linear linear || linear >> λ linear { } { } -
>> updateDB λ << >> λ || read Kill using
thread-local reasoning linear linear || linear >> λ linear { } { } -
>> updateDB λ << >> λ || read Kill using
thread-local reasoning linear || linear { } -
val parInf = parTw || parFb lin Par[read Info] Leverage
static information -
|| lin || lin v3 v4 || read v1 v2
parInf= val parInf = parTw || parFb lin Par[read Info] || parInst || parReddit Leverage static information -
|| lin || lin v3 v4 || read v1 v2
parInf= statically checked val parInf = parTw || parFb lin Par[read Info] || parInst || parReddit Leverage static information -
|| lin || lin v3 v4 || read v1 v2
parInf= statically checked labels change at runtime val parInf = parTw || parFb lin Par[read Info] || parInst || parReddit Leverage static information -
|| lin || lin v3 v4 || read v1 v2
parInf= statically checked labels change at runtime val parInf = parTw || parFb lin Par[read Info] || parInst || parReddit Leverage static information Translates into: - Reuse of ParT collection structure - Polymorphic dispatch -
Leverage static information - Polymorphic dispatch ParT is statically checked,
but the actual behaviour depends on the dynamic labels, which themselves may change -
Leverage static information - Polymorphic dispatch ParT is statically checked,
but the actual behaviour depends on the dynamic labels, which themselves may change -
Leverage static information - Polymorphic dispatch ParT is statically checked,
but the actual behaviour depends on the dynamic labels, which themselves may change -
|| lin || lin v3 v4 || read v1 v2
Sharing a linear reference parInf= parInf :: lin Par[read Info] Leverage static information -
|| lin || lin v3 v4 || read v1 v2
let !x = parInf in (!x >> λ) Sharing a linear reference parInf= parInf :: lin Par[read Info] Leverage static information -
|| lin || lin v3 v4 || read v1 v2
let !x = parInf in (!x >> λ) Sharing a linear reference parInf= parInf :: lin Par[read Info] !x :: read Par[read Info] !x = Leverage static information -
|| lin || lin v3 v4 || read v1 v2
let !x = parInf in (!x >> λ) Sharing a linear reference parInf= parInf :: lin Par[read Info] !x :: read Par[read Info] !x = read Leverage static information -
|| lin || lin v3 v4 || read v1 v2
let !x = parInf in (!x >> λ) Sharing a linear reference parInf= parInf :: lin Par[read Info] !x :: read Par[read Info] !x = read Leverage static information -
|| lin || lin v3 v4 || read v1 v2
let !x = parInf in (!x >> λ) Sharing a linear reference parInf= parInf :: lin Par[read Info] !x :: read Par[read Info] !x = read Leverage static information ParT is statically checked, but the actual behaviour depends on the dynamic labels, which themselves may change -
|| lin || lin v3 v4 || read v1 v2
let !x = parInf in (!x >> λ) Sharing a linear reference parInf= parInf :: lin Par[read Info] !x :: read Par[read Info] !x = read Leverage static information ParT is statically checked, but the actual behaviour depends on the dynamic labels, which themselves may change -
Integration with Encore • Actor-based language • Capability-based type system
linear subord active local Cannot escape its actor read Immutable No aliasing allowed Cannot escape its aggregate Actor, method calls return futures Restriction: A type has a single capability type -
Integration with Encore • Actor-based language • Capability-based type system
linear subord active local Cannot escape its actor read Immutable No aliasing allowed Cannot escape its aggregate Actor, method calls return futures Restriction: A type has a single capability type -
Integration with Encore • Actor-based language • Capability-based type system
linear subord active local Cannot escape its actor read Immutable No aliasing allowed Cannot escape its aggregate Actor, method calls return futures Restriction: A type has a single capability type -
Integration with Encore • Actor-based language • Capability-based type system
linear subord active local Cannot escape its actor read Immutable No aliasing allowed Cannot escape its aggregate Actor, method calls return futures Restriction: A type has a single capability type -
Work in progress • How to kill: • Proof of
soundness • Implementation • Guided by SAT solver and other benchmarks - Kill thread, actor or introduce well-defined stopping points - ParT internally relies on a task or actor running computations -
Conclusion • Killing in an affine type system: • read
(shared) references are nop • linear references can be killed • Thread-local reasoning when killing parallel computations • Leverage static information: e.g. polymorphic dispatch, in-place updates • Integration with Encore (status)