Skip to content

Commit

Permalink
Merge pull request #60 from JuliaDebug/teh/startup_latency
Browse files Browse the repository at this point in the history
Reduce startup latency
  • Loading branch information
timholy authored Feb 22, 2019
2 parents 91cd0db + 1bb4283 commit ca07ee9
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*.jl.mem
expected.out
failed.out
src/builtins.jl
src/builtins*.jl
deps/build.log
docs/build/
test/results.md
2 changes: 1 addition & 1 deletion deps/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ using InteractiveUtils

const srcpath = joinpath(dirname(@__DIR__), "src")
include(joinpath(srcpath, "generate_builtins.jl"))
open(joinpath(srcpath, "builtins.jl"), "w") do io
open(joinpath(srcpath, "builtins-julia$(Int(VERSION.major)).$(Int(VERSION.minor)).jl"), "w") do io
generate_builtins(io)
end
2 changes: 1 addition & 1 deletion src/JuliaInterpreter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ const empty_svec = Core.svec()

include("localmethtable.jl")
include("interpret.jl")
include("builtins.jl")
include("builtins-julia$(Int(VERSION.major)).$(Int(VERSION.minor)).jl")

function show_stackloc(io::IO, stack, frame, pc=frame.pc[])
indent = ""
Expand Down
102 changes: 66 additions & 36 deletions src/generate_builtins.jl
Original file line number Diff line number Diff line change
@@ -1,49 +1,63 @@
# This file generates builtins.jl.

function scopedname(f)
fstr = string(f)
io = IOBuffer()
show(io, f)
fstr = String(take!(io))
occursin('.', fstr) && return fstr
tn = typeof(f).name
Base.isexported(tn.module, Symbol(fstr)) && return fstr
return string(tn.module) * '.' * fstr
fsym = Symbol(fstr)
isdefined(tn.module, fsym) && return string(tn.module) * '.' * fstr
return "Base." * fstr
end

# Look up the expected number of arguments in Core.Compiler.tfunc data
function generate_fcall(f, table, id)
function nargs(f, table, id)
# Look up the expected number of arguments in Core.Compiler.tfunc data
if id !== nothing
minarg, maxarg, tfunc = table[id]
else
minarg = 0
maxarg = typemax(Int)
end
# The tfunc tables are wrong for fptoui and fptosi
# The tfunc tables are wrong for fptoui and fptosi (fixed in https://github.com/JuliaLang/julia/pull/30787)
if f == "Base.fptoui" || f == "Base.fptosi"
minarg = 2
end
return minarg, maxarg
end

function generate_fcall_nargs(fname, minarg, maxarg)
# Generate a separate call for each number of arguments
fname = scopedname(f)
if maxarg < typemax(Int)
wrapper = minarg == maxarg ? "" : "if nargs == "
for nargs = minarg:maxarg
if minarg < maxarg
wrapper *= "$nargs\n "
end
argcall = ""
for i = 1:nargs
argcall *= "@lookup(frame, args[$(i+1)])"
if i < nargs
argcall *= ", "
end
end
wrapper *= "return Some{Any}($fname($argcall))"
if nargs < maxarg
wrapper *= "\n elseif nargs == "
maxarg < typemax(Int) || error("call this only for constrained number of arguments")
wrapper = minarg == maxarg ? "" : "if nargs == "
for nargs = minarg:maxarg
if minarg < maxarg
wrapper *= "$nargs\n "
end
argcall = ""
for i = 1:nargs
argcall *= "@lookup(frame, args[$(i+1)])"
if i < nargs
argcall *= ", "
end
end
if minarg < maxarg
wrapper *= "\n end"
wrapper *= "return Some{Any}($fname($argcall))"
if nargs < maxarg
wrapper *= "\n elseif nargs == "
end
return wrapper
end
if minarg < maxarg
wrapper *= "\n end"
end
return wrapper
end

function generate_fcall(f, table, id)
minarg, maxarg = nargs(f, table, id)
fname = scopedname(f)
if maxarg < typemax(Int)
return generate_fcall_nargs(fname, minarg, maxarg)
end
# A built-in with arbitrary or unknown number of arguments.
# This will (unfortunately) use dynamic dispatch.
Expand Down Expand Up @@ -124,13 +138,7 @@ function maybe_evaluate_builtin(frame, call_expr)
"""
# Intrinsics
""")
for fsym in names(Core.Intrinsics)
fsym == :Intrinsics && continue
isdefined(Base, fsym) || (println("skipping ", fname); continue)
f = getfield(Base, fsym)
f isa Core.IntrinsicFunction || error("not an intrinsic")
if f == cglobal
print(io,
print(io,
"""
elseif f === Base.cglobal
if nargs == 1
Expand All @@ -141,18 +149,40 @@ function maybe_evaluate_builtin(frame, call_expr)
return Some{Any}(Core.eval(moduleof(frame), call_expr))
end
""")
continue
# Extract any intrinsics that support varargs
fva = []
minmin, maxmax = typemax(Int), 0
for fsym in names(Core.Intrinsics)
fsym == :Intrinsics && continue
isdefined(Base, fsym) || continue
f = getfield(Base, fsym)
id = reinterpret(Int32, f) + 1
minarg, maxarg = nargs(f, Core.Compiler.T_IFUNC, id)
if maxarg == typemax(Int)
push!(fva, f)
else
minmin = min(minmin, minarg)
maxmax = max(maxmax, maxarg)
end
end
for f in fva
id = reinterpret(Int32, f) + 1
f = isdefined(Base, fsym) ? "Base.$fsym" :
isdefined(Core, fsym) ? "Core.$fsym" : error("whoops on $f")
fname = scopedname(f)
fcall = generate_fcall(f, Core.Compiler.T_IFUNC, id)
print(io,
"""
elseif f === $f
elseif f === $fname
$fcall
end
""")
end
# Now handle calls with bounded numbers of args
fcall = generate_fcall_nargs("f", minmin, maxmax)
print(io,
"""
if isa(f, Core.IntrinsicFunction)
$fcall
""")
print(io,
"""
end
Expand Down
1 change: 1 addition & 0 deletions src/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function _precompile_()
precompile(Tuple{typeof(prepare_locals), JuliaFrameCode, Vector{Any}})
precompile(Tuple{typeof(prepare_args), Any, Vector{Any}, Vector{Any}})
precompile(Tuple{typeof(prepare_call), Any, Vector{Any}})
precompile(Tuple{typeof(Core.kwfunc(prepare_call)), NamedTuple{(:enter_generated,),Tuple{Bool}}, typeof(JuliaInterpreter.prepare_call), Function, Vector{Any}})
precompile(Tuple{typeof(build_frame), JuliaFrameCode, Vector{Any}, Core.SimpleVector})
precompile(Tuple{typeof(extract_args), Module, Expr})
precompile(Tuple{typeof(enter_call), Int, Int})
Expand Down

0 comments on commit ca07ee9

Please sign in to comment.