Often it is convenient to have inner functions, eg for functional ones like mapreduce. How can I apply code inspection macros like @code_llvm or @code_warntype to the “full” function?
Example:
julia> function test(a)
inner() = a + 3
inner()
end
test (generic function with 1 method)
julia> @code_warntype test(3)
Variables
#self#::Core.Const(test)
a::Int64
inner::var"#inner#1"{Int64}
Body::Int64
1 ─ %1 = Main.:(var"#inner#1")::Core.Const(var"#inner#1")
│ %2 = Core.typeof(a)::Core.Const(Int64)
│ %3 = Core.apply_type(%1, %2)::Core.Const(var"#inner#1"{Int64})
│ (inner = %new(%3, a))
│ %5 = (inner)()::Int64
└── return %5
In that case, I can see that inner returns Int64. But when inner is more complex, it can still have type problems even when the final return type is inferred ok. Also, when one wants to inspect the generated code, how can one do this?
One way would be to use the debugger, put a breakpoint right after the definition of the inner function and use @code_warntype from within the debugger.
In practice, I tend to use a more hacky way: manually “exflitrate” the inner function in the global scope, so that it can be inspected from the REPL:
julia> function test(a)
inner() = a + 3
global TEST_INNER=inner
inner()
end
test (generic function with 1 method)
julia> test(3)
6
julia> @code_warntype TEST_INNER()
MethodInstance for (::var"#inner#1"{Int64})()
from (::var"#inner#1")() in Main at REPL[1]:2
Arguments
#self#::var"#inner#1"{Int64}
Body::Int64
1 ─ %1 = Core.getfield(#self#, :a)::Int64
│ %2 = (%1 + 3)::Int64
└── return %2
But none of this entirely satisfies me (*), so I’m also interested in what others have to say about this: maybe there is some tooling that I don’t know about…
(*) one thing that bothers me in particular is that both those techniques require the outer function to actually be executed
As far as I understand that is what Cthulhu.jl is for?
OK, so maybe I should elaborate: I tried Cthulhu in the past and it seems to me pretty intimidating, a manual process similar to the use of the debugger @ffevotte is describing. So this would be some kind of last resort for me.
I prefer to using a profiler and JET.jl to spot irregularities.
As to the other questions: there are @code_typed, @code_lowered, @code_llvm and @code_native which allow to inspect the whole compilation pipeline.