Skip to content

Commit

Permalink
Reduce the time-to-first-request by adding pregenerated precompile st…
Browse files Browse the repository at this point in the history
…atements
  • Loading branch information
DilumAluthge committed Jun 21, 2024
1 parent 96a0b34 commit d9b68be
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
96 changes: 96 additions & 0 deletions contrib/precompile_generate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
function gen_single_tracefile(
code::AbstractString,
tracefile::AbstractString,
)
julia_binary = Base.julia_cmd().exec[1]
cmd = `$(julia_binary)`
push!(cmd.exec, "--compile=all")
push!(cmd.exec, "--trace-compile=$(tracefile)")
push!(cmd.exec, "-e $(code)")
splitter = Sys.iswindows() ? ';' : ':'
project = Base.active_project()
env2 = copy(ENV)
env2["JULIA_LOAD_PATH"] = "$(project)$(splitter)@stdlib"
env2["JULIA_PROJECT"] = "$(project)"
run(setenv(cmd, env2))
return nothing
end

function gen_single_precompile(code::AbstractString)
str = mktempdir() do dir
tracefile = joinpath(dir, "tracefile")
gen_single_tracefile(code, tracefile)
return read(tracefile, String)::String
end::String
lines = convert(
Vector{String},
strip.(split(strip(str), '\n')),
)::Vector{String}
filter!(line -> !isempty(line), lines)
return lines
end

function gen_all_precompile()
codes = String[
"import HTTP; HTTP.get(\"https://example.com/\")",
]
all_lines = String[]
for code in codes
lines = gen_single_precompile(code)
append!(all_lines, lines)
end
unique!(all_lines)
end

function write_all_precompile(io::IO, all_lines::Vector{String})
preamble_lines = String[
"import MbedTLS",
"const MbedTLS_jll = MbedTLS.MbedTLS_jll"
]
for line in preamble_lines
println(io, line)
end
println(io)
println(io, """
function _precompile()
""")
println(io, """
if ccall(:jl_generating_output, Cint, ()) != 1
return nothing
end
""")
println(io, """
@static if Base.VERSION < v"1.9-"
# We need https://github.com/JuliaLang/julia/pull/43990, otherwise this isn't worth doing.
return nothing
end
""")
for line in all_lines
println(io, " ", line)
end
println(io)
println(io, """
return nothing
end
""")
return nothing
end

function write_all_precompile(
output_file::AbstractString,
all_lines::Vector{String},
)
open(output_file, "w") do io
write_all_precompile(io, all_lines)
end
return nothing
end

function main()
output_file = joinpath(dirname(@__DIR__), "src", "precompile.jl")
all_lines = gen_all_precompile()
write_all_precompile(output_file, all_lines)
return nothing
end

main()
3 changes: 3 additions & 0 deletions src/HTTP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -631,4 +631,7 @@ function Base.parse(::Type{T}, str::AbstractString)::T where T <: Message
return m
end

include("precompile.jl")
_precompile()

end # module
73 changes: 73 additions & 0 deletions src/precompile.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import MbedTLS
const MbedTLS_jll = MbedTLS.MbedTLS_jll

function _precompile()

if ccall(:jl_generating_output, Cint, ()) != 1
return nothing
end

@static if Base.VERSION < v"1.9-"
# We need https://github.com/JuliaLang/julia/pull/43990, otherwise this isn't worth doing.
return nothing
end

precompile(Tuple{typeof(Base.:(!=)), UInt64, UInt64})
precompile(Tuple{typeof(MbedTLS_jll.__init__)})
precompile(Tuple{typeof(MbedTLS.f_send), Ptr{Nothing}, Ptr{UInt8}, UInt64})
precompile(Tuple{typeof(MbedTLS.f_recv), Ptr{Nothing}, Ptr{UInt8}, UInt64})
precompile(Tuple{typeof(MbedTLS.__init__)})
precompile(Tuple{typeof(URIs.__init__)})
precompile(Tuple{typeof(HTTP.Parsers.__init__)})
precompile(Tuple{typeof(HTTP.CookieRequest.__init__)})
precompile(Tuple{typeof(HTTP.ConnectionRequest.__init__)})
precompile(Tuple{typeof(HTTP.Servers.__init__)})
precompile(Tuple{typeof(HTTP.MultiPartParsing.__init__)})
precompile(Tuple{typeof(HTTP.get), String})
precompile(Tuple{Type{NamedTuple{(:init,), T} where T<:Tuple}, Tuple{DataType}})
precompile(Tuple{Base.var"#reduce##kw", NamedTuple{(:init,), Tuple{DataType}}, typeof(Base.reduce), Function, Base.Set{Tuple{Union{Type{Union{}}, UnionAll}, UnionAll}}})
precompile(Tuple{typeof(Base.mapfoldl_impl), typeof(Base.identity), HTTP.var"#24#25", Type, Base.Set{Tuple{Union{Type{Union{}}, UnionAll}, UnionAll}}})
precompile(Tuple{typeof(HTTP.request), Type{HTTP.TopRequest.TopLayer{HTTP.RedirectRequest.RedirectLayer{HTTP.BasicAuthRequest.BasicAuthLayer{HTTP.MessageRequest.MessageLayer{HTTP.RetryRequest.RetryLayer{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}}}}}}, String, URIs.URI, Array{Pair{Base.SubString{String}, Base.SubString{String}}, 1}, Array{UInt8, 1}})
precompile(Tuple{HTTP.var"#request##kw", NamedTuple{(:iofunction, :reached_redirect_limit), Tuple{Nothing, Bool}}, typeof(HTTP.request), Type{HTTP.ExceptionRequest.ExceptionLayer{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}}, URIs.URI, HTTP.Messages.Request, Array{UInt8, 1}})
precompile(Tuple{HTTP.var"#request##kw", NamedTuple{(:iofunction, :reached_redirect_limit), Tuple{Nothing, Bool}}, typeof(HTTP.request), Type{HTTP.ConnectionRequest.ConnectionPoolLayer{HTTP.StreamRequest.StreamLayer{Union{}}}}, URIs.URI, HTTP.Messages.Request, Array{UInt8, 1}})
precompile(Tuple{typeof(Sockets.uv_getaddrinfocb), Ptr{Nothing}, Int32, Ptr{Nothing}})
precompile(Tuple{HTTP.ConnectionPool.var"#newconnection##kw", NamedTuple{(:iofunction, :reached_redirect_limit), Tuple{Nothing, Bool}}, typeof(HTTP.ConnectionPool.newconnection), Type{MbedTLS.SSLContext}, Base.SubString{String}, Base.SubString{String}})
precompile(Tuple{typeof(Sockets.uv_connectcb), Ptr{Nothing}, Int32})
precompile(Tuple{typeof(Sockets.connect), Sockets.IPv4, UInt64})
precompile(Tuple{typeof(Base.setproperty!), Sockets.TCPSocket, Symbol, Int64})
precompile(Tuple{typeof(Base.notify), Base.GenericCondition{Base.Threads.SpinLock}})
precompile(Tuple{typeof(MbedTLS.f_rng), MbedTLS.CtrDrbg, Ptr{UInt8}, UInt64})
precompile(Tuple{typeof(Base.isopen), Sockets.TCPSocket})
precompile(Tuple{typeof(Base.getproperty), Sockets.TCPSocket, Symbol})
precompile(Tuple{typeof(Base.unsafe_write), Sockets.TCPSocket, Ptr{UInt8}, UInt64})
precompile(Tuple{typeof(Base.bytesavailable), Sockets.TCPSocket})
precompile(Tuple{typeof(Base.eof), Sockets.TCPSocket})
precompile(Tuple{typeof(Base.alloc_buf_hook), Sockets.TCPSocket, UInt64})
precompile(Tuple{Base.var"#readcb_specialized#671", Sockets.TCPSocket, Int64, UInt64})
precompile(Tuple{typeof(Base.min), UInt64, Int64})
precompile(Tuple{typeof(Base.unsafe_read), Sockets.TCPSocket, Ptr{UInt8}, UInt64})
precompile(Tuple{Type{Int32}, UInt64})
precompile(Tuple{typeof(HTTP.Messages.hasheader), HTTP.Messages.Request, String})
precompile(Tuple{typeof(HTTP.Messages.ischunked), HTTP.Messages.Request})
precompile(Tuple{typeof(HTTP.Messages.writeheaders), Base.GenericIOBuffer{Array{UInt8, 1}}, HTTP.Messages.Request})
precompile(Tuple{typeof(Base.unsafe_write), MbedTLS.SSLContext, Ptr{UInt8}, UInt64})
precompile(Tuple{typeof(Base.check_open), Sockets.TCPSocket})
precompile(Tuple{MbedTLS.var"#25#26"{MbedTLS.SSLContext}})
precompile(Tuple{typeof(Base.eof), MbedTLS.SSLContext})
precompile(Tuple{HTTP.StreamRequest.var"#2#3"{HTTP.ConnectionPool.Connection, HTTP.Messages.Request, Array{UInt8, 1}, HTTP.Streams.Stream{HTTP.Messages.Response, HTTP.ConnectionPool.Connection}}})
precompile(Tuple{typeof(Base.bytesavailable), MbedTLS.SSLContext})
precompile(Tuple{typeof(Base.unsafe_read), MbedTLS.SSLContext, Ptr{UInt8}, Int64})
precompile(Tuple{typeof(Base.readuntil), Base.GenericIOBuffer{Array{UInt8, 1}}, typeof(HTTP.Parsers.find_end_of_header)})
precompile(Tuple{typeof(Base.release), HTTP.ConnectionPool.ConnectionPools.Pool{HTTP.ConnectionPool.Connection}, Tuple{DataType, String, String, Bool, Bool}, HTTP.ConnectionPool.Connection})
precompile(Tuple{typeof(Base.isequal), Tuple{DataType, String, String, Bool, Bool}, Tuple{DataType, Base.SubString{String}, Base.SubString{String}, Bool, Bool}})
precompile(Tuple{typeof(Base.isopen), MbedTLS.SSLContext})
precompile(Tuple{MbedTLS.var"#21#23"{MbedTLS.SSLContext}, MbedTLS.SSLContext})
precompile(Tuple{MbedTLS.var"#15#16", MbedTLS.CRT})
precompile(Tuple{MbedTLS.var"#10#11", MbedTLS.CtrDrbg})
precompile(Tuple{MbedTLS.var"#8#9", MbedTLS.Entropy})
precompile(Tuple{MbedTLS.var"#17#19", MbedTLS.SSLConfig})
precompile(Tuple{typeof(Base.uvfinalize), Sockets.TCPSocket})

return nothing
end

0 comments on commit d9b68be

Please sign in to comment.