-
-
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
Show any compile time spent in time and timev macros #37678
Show any compile time spent in time and timev macros #37678
Conversation
This will be a great feature to have! |
I agree; this seems like a great idea to help understand where time is being spent. |
Question: for the cases in which there was no compilation, does it make sense to print My instinct is that it would be unnecessary. But I just wanted to throw the idea out there. |
I have an uncommitted macro to return the actual value in seconds, if it's useful? I wasn't sure given the dedicated more detailed timing information that's available as a build option
|
Also, is it too late to get this feature into 1.6? I have lost track of time and I have no idea when the feature freeze deadline is for 1.6. Personally I hope we can get this into 1.6. |
Nah... I don't think I can come up with a use case in which I would ask for this. I think the approach you currently have in this PR is more useful. |
I think it's useful to be able to easily access that info (say, as part of CI to test that compile time didn't explode), but maybe it could be part of |
I thought about adding it to the end of the output of |
True, good question. In #34149 it was made a |
wrt.
Edit: This is actually an inaccurate approach for timing compilation, as discussed below |
I guess needs review by @vtjnash / @JeffBezanson ? |
I've added the |
This reverts commit 5747bb4.
Friendly bump for review/merge 🙏 Note that the additional function add has been reverted |
@yuyichao Is this ready to go? |
I can’t assign reviewers, so if this needs more review can someone please assign the appropriate people |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can probably use a bit more mention in the doc and the C++ code can also use +=
to be a bit more concise. Neither of these are blocking issues for the PR.
Good point. The docstring now reads:
A macro to execute an expression, printing the time it took to execute, the number of See also !!! note
|
@ianshmean Perhaps you could also add a compilation time example to the docstring for the |
Should be good to go now |
Needs whitespace fix. |
Failures seem unrelated? |
🎉 |
As discussed in the comments for JuliaLang#37678, the `% compilation time` metric added to `@time` is not an accurate measurement of the total compilation time. It is in fact excluding any top-level compilation time, which may in fact be quite expensive if the body of your block is fully type stable and inferrable. This change adds a final print to the report for the top-level compilation time that was spent compiling your block. For example: ```julia julia> @eval function f(a) $(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 + 0.474445 seconds top-level compilation time -2.53151813758841e205 julia> x = 2 2 julia> @time f(x) # Inferring with a non-const is slower, but does not happen at top-level, since x is a global whose type cannot be known until runtime. 1.212882 seconds (129.51 k allocations: 4.811 MiB, 100.00% compilation time) -2.53151813758841e205 julia> @time f(x) # But now, subsequent invocations have no compilation time since it's already compiled. 0.000006 seconds (1 allocation: 16 bytes) -2.53151813758841e205 ``` Without this change, the `@time f(2)` call, would have reported `0.0 seconds` with no other context. The following example shows both types of compilation time reported: ```julia julia> @time peakflops() 0.803850 seconds (2.26 M allocations: 181.699 MiB, 4.90% gc time, 84.81% compilation time) + 0.017840 seconds top-level compilation time 1.5840888414049457e11 ``` ---- This change is fairly complex. Here's why: The trouble with the `@time` macro is that the user's code is compiled as _part of_ compiling the enclosing block, so the naive implementation of this change would report _every invocation_ as having some compilation time. To address this, we use a heuristic: we record the time to compile an _empty block_ that simply times an empty statement, and subtract that empty block compilation time from the time to compile the user's block, to get the true user compilation time. We also subtract the inner, dynamic compilation time (the number used to report the percentage), to get the top-level compilation time. Finally, we only report the top-level compilation time if it is suffiently larger than the empty block's compilation time by a ratio threshold, to prevent reporting compilation time due to noisy variance. It's annoyingly tricky, but we think it works, and achieves the best of all the above worlds regarding reporting these metrics. :) The user won't be fooled by `@time` reporting a much shorter time than the actual wall time because we actually spent 5 min inferring the code (this has happened to me in real life, and confused me for days). And the user _also_ won't be confused to see top-level compilation time where they don't expect it. And the total runtime reported remains only the time to execute their function, which is what they likely expect. It's complex, but we think this is a nice balance. :) Co-Authored-By: Valentin Churavy <[email protected]>
As discussed in the comments for JuliaLang#37678, the `% compilation time` metric added to `@time` is not an accurate measurement of the total compilation time. It is in fact excluding any top-level compilation time, which may in fact be quite expensive if the body of your block is fully type stable and inferrable. This change adds a final print to the report for the top-level compilation time that was spent compiling your block. For example: ```julia julia> @eval function f(a) $(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 + 0.474445 seconds top-level compilation time -2.53151813758841e205 julia> x = 2 2 julia> @time f(x) # Inferring with a non-const is slower, but does not happen at top-level, since x is a global whose type cannot be known until runtime. 1.212882 seconds (129.51 k allocations: 4.811 MiB, 100.00% compilation time) -2.53151813758841e205 julia> @time f(x) # But now, subsequent invocations have no compilation time since it's already compiled. 0.000006 seconds (1 allocation: 16 bytes) -2.53151813758841e205 ``` Without this change, the `@time f(2)` call, would have reported `0.0 seconds` with no other context. The following example shows both types of compilation time reported: ```julia julia> @time peakflops() 0.803850 seconds (2.26 M allocations: 181.699 MiB, 4.90% gc time, 84.81% compilation time) + 0.017840 seconds top-level compilation time 1.5840888414049457e11 ``` ---- This change is fairly complex. Here's why: The trouble with the `@time` macro is that the user's code is compiled as _part of_ compiling the enclosing block, so the naive implementation of this change would report _every invocation_ as having some compilation time. To address this, we use a heuristic: we record the time to compile an _empty block_ that simply times an empty statement, and subtract that empty block compilation time from the time to compile the user's block, to get the true user compilation time. We also subtract the inner, dynamic compilation time (the number used to report the percentage), to get the top-level compilation time. Finally, we only report the top-level compilation time if it is suffiently larger than the empty block's compilation time by a ratio threshold, to prevent reporting compilation time due to noisy variance. It's annoyingly tricky, but we think it works, and achieves the best of all the above worlds regarding reporting these metrics. :) The user won't be fooled by `@time` reporting a much shorter time than the actual wall time because we actually spent 5 min inferring the code (this has happened to me in real life, and confused me for days). And the user _also_ won't be confused to see top-level compilation time where they don't expect it. And the total runtime reported remains only the time to execute their function, which is what they likely expect. It's complex, but we think this is a nice balance. :) Co-Authored-By: Valentin Churavy <[email protected]>
Adds a report of any compilation time to the
@time
and@timev
macros, as a % of total timeI was wondering if
compiler_start_time
should be set earlier than it is here, to catch more compiler-related time?