When I time a function using TimerOutputs.jl’s @timeit, I get broken stacktraces when there is a compilation error inside the called function.
Example:
@timeit to "mesh loading" mesh = load_mesh(restart_filename)
yields something like
Loading mesh... ERROR: LoadError: MethodError: no method matching Val{1}(::Int64)
Closest candidates are:
Val{1}() where x at essentials.jl:693
Stacktrace:
[1] load_mesh(::String) at /home/user/.julia/packages/TimerOutputs/7Id5J/src/TimerOutput.jl:214
[2] macro expansion at /home/user/.julia/packages/TimerOutputs/7Id5J/src/TimerOutput.jl:214 [inlined]
[3] run() at /home/user/code/src/main.jl:32
...
That is, while [3] still points to the correct source location, [2] and [1] return useless information, making errors hard to track down unless I remove the @timeit macro (which may be non-trivial if there are nested macro uses). What can I do to get proper error information from within macros? I found this seemingly related issue, but I guess it does not apply to my case: Corrupt linenumber in stacktraces for functions with macros · Issue #28618 · JuliaLang/julia · GitHub
Instead of :(...) you can try @q(...) from MacroTools.
help?> MacroTools.@q
@q [expression]
Like the quote keyword but doesn't insert line numbers from the construction
site. e.g. compare @q begin end with quote end. Line numbers of interpolated
expressions are preserverd.
If there is any way I can help, though, please let me know. We are using @timeit to both identify and optimize hotspots, and the combination of run time and allocations is just perfect for that.
No, it actually is my example (although your example might have similar issues ). Here’s an MWE:
mwe.jl:
using TimerOutputs
function foo(::Float64) end
@timeit "foo" foo(1)
Running julia mwe.jl then yields
ERROR: LoadError: MethodError: no method matching foo(::Int64)
Closest candidates are:
foo(::Float64) at /path/to/mwe.jl:3
Stacktrace:
[1] top-level scope at /home/user/.julia/packages/TimerOutputs/7Id5J/src/TimerOutput.jl:214
[2] include at ./boot.jl:328 [inlined]
[3] include_relative(::Module, ::String) at ./loading.jl:1105
[4] include(::Module, ::String) at ./Base.jl:31
[5] exec_options(::Base.JLOptions) at ./client.jl:287
[6] _start() at ./client.jl:460
in expression starting at /path/to/mwe.jl:5
However, while constructing this MWE, I came across another (probably unrelated error) that I have encountered before: If I change the first line of mwe.jl to using TimerOutputs: @timeit, I get the following error:
ERROR: LoadError: UndefVarError: TimerOutputs not defined
Stacktrace:
[1] top-level scope at /home/user/.julia/packages/TimerOutputs/7Id5J/src/TimerOutput.jl:210
[2] include at ./boot.jl:328 [inlined]
[3] include_relative(::Module, ::String) at ./loading.jl:1105
[4] include(::Module, ::String) at ./Base.jl:31
[5] exec_options(::Base.JLOptions) at ./client.jl:287
[6] _start() at ./client.jl:460
in expression starting at /path/to/mwe.jl:5
I am not an expert in Julia, but from intuition I feel that if I make available all symbols that I am using in my user code through using/import, I should not get any errors about undefined symbols.