/
deep_demos.jl
159 lines (135 loc) · 4.67 KB
/
deep_demos.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
149
150
151
152
153
154
155
156
157
158
"""
tinf = SnoopCompile.flatten_demo()
A simple demonstration of [`@snoopi_deep`](@ref). This demo defines a module
```julia
module FlattenDemo
struct MyType{T} x::T end
extract(y::MyType) = y.x
function packintype(x)
y = MyType{Int}(x)
return dostuff(y)
end
function domath(x)
y = x + x
return y*x + 2*x + 5
end
dostuff(y) = domath(extract(y))
end
```
It then "warms up" (forces inference on) all of Julia's `Base` methods needed for `domath`,
to ensure that these MethodInstances do not need to be inferred when we collect the data.
It then returns the results of
```julia
@snoopi_deep FlattenDemo.packintypes(1)
```
See [`flatten`](@ref) for an example usage.
"""
function flatten_demo()
eval(:(
module FlattenDemo
struct MyType{T} x::T end
extract(y::MyType) = y.x
function packintype(x)
y = MyType{Int}(x)
return dostuff(y)
end
function domath(x)
y = x + x
return y*x + 2*x + 5
end
dostuff(y) = domath(extract(y))
end
))
z = (1 + 1)*1 + 2*1 + 5
return @snoopi_deep Base.invokelatest(FlattenDemo.packintype, 1)
end
"""
tinf = SnoopCompile.itrigs_demo()
A simple demonstration of collecting inference triggers. This demo defines a module
```julia
module ItrigDemo
@noinline double(x) = 2x
@inline calldouble1(c) = double(c[1])
calldouble2(cc) = calldouble1(cc[1])
calleach(ccs) = (calldouble2(ccs[1]), calldouble2(ccs[2]))
end
```
It then "warms up" (forces inference on) `calldouble2(::Vector{Vector{Any}})`, `calldouble1(::Vector{Any})`, `double(::Int)`:
```julia
cc = [Any[1]]
ItrigDemo.calleach([cc,cc])
```
Then it collects and returns inference data using
```julia
cc1, cc2 = [Any[0x01]], [Any[1.0]]
@snoopi_deep ItrigDemo.calleach([cc1, cc2])
```
This does not require any new inference for `calldouble2` or `calldouble1`, but it does force inference on `double` with two new types.
See [`inference_triggers`](@ref) to see what gets collected and returned.
"""
function itrigs_demo()
eval(:(
module ItrigDemo
@noinline double(x) = 2x
@inline calldouble1(c) = double(c[1])
calldouble2(cc) = calldouble1(cc[1])
calleach(ccs) = (calldouble2(ccs[1]), calldouble2(ccs[2]))
end
))
# Call once to infer `calldouble2(::Vector{Vector{Any}})`, `calldouble1(::Vector{Any})`, `double(::Int)`
cc = [Any[1]]
Base.invokelatest(ItrigDemo.calleach, [cc,cc])
# Now use UInt8 & Float64 elements to force inference on double, without forcing new inference on its callers
cc1, cc2 = [Any[0x01]], [Any[1.0]]
return @snoopi_deep Base.invokelatest(ItrigDemo.calleach, [cc1, cc2])
end
"""
tinf = SnoopCompile.itrigs_higherorder_demo()
A simple demonstration of handling higher-order methods with inference triggers. This demo defines a module
```julia
module ItrigHigherOrderDemo
double(x) = 2x
@noinline function mymap!(f, dst, src)
for i in eachindex(dst, src)
dst[i] = f(src[i])
end
return dst
end
@noinline mymap(f::F, src) where F = mymap!(f, Vector{Any}(undef, length(src)), src)
callmymap(src) = mymap(double, src)
end
```
The key feature of this set of definitions is that the function `double` gets passed as an argument
through `mymap` and `mymap!` (the latter are [higher-order functions](https://en.wikipedia.org/wiki/Higher-order_function)).
It then "warms up" (forces inference on) `callmymap(::Vector{Any})`, `mymap(::typeof(double), ::Vector{Any})`,
`mymap!(::typeof(double), ::Vector{Any}, ::Vector{Any})` and `double(::Int)`:
```julia
ItrigHigherOrderDemo.callmymap(Any[1, 2])
```
Then it collects and returns inference data using
```julia
@snoopi_deep ItrigHigherOrderDemo.callmymap(Any[1.0, 2.0])
```
which forces inference for `double(::Float64)`.
See [`skiphigherorder`](@ref) for an example using this demo.
"""
function itrigs_higherorder_demo()
eval(:(
module ItrigHigherOrderDemo
double(x) = 2x
@noinline function mymap!(f, dst, src)
for i in eachindex(dst, src)
dst[i] = f(src[i])
end
return dst
end
@noinline mymap(f::F, src) where F = mymap!(f, Vector{Any}(undef, length(src)), src)
callmymap(src) = mymap(double, src)
end
))
# Call once to infer `callmymap(::Vector{Any})`, `mymap(::typeof(double), ::Vector{Any})`,
# `mymap!(::typeof(double), ::Vector{Any}, ::Vector{Any})` and `double(::Int)`
Base.invokelatest(ItrigHigherOrderDemo.callmymap, Any[1, 2])
src = Any[1.0, 2.0] # double not yet inferred for Float64
return @snoopi_deep Base.invokelatest(ItrigHigherOrderDemo.callmymap, src)
end