Skip to content

Commit

Permalink
Tweaks to reduce latency (#590)
Browse files Browse the repository at this point in the history
Investigation via `SnoopCompile.@snoopi_deep` identified several
opportunities to reduce latency:
- JuliaLang/julia#38906
- JuliaDebug/JuliaInterpreter.jl#461
- JuliaDebug/LoweredCodeUtils.jl#58

Together with the changes here, the aggregate effect is to reduce
the time for the first revision from 3.1s
to about 1.5s. That's much more reasonable.
  • Loading branch information
timholy authored Dec 21, 2020
1 parent 0ea8c13 commit 5dd0b43
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 12 deletions.
10 changes: 5 additions & 5 deletions src/lowered.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function matches_eval(stmt::Expr)
(isa(f, GlobalRef) && f.name === :eval) || is_quotenode_egal(f, Core.eval)
end

function categorize_stmt(stmt)
function categorize_stmt(@nospecialize(stmt))
ismeth, haseval, isinclude, isnamespace, istoplevel = false, false, false, false, false
if isa(stmt, Expr)
haseval = matches_eval(stmt)
Expand All @@ -77,7 +77,7 @@ to `Revise.is_method_or_eval`.
Since the contents of such expression are difficult to analyze, it is generally
safest to execute all such evals.
"""
function minimal_evaluation!(predicate, methodinfo, src::Core.CodeInfo, mode::Symbol)
function minimal_evaluation!(@nospecialize(predicate), methodinfo, src::Core.CodeInfo, mode::Symbol)
edges = CodeEdges(src)
# LoweredCodeUtils.print_with_code(stdout, src, edges)
isrequired = fill(false, length(src.code))
Expand Down Expand Up @@ -112,11 +112,11 @@ function minimal_evaluation!(predicate, methodinfo, src::Core.CodeInfo, mode::Sy
add_dependencies!(methodinfo, edges, src, isrequired)
return isrequired, evalassign
end
minimal_evaluation!(predicate, methodinfo, frame::JuliaInterpreter.Frame, mode::Symbol) =
minimal_evaluation!(@nospecialize(predicate), methodinfo, frame::JuliaInterpreter.Frame, mode::Symbol) =
minimal_evaluation!(predicate, methodinfo, frame.framecode.src, mode)

function minimal_evaluation!(methodinfo, frame, mode::Symbol)
minimal_evaluation!(methodinfo, frame, mode) do stmt
minimal_evaluation!(methodinfo, frame, mode) do @nospecialize(stmt)
ismeth, haseval, isinclude, isnamespace, istoplevel = categorize_stmt(stmt)
isreq = ismeth | isinclude | istoplevel
return mode === :sigs ? (isreq, haseval) : (isreq | isnamespace, haseval)
Expand Down Expand Up @@ -184,7 +184,7 @@ function methods_by_execution!(@nospecialize(recurse), methodinfo, docexprs, mod
end
if lwr.head !== :thunk
mode === :sigs && return nothing, nothing
return Core.eval(mod, lwr)
return Core.eval(mod, lwr), nothing
end
frame = JuliaInterpreter.Frame(mod, lwr.args[1])
mode === :eval || LoweredCodeUtils.rename_framemethods!(recurse, frame)
Expand Down
18 changes: 13 additions & 5 deletions src/packagedef.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@ const silencefile = Ref(joinpath(depsdir, "silence.txt")) # Ref so that tests d
## now this is the right strategy.) From the standpoint of CodeTracking, we should
## link the signature to the actual method-defining expression (either :(f() = 1) or :(g() = 2)).

if isdefined(Core, :MethodMatch)
get_method_from_match(mm::Core.MethodMatch) = mm.method
else
get_method_from_match(mm::Core.SimpleVector) = mm[3]::Method
end

function delete_missing!(exs_sigs_old::ExprsSigs, exs_sigs_new)
with_logger(_debug_logger) do
for (ex, sigs) in exs_sigs_old
Expand All @@ -242,7 +248,7 @@ function delete_missing!(exs_sigs_old::ExprsSigs, exs_sigs_new)
ret = Base._methods_by_ftype(sig, -1, typemax(UInt))
success = false
if !isempty(ret)
m = ret[end][3]::Method # the last method returned is the least-specific that matches, and thus most likely to be type-equal
m = get_method_from_match(ret[end]) # the last method returned is the least-specific that matches, and thus most likely to be type-equal
methsig = m.sig
if sig <: methsig && methsig <: sig
locdefs = get(CodeTracking.method_info, sig, nothing)
Expand Down Expand Up @@ -408,10 +414,12 @@ function add_signature!(methodinfo::CodeTrackingMethodInfo, @nospecialize(sig),
locdefs = get(CodeTracking.method_info, sig, nothing)
locdefs === nothing && (locdefs = CodeTracking.method_info[sig] = Tuple{LineNumberNode,Expr}[])
newdef = unwrap(methodinfo.exprstack[end])
if !any(locdef->locdef[1] == ln && isequal(RelocatableExpr(locdef[2]), RelocatableExpr(newdef)), locdefs)
push!(locdefs, (fixpath(ln), newdef))
if newdef !== nothing
if !any(locdef->locdef[1] == ln && isequal(RelocatableExpr(locdef[2]), RelocatableExpr(newdef)), locdefs)
push!(locdefs, (fixpath(ln), newdef))
end
push!(methodinfo.allsigs, sig)
end
push!(methodinfo.allsigs, sig)
return methodinfo
end
push_expr!(methodinfo::CodeTrackingMethodInfo, mod::Module, ex::Expr) = (push!(methodinfo.exprstack, ex); methodinfo)
Expand Down Expand Up @@ -452,7 +460,7 @@ end
function eval_with_signatures(mod, ex::Expr; mode=:eval, kwargs...)
methodinfo = CodeTrackingMethodInfo(ex)
docexprs = DocExprs()
_, frame = methods_by_execution!(finish_and_return!, methodinfo, docexprs, mod, ex; mode=mode, kwargs...)
frame = methods_by_execution!(finish_and_return!, methodinfo, docexprs, mod, ex; mode=mode, kwargs...)[2]
return methodinfo.allsigs, methodinfo.deps, methodinfo.includes, frame
end

Expand Down
1 change: 1 addition & 0 deletions src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function _precompile_()

MI = CodeTrackingMethodInfo
@assert precompile(Tuple{typeof(minimal_evaluation!), MI, Core.CodeInfo, Symbol})
@assert precompile(Tuple{typeof(minimal_evaluation!), Any, MI, Core.CodeInfo, Symbol})
@assert precompile(Tuple{typeof(methods_by_execution!), Any, MI, DocExprs, Module, Expr})
@assert precompile(Tuple{typeof(methods_by_execution!), Any, MI, DocExprs, JuliaInterpreter.Frame, Vector{Bool}})
@assert precompile(Tuple{typeof(Core.kwfunc(methods_by_execution!)),
Expand Down
4 changes: 2 additions & 2 deletions src/relocatable_exprs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ function Base.isequal(itera::LineSkippingIterator, iterb::LineSkippingIterator)
while true
reta === nothing && retb === nothing && return true
(reta === nothing || retb === nothing) && return false
vala, ia = reta
valb, ib = retb
vala, ia = reta::Tuple{Any,Int}
valb, ib = retb::Tuple{Any,Int}
if isa(vala, Expr) && isa(valb, Expr)
vala, valb = vala::Expr, valb::Expr
vala.head == valb.head || return false
Expand Down

0 comments on commit 5dd0b43

Please sign in to comment.