Skip to content

Commit fed3fc9

Browse files
committed
the timer example is working for the first time
1 parent ace5330 commit fed3fc9

File tree

2 files changed

+222
-9
lines changed

2 files changed

+222
-9
lines changed

docs/src/lecture_09/lecture.md

Lines changed: 94 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -241,32 +241,117 @@ julia> retrieve_code_info((typeof(foo), Float64, Float64)).slotnames
241241
This allows to convert the names back to the original. Let's create a dictionary of assignments
242242
as
243243
```julia
244-
fun_vars = Dict(enumerate(ci.slotnames))
245-
lower_vars = Dict(i => gensym(:left) for i in 1:length(ci.code))
246-
247-
rename_args(ex::Expr, fun_vars, lower_vars) = Expr(ex.head, rename_args(ex.args, fun_vars, lower_vars))
248-
rename_args(args::AbstractArray, fun_vars, lower_vars) = map(a -> rename_args(a, fun_vars, lower_vars), args)
249-
rename_args(a::Core.SlotNumber, fun_vars, lower_vars) = lower_vars[a.id]
250-
rename_args(a::Core.SSAValue, fun_vars, lower_vars) = fun_vars[a.id]
244+
slot_vars = Dict(enumerate(ci.slotnames))
245+
# ssa_vars = Dict(i => gensym(:left) for i in 1:length(ci.code))
246+
ssa_vars = Dict(i => Symbol(:L,i) for i in 1:length(ci.code))
247+
248+
rename_args(ex, slot_vars, ssa_vars) = ex
249+
rename_args(ex::Expr, slot_vars, ssa_vars) = Expr(ex.head, rename_args(ex.args, slot_vars, ssa_vars)...)
250+
rename_args(args::AbstractArray, slot_vars, ssa_vars) = map(a -> rename_args(a, slot_vars, ssa_vars), args)
251+
rename_args(r::Core.ReturnNode, slot_vars, ssa_vars) = Core.ReturnNode(rename_args(r.val, slot_vars, ssa_vars))
252+
rename_args(a::Core.SlotNumber, slot_vars, ssa_vars) = slot_vars[a.id]
253+
rename_args(a::Core.SSAValue, slot_vars, ssa_vars) = ssa_vars[a.id]
251254
```
252255
and let's redo the rewriting once more while replacing the variables and inserting the left-hand equalities
256+
```julia
257+
slot_vars = Dict(enumerate(ci.slotnames))
258+
# ssa_vars = Dict(i => gensym(:left) for i in 1:length(ci.code))
259+
ssa_vars = Dict(i => Symbol(:L,i) for i in 1:length(ci.code))
253260
exprs = []
254261
for (i, ex) in enumerate(ci.code)
255-
ex = rename_args(ex, fun_vars, lower_vars)
262+
ex = rename_args(ex, slot_vars, ssa_vars)
256263
if !overdubbable(ctx, ex)
257264
push!(exprs, ex)
258265
continue
259266
end
260267
if timable(ctx, ex)
261268
push!(exprs, Expr(:call, :push!, :to, :start, ex.args[1]))
262269
#ex = Expr(ex.head, :overdub, :ctx, ex.args...)
263-
#push!(exprs, :($(lower_vars[i]) = $(ex))
270+
#push!(exprs, :($(ssa_vars[i]) = $(ex))
264271
push!(exprs, Expr(ex.head, :overdub, :ctx, ex.args...))
265272
push!(exprs, Expr(:call, :push!, :to, :stop, ex.args[1]))
266273
else
267274
push!(exprs, ex)
268275
end
269276
end
277+
Expr(:block, exprs...)
278+
```
279+
The last trouble we are facing is that there are not assigning the lefthandside variables. This is certainly troublesome and needs to be fixed. We can either blindly assign all variables including those, which are never used or collect those, which will be used and assign only those. We will choose the latter one, as it is indeed "nicer". We first define bunch of variables that traverses expressions and assigns them
280+
```julia
281+
assigned_vars(ex) = []
282+
assigned_vars(ex::Expr) = assigned_vars(ex.args)
283+
assigned_vars(args::AbstractArray) = mapreduce(assigned_vars, vcat, args)
284+
assigned_vars(r::Core.ReturnNode) = assigned_vars(r.val)
285+
assigned_vars(a::Core.SlotNumber) = []
286+
assigned_vars(a::Core.SSAValue) = [a.id]
287+
```
288+
and then add the assignement to our code where needed
289+
```julia
290+
using Dictionaries
291+
slot_vars = Dict(enumerate(ci.slotnames))
292+
# ssa_vars = Dict(i => gensym(:left) for i in 1:length(ci.code))
293+
ssa_vars = Dict(i => Symbol(:L,i) for i in 1:length(ci.code))
294+
used = assigned_vars(ci.code) |> distinct
295+
exprs = []
296+
for (i, ex) in enumerate(ci.code)
297+
ex = rename_args(ex, slot_vars, ssa_vars)
298+
if !overdubbable(ctx, ex)
299+
ex = i used ? Expr(:(=) , ssa_vars[i], ex) : ex
300+
push!(exprs, ex)
301+
continue
302+
end
303+
if timable(ctx, ex)
304+
push!(exprs, Expr(:call, :push!, :to, :start, ex.args[1]))
305+
ex = Expr(ex.head, :overdub, :ctx, ex.args...)
306+
ex = i used ? Expr(:(=) , ssa_vars[i], ex) : ex
307+
push!(exprs, ex)
308+
push!(exprs, Expr(:call, :push!, :to, :stop, ex.args[1]))
309+
else
310+
push!(exprs, ex)
311+
end
312+
end
313+
Expr(:block, exprs...)
314+
```
315+
316+
317+
```julia
318+
@generated function overdub(ctx::Context, f::F, args...) where {F}
319+
@show (F, args...)
320+
ci = retrieve_code_info((F, args...))
321+
slot_vars = Dict(enumerate(ci.slotnames))
322+
# ssa_vars = Dict(i => gensym(:left) for i in 1:length(ci.code))
323+
ssa_vars = Dict(i => Symbol(:L,i) for i in 1:length(ci.code))
324+
used = assigned_vars(ci.code) |> distinct
325+
exprs = []
326+
for (i, ex) in enumerate(ci.code)
327+
ex = rename_args(ex, slot_vars, ssa_vars)
328+
if !overdubbable(ex)
329+
ex = i used ? Expr(:(=) , ssa_vars[i], ex) : ex
330+
push!(exprs, ex)
331+
continue
332+
end
333+
if timable(ex)
334+
push!(exprs, Expr(:call, :push!, :to, :start, ex.args[1]))
335+
ex = Expr(ex.head, :overdub, :ctx, ex.args...)
336+
ex = i used ? Expr(:(=) , ssa_vars[i], ex) : ex
337+
push!(exprs, ex)
338+
push!(exprs, Expr(:call, :push!, :to, :stop, ex.args[1]))
339+
else
340+
push!(exprs, ex)
341+
end
342+
end
343+
Expr(:block, exprs...)
344+
end
345+
```
346+
347+
```
348+
macro meta(ex)
349+
isexpr(ex, :call) || error("@meta f(args...)")
350+
f, args = ex.args[1], ex.args[2:end]
351+
:(meta(typesof($(esc.((f, args...))...))))
352+
end
353+
```
354+
270355
271356
```julia
272357
macro timeit(ex::Expr)

docs/src/lecture_09/timer.jl

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Generated functions
2+
using Dictionaries
3+
function retrieve_code_info(sigtypes, world = Base.get_world_counter())
4+
S = Tuple{map(s -> Core.Compiler.has_free_typevars(s) ? typeof(s.parameters[1]) : s, sigtypes)...}
5+
_methods = Base._methods_by_ftype(S, -1, world)
6+
isempty(_methods) && @error("method $(sigtypes) does not exist, may-be run it once")
7+
type_signature, raw_static_params, method = _methods[1] # method is the same as we would get by invoking methods(+, (Int, Int)).ms[1]
8+
9+
# this provides us with the CodeInfo
10+
method_instance = Core.Compiler.specialize_method(method, type_signature, raw_static_params, false)
11+
code_info = Core.Compiler.retrieve_code_info(method_instance)
12+
end
13+
14+
struct Calls
15+
stamps::Vector{Float64} # contains the time stamps
16+
event::Vector{Symbol} # name of the function that is being recorded
17+
startstop::Vector{Symbol} # if the time stamp corresponds to start or to stop
18+
i::Ref{Int}
19+
end
20+
21+
function Calls(n::Int)
22+
Calls(Vector{Float64}(undef, n+1), Vector{Symbol}(undef, n+1), Vector{Symbol}(undef, n+1), Ref{Int}(0))
23+
end
24+
25+
function Base.show(io::IO, calls::Calls)
26+
for i in 1:calls.i[]
27+
println(io, calls.stamps[i] - calls.stamps[1]," ", calls.startstop[i]," ",calls.event[i])
28+
end
29+
end
30+
31+
function Base.push!(calls::Calls, s::Symbol, ev::Symbol)
32+
n = calls.i[] = calls.i[] + 1
33+
n > length(calls.stamps) && return
34+
calls.event[n] = ev
35+
calls.startstop[n] = s
36+
calls.stamps[n] = time()
37+
end
38+
39+
reset!(calls::Calls) = calls.i[] = 0
40+
41+
global to = Calls(100)
42+
43+
44+
struct Context{T<:Union{Nothing, Vector{Symbol}}}
45+
functions::T
46+
end
47+
Context() = Context(nothing)
48+
49+
ctx = Context()
50+
51+
function overdubbable(ex::Expr)
52+
ex.head != :call && return(false)
53+
length(ex.args) < 2 && return(false)
54+
(ex.args[1] isa Core.IntrinsicFunction) && return(false)
55+
return(true)
56+
end
57+
overdubbable(ex::Expr) = false
58+
overdubbable(ex) = false
59+
# overdubbable(ctx::Context, ex::Expr) = ex.head == :call
60+
# overdubbable(ctx::Context, ex) = false
61+
# timable(ctx::Context{Nothing}, ex) = true
62+
timable(ex::Expr) = ex.head == :call
63+
timable(ex) = false
64+
65+
function foo(x, y)
66+
z = x * y
67+
z + sin(y)
68+
end
69+
70+
rename_args(ex, slot_vars, ssa_vars) = ex
71+
rename_args(ex::Expr, slot_vars, ssa_vars) = Expr(ex.head, rename_args(ex.args, slot_vars, ssa_vars)...)
72+
rename_args(args::AbstractArray, slot_vars, ssa_vars) = map(a -> rename_args(a, slot_vars, ssa_vars), args)
73+
rename_args(r::Core.ReturnNode, slot_vars, ssa_vars) = Core.ReturnNode(rename_args(r.val, slot_vars, ssa_vars))
74+
rename_args(a::Core.SlotNumber, slot_vars, ssa_vars) = slot_vars[a.id]
75+
rename_args(a::Core.SSAValue, slot_vars, ssa_vars) = ssa_vars[a.id]
76+
77+
assigned_vars(ex) = []
78+
assigned_vars(ex::Expr) = assigned_vars(ex.args)
79+
assigned_vars(args::AbstractArray) = mapreduce(assigned_vars, vcat, args)
80+
assigned_vars(r::Core.ReturnNode) = assigned_vars(r.val)
81+
assigned_vars(a::Core.SlotNumber) = []
82+
assigned_vars(a::Core.SSAValue) = [a.id]
83+
84+
exportname(ex::GlobalRef) = ex.name
85+
exportname(ex::Expr) = ex.args[1]
86+
87+
overdub(ctx::Context, f::Core.IntrinsicFunction, args...) = f(args...)
88+
89+
@generated function overdub(ctx::Context, f::F, args...) where {F}
90+
ci = retrieve_code_info((F, args...))
91+
slot_vars = Dict(enumerate(ci.slotnames))
92+
# ssa_vars = Dict(i => gensym(:left) for i in 1:length(ci.code))
93+
ssa_vars = Dict(i => Symbol(:L,i) for i in 1:length(ci.code))
94+
used = assigned_vars(ci.code) |> distinct
95+
exprs = []
96+
for i in 1:length(args)
97+
push!(exprs, Expr(:(=), ci.slotnames[i+1], :(args[$(i)])))
98+
end
99+
for (i, ex) in enumerate(ci.code)
100+
@show ex
101+
if ex isa Core.ReturnNode
102+
push!(exprs, Expr(:return, rename_args(ex.val, slot_vars, ssa_vars)))
103+
continue
104+
end
105+
ex = rename_args(ex, slot_vars, ssa_vars)
106+
if timable(ex)
107+
fname = exportname(ex)
108+
fname = :(Symbol($(fname)))
109+
push!(exprs, Expr(:call, :push!, :to, :(:start), fname))
110+
ex = overdubbable(ex) ? Expr(:call, :overdub, :ctx, ex.args...) : ex
111+
ex = i used ? Expr(:(=) , ssa_vars[i], ex) : ex
112+
push!(exprs, ex)
113+
push!(exprs, Expr(:call, :push!, :to, :(:stop), fname))
114+
else
115+
push!(exprs, ex)
116+
end
117+
end
118+
r = Expr(:block, exprs...)
119+
@show r
120+
# println(" ")
121+
r
122+
end
123+
124+
reset!(to)
125+
overdub(ctx, foo, 1.0, 1.0)
126+
127+
128+
ctx = Context()

0 commit comments

Comments
 (0)