Skip to content

make new timing change backward-compatible #24

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

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 48 additions & 9 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ end

_typeinf_identifier(frame::InferenceFrameInfo) = frame

_typeinf_frame_linfo(frame::Core.Compiler.InferenceState) = frame.linfo
_typeinf_frame_linfo(frame::InferenceFrameInfo) = frame.mi

"""
Core.Compiler.Timings.Timing(mi_info, start_time, ...)

Expand Down Expand Up @@ -97,16 +100,49 @@ const _finished_timings = Timing[]
# because we create a new node for duplicates.)
const _timings = Timing[]

# ROOT() is an empty function used as the top-level Timing node to measure all time spent
# *not* in type inference during a given recording trace. It is used as a "dummy" node.
function ROOT() end
const ROOTmi = Core.Compiler.specialize_method(
first(Core.Compiler.methods(ROOT)), Tuple{typeof(ROOT)}, Core.svec())
"""
Core.Compiler.reset_timings()
Empty out the previously recorded type inference timings (`Core.Compiler._timings`), and
start the ROOT() timer again. `ROOT()` measures all time spent _outside_ inference.

DEPRECATED: this will be removed; use `clear_and_fetch_timings` instead.
"""
function reset_timings()
empty!(_timings)
push!(_timings, Timing(
# The MethodInstance for ROOT(), and default empty values for other fields.
InferenceFrameInfo(ROOTmi, 0x0, Any[], Any[Core.Const(ROOT)], 1),
_time_ns()))
return nothing
end

# (This is split into a function so that it can be called both in this module, at the top
# of `enter_new_timer()`, and once at the Very End of the operation, by whoever started
# the operation and called `reset_timings()`.)
# NOTE: the @inline annotations here are not to make it faster, but to reduce the gap between
# timer manipulations and the tasks we're timing.
@inline function close_current_timer()
stop_time = _time_ns()
parent_timer = _timings[end]
accum_time = stop_time - parent_timer.cur_start_time

# Add in accum_time
@inbounds begin
_timings[end].time += accum_time
end
return nothing
end

@inline function enter_new_timer(frame)
# Very first thing, stop the active timer: get the current time and add in the
# time since it was last started to its aggregate exclusive time.
if length(_timings) > 0
stop_time = _time_ns()
parent_timer = _timings[end]
accum_time = stop_time - parent_timer.cur_start_time

# Add in accum_time
parent_timer.time += accum_time
close_current_timer()
end

# Start the new timer right before returning
Expand All @@ -131,15 +167,18 @@ end
# Finish the new timer
stop_time = _time_ns()

expected_mi_info = _typeinf_identifier(_expected_frame_)
expected_linfo = _typeinf_frame_linfo(_expected_frame_)

# Grab the new timer again because it might have been modified in _timings
# (since it's an immutable struct)
# And remove it from the current timings stack
new_timer = pop!(_timings)
Core.Compiler.@assert new_timer.mi_info.mi === expected_mi_info.mi
Core.Compiler.@assert new_timer.mi_info.mi === expected_linfo

is_profile_root = length(_timings) === 0
# check for two cases: normal case & backcompat case
is_profile_root_normal = length(_timings) === 0
is_profile_root_backcompat = length(_timings) === 1 && _timings[1] === ROOTmi
is_profile_root = is_profile_root_normal || is_profile_root_backcompat

accum_time = stop_time - new_timer.cur_start_time
# Add in accum_time ("modify" the immutable struct)
Expand Down