-
Notifications
You must be signed in to change notification settings - Fork 2
/
scheduling.jl
148 lines (123 loc) · 4.44 KB
/
scheduling.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
using UnicodePlots
const STEPS_PER_ROUND=1e6
# ---- Sample code simplified from the original use case of this jit optimizer (CircoCore.jl) ----
#
# This is an actor scheduler, where the hot loop is parametrized with code,
# and the distribution of dispatched concrete types depends on the actor program
# that is executed.
struct Addr
box::UInt64
end
abstract type Actor{Tcore} end
struct Msg{TBody}
target::Addr
body::TBody
end
target(msg) = msg.target
abstract type AbstractScheduler{TMsg, TCoreState} end
mutable struct Scheduler{THooks, TMsg, TCoreState} <: AbstractScheduler{TMsg, TCoreState}
msgqueue::Vector{Any}
actorcache::Dict{UInt64,Any}
hooks::THooks
Scheduler{T}() where T = new{T,T,T}([], Dict())
end
@jit step_kern1! (msg) function step!(scheduler::AbstractScheduler, jitctx=Catwalk.OptimizerCtx())
msg = popfirst!(scheduler.msgqueue) # get the next message
step_kern1!(msg, scheduler, jitctx) # and deliver it (Catwalked call on message type)
return nothing
end
# Kernel function to stabilize message type first. Gets the target actor and delivers the message
@inline @jit step_kern! (targetactor) function step_kern1!(msg, scheduler::AbstractScheduler, jitctx)
targetbox = target(msg).box::UInt64
targetactor = get(scheduler.actorcache, targetbox, nothing)
step_kern!(scheduler, msg, targetactor) # Catwalked call on actor type
end
@inline function step_kern!(scheduler::AbstractScheduler, msg, targetactor)
onmessage(targetactor, msg.body, scheduler)
end
@inline function onmessage(actor, msg, scheduler)
error("This should never happen.") # escape route for monkey-patching and co.
end
# --- Non-jitted version for comparison
@inline function step_nojit!(scheduler::AbstractScheduler)
msg = popfirst!(scheduler.msgqueue)
step_kern1_nojit!(msg, scheduler)
return nothing
end
@inline function step_kern1_nojit!(msg, scheduler::AbstractScheduler)
targetbox = target(msg).box::UInt64
targetactor = get(scheduler.actorcache, targetbox, nothing)
step_kern!(scheduler, msg, targetactor)
end
mutable struct PingPonger{TCore} <: Actor{TCore}
addr::Addr
core::TCore # boilerplate, should be eliminated by a dsl
end
struct Ping end
struct Pong end
for i=1:10
name = Symbol(string("Body", i))
eval(:(struct $name end))
eval(quote
@inline function onmessage(actor, msg::$(name), scheduler)
print($name)
end
end)
end
@inline function onmessage(actor, msg::Pong, scheduler)
push!(scheduler.msgqueue, Msg{Ping}(actor.addr, Ping()))
end
@inline function onmessage(actor, msg::Ping, scheduler)
push!(scheduler.msgqueue, Msg{Pong}(actor.addr, Pong()))
end
function run_steps(scheduler, ctx=Catwalk.OptimizerCtx(); num=STEPS_PER_ROUND)
for i=1:num
step!(scheduler, ctx)
end
end
function measure_steps(scheduler, opt; num=STEPS_PER_ROUND)
startts = time_ns()
Catwalk.step!(opt)
run_steps(scheduler, Catwalk.ctx(opt))
return time_ns() - startts
end
function measure_steps_nojit!(scheduler; num=STEPS_PER_ROUND)
startts = time_ns()
for i=1:num
step_nojit!(scheduler)
end
return time_ns() - startts
end
const scheduler = Scheduler{Set}()
scheduler.actorcache[42] = PingPonger{Dict}(Addr(42), Dict())
for i=1:10
body = eval(:($(Symbol(string("Body", i)))))
push!(scheduler.msgqueue, Msg{body}(Addr(42), body()))
end
push!(scheduler.msgqueue, Msg{Ping}(Addr(42), Ping()))
@testset "ping-pong" begin
msgcallboost = Catwalk.CallBoost(:step_kern1!, profilestrategy = Catwalk.SparseProfile(0.02))
actorcallboost = Catwalk.CallBoost(:step_kern!, profilestrategy = Catwalk.SparseProfile(0.01))
optimizer = JIT(;explorerfactory=Catwalk.NoExplorer)
Catwalk.add_boost!(optimizer, msgcallboost)
Catwalk.add_boost!(optimizer, actorcallboost)
normaltime = 0
jittedtime = 0
for i=1:300
println("------ Catwalk round #$(i): -------")
jittedtime += measure_steps(scheduler, optimizer)
normaltime += measure_steps_nojit!(scheduler)
println(barplot(
["Catwalked", "original"],
[jittedtime / 1e9, normaltime / 1e9];
title="Runtime"
))
win = 1.0 - (jittedtime / normaltime)
winpercent = round(win * 100_000) / 1000
println("Win: $(winpercent)%.")
print(repeat("\n", 10))
print(repeat("\u1b[1F", 10))
end
win = 1.0 - (jittedtime / normaltime)
@test win > 0.1
end