-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@time macro can have huge error #39760
Comments
Have you checked whether the same happens in 1.5? If it does, it could be that execution time is dominated by interpretation, given |
Well, measuring the time is simple: Record the start time and the end time and calculate the difference. If the @time macro is not doing that, then it has a major design flaw that should be fixed. Just my two cents... |
Yeah, it's a fair point. There has been some efforts to fix it #37938 It's not clear if your issue is specific to 1.6 though, and it's still just a guess that missing |
More or less the same results when using @Elapsed:
|
Ok. Seems like it's an issue of missing the top-level compilation, and not specific to 1.6 I may open an issue to specifically track |
Why do we force-compile Line 202 in 3129a5b
So presumably what's happening is this:
So It seems like commenting-out the |
CC @vtjnash, any thoughts? |
I did the same test on Julia 1.5.3:
This means the error is a factor of 2.7 on Julia 1.5.3 and a factor of 4.33 on Julia 1.6.0rc1 . |
As far as I see there are two options to fix this issue: What are the advantages and disadvantages of these two possible fixes? |
Some testing on master julia> @eval function f(a) # Expensive function to compile. From https://github.com/JuliaLang/julia/pull/37678#discussion_r495515401
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:100]...) end)
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:100]...) end)
return a
end
f (generic function with 1 method)
julia> @time f(2)
0.000000 seconds
-3.706395705243192e209
julia> @time x = 1
0.000000 seconds
1
julia> Revise.track(Base)
## `while false; end` removed from @time
julia> @time 1 # Let Revise recompile @time itself given change (the % overflow is excusable here)
0.000001 seconds (30 allocations: 2.188 KiB, 196153.24% compilation time)
1
julia> @eval function f(a) # Note the slight change to indices
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:101]...) end)
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:101]...) end)
return a
end
f (generic function with 1 method)
julia> @time f(2)
0.896492 seconds (1.54 M allocations: 65.063 MiB, 1.47% gc time, 100.00% compilation time)
-3.063136946481976e207
julia> @time x = 1
0.000001 seconds (6 allocations: 192 bytes)
1 So it's necessary to make allocations accurate. If we remove the |
Sounds good. But this: |
I take it you missed the comment above it. |
Indeed, I missed the comment. |
That's not the point. Recompiling |
Maybe that's not going to work
|
Well, we can subtract 6 and 192 and set it to zero if it is negative ... |
@ufechner7 would you mind trying out #39779 to see if that kind of report helps? |
Yes, but how can I check it out? I tried:
|
|
|
I did:
updated the registry, instantiated the KiteViewer project,
and executed
Conclusion: Problem not solved. Did I check out the wrong branch/ pullrequest?
|
You probably need to call |
No, just julia is good enough:
|
Sorry, I stand corrected |
That branch is far from well tested, but if it is top-level compilation, I believe you should be seeing the julia> using TickTock
julia> @eval function f(a)
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:400]...) end)
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:400]...) end)
return a
end
f (generic function with 1 method)
julia> begin
tick();tock()
tick()
@time f(2)
tock()
end
[ Info: started timer at: 2021-02-22T09:30:57.712
[ Info: 0.000112848s: empty period
[ Info: started timer at: 2021-02-22T09:30:57.713
0.000000 seconds + 1.7 seconds of top-level compilation
[ Info: 0.000205973s: empty period but notice that in this case top-level compilation isn't affecting the @ufechner7 perhaps something else is going on with your code. Could you try replacing Or perhaps replace |
I tried your example after deleteing startup.jl.
So I think we are not testing the same Julia. Can you please double check the way I checked out your code? |
Looks like you're on the correct commit hash. Your computer might just be faster than mine and doing the top-level compilation faster than 0.5 seconds, which is the cutoff in that PR (which may be a bad design decision given this kind of confusion!). In the example function try increasing the |
Not much difference: ufechner@TUD277255:~/repos/KiteViewer$ julia --project
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.7.0-DEV.583 (2021-02-21)
_/ |\__'_|_|_|\__'_| | topleveloverhead/cf1226e55d* (fork: 1 commits, 1 day)
|__/ |
julia> using TickTock
julia> @eval function f(a)
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:2000]...) end)
$(quote $([:(a = a + a * 10 + (a > 0 ? $i : 0.2)) for i in 1:2000]...) end)
return a
end
f (generic function with 1 method)
julia> begin
tick();tock()
tick()
@time f(2)
tock()
end
[ Info: started timer at: 2021-02-22T18:42:59.924
[ Info: 0.288659268s: 288 milliseconds
[ Info: started timer at: 2021-02-22T18:43:00.270
0.000000 seconds
[ Info: 6.8015e-5s: empty period
julia>
|
I am not using Revise in the moment ... In case it matters: I am using:
|
As folks here figured out, this originated mostly in wanting accurate allocation counts, and because most people want |
I disagree with this. In my opinion, |
It seems odd to me to want
to give a very different result from
|
Is it that strange though? I think it would be nice to easily get both numbers, considering they represent different things. Moreover, I think it's pretty weird to see |
It is easy to get both numbers: |
I didn't know that trick! That seems like the solution.. Should we wrap it into |
From my point of view it would then be more logical to have an From software engineering I like POLA: Principle of Least Astonishment. Don't violate that. |
I can confirm that
The above was run on Julia 1.6rc1. |
But which time is |
The elapsed time of the execution of the given expression, after the compiler has done whatever it can and after any other setup overhead. So the reported compilation time is extra compilation that had to be done at run time since it could not be predicted in advance. That's arguably useful, since it tells you something about how statically-compileable your code is. |
It's not terribly difficult to capture both with a single call: macro toptime(ex)
val = gensym("val")
ex = quote
while false; end # compiler heuristic: compile this block (alter this if the heuristic changes)
local stats = Base.gc_num()
local compile_elapsedtime = Base.cumulative_compile_time_ns_before()
local elapsedtime = time_ns()
$val = $(esc(ex))
elapsedtime = time_ns() - elapsedtime
compile_elapsedtime = Base.cumulative_compile_time_ns_after() - compile_elapsedtime
local diff = Base.GC_Diff(Base.gc_num(), stats)
Base.time_print(elapsedtime, diff.allocd, diff.total_time, Base.gc_alloc_count(diff), compile_elapsedtime, true)
end
touter = gensym("touter")
Expr(:toplevel, :($touter = time_ns()), ex, quote
$touter = time_ns() - $touter
println("outer time: ", $touter/1e9)
$val
end)
end But this can only be used from toplevel. Unless there's another way to split an expression that says "compile this block but not this one"? |
I tested the macro toptime:
Printing could be approved, and not so sure about the accuracy. But in principle it works. @time @eval gives much higher allocations, though:
Also not clear to me: I am using already a custom sysimage and the same function Utils.test(true) was also called from PackageCompiler. Why is the outer time nevertheless so high? |
There does seem to be a bizarre lag. I can't take time to figure it out now; I like the idea of advertising the |
I'd be up opening a PR on that. Perhaps not worth worrying too much about 0.02% but it's the first time I've seen the comp time report be > 100% (and not be a overflow error)
|
I can reproduce your result for |
@ufechner7 Please use backticks to quote macros |
Done. |
Bump! There is a pull request to improve the documentation. Can this become part of Julia 1.6, please? |
#39802 is now in 1.6.0. Perhaps the issue can remain open to see how people get on with the |
We had a discussion here and the trick solved the mystery for me. Only unusual observation is that not all tester confirmed the problem. Could it be platform specific (in this case only Windows)? |
I guess we can close this now -- the |
Steps to reproduce:
And then execute the test:
Result:
This means that the
@time
macro reports a time that is more than a factor of four lower then the real execution time.The same problem happens without using a custom sysimage, but the relative error is smaller (8s vs 5s).
This are times that I can measure with my stopwatch, so I can confirm that the time reported by
tick and tock is much closer to the real time than the time reported by the
@time
macro.I would consider any error of more then 10% as a bug, in particular if the measured time is above 1s.
Any comment?
The text was updated successfully, but these errors were encountered: