Skip to content

Commit 1003cb5

Browse files
committed
Reduce the time-to-first-request by adding pregenerated precompile statements
1 parent 47f6b8d commit 1003cb5

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

contrib/precompile_generate.jl

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
function gen_single_tracefile(
2+
code::AbstractString,
3+
tracefile::AbstractString,
4+
)
5+
julia_binary = Base.julia_cmd().exec[1]
6+
cmd = `$(julia_binary)`
7+
push!(cmd.exec, "--compile=all")
8+
push!(cmd.exec, "--trace-compile=$(tracefile)")
9+
push!(cmd.exec, "-e $(code)")
10+
splitter = Sys.iswindows() ? ';' : ':'
11+
project = Base.active_project()
12+
env2 = copy(ENV)
13+
env2["JULIA_LOAD_PATH"] = "$(project)$(splitter)@stdlib"
14+
env2["JULIA_PROJECT"] = "$(project)"
15+
run(setenv(cmd, env2))
16+
return nothing
17+
end
18+
19+
function gen_single_precompile(code::AbstractString)
20+
str = mktempdir() do dir
21+
tracefile = joinpath(dir, "tracefile")
22+
gen_single_tracefile(code, tracefile)
23+
return read(tracefile, String)::String
24+
end::String
25+
lines = convert(
26+
Vector{String},
27+
strip.(split(strip(str), '\n')),
28+
)::Vector{String}
29+
filter!(line -> !isempty(line), lines)
30+
return lines
31+
end
32+
33+
function gen_all_precompile()
34+
codes = String[
35+
"import HTTP; HTTP.get(\"https://example.com/\")",
36+
]
37+
all_lines = String[]
38+
for code in codes
39+
lines = gen_single_precompile(code)
40+
append!(all_lines, lines)
41+
end
42+
unique!(all_lines)
43+
end
44+
45+
function write_all_precompile(io::IO, all_lines::Vector{String})
46+
preamble_lines = String[
47+
"import MbedTLS",
48+
"const MbedTLS_jll = MbedTLS.MbedTLS_jll"
49+
]
50+
for line in preamble_lines
51+
println(io, line)
52+
end
53+
println(io)
54+
println(io, """
55+
function _precompile()
56+
""")
57+
println(io, """
58+
if ccall(:jl_generating_output, Cint, ()) != 1
59+
return nothing
60+
end
61+
""")
62+
println(io, """
63+
@static if Base.VERSION < v"1.9-"
64+
# We need https://github.com/JuliaLang/julia/pull/43990, otherwise this isn't worth doing.
65+
return nothing
66+
end
67+
""")
68+
for line in all_lines
69+
println(io, " ", line)
70+
end
71+
println(io)
72+
println(io, """
73+
return nothing
74+
end
75+
""")
76+
return nothing
77+
end
78+
79+
function write_all_precompile(
80+
output_file::AbstractString,
81+
all_lines::Vector{String},
82+
)
83+
open(output_file, "w") do io
84+
write_all_precompile(io, all_lines)
85+
end
86+
return nothing
87+
end
88+
89+
function main()
90+
output_file = joinpath(dirname(@__DIR__), "src", "precompile.jl")
91+
all_lines = gen_all_precompile()
92+
write_all_precompile(output_file, all_lines)
93+
return nothing
94+
end
95+
96+
main()

src/HTTP.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,4 +623,7 @@ function Base.parse(::Type{T}, str::AbstractString)::T where T <: Message
623623
return m
624624
end
625625

626+
include("precompile.jl")
627+
_precompile()
628+
626629
end # module

src/precompile.jl

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import MbedTLS
2+
const MbedTLS_jll = MbedTLS.MbedTLS_jll
3+
4+
function _precompile()
5+
6+
if ccall(:jl_generating_output, Cint, ()) != 1
7+
return nothing
8+
end
9+
10+
@static if Base.VERSION < v"1.9-"
11+
# We need https://github.com/JuliaLang/julia/pull/43990, otherwise this isn't worth doing.
12+
return nothing
13+
end
14+
15+
precompile(Tuple{typeof(Base.:(!=)), UInt64, UInt64})
16+
precompile(Tuple{typeof(MbedTLS_jll.__init__)})
17+
precompile(Tuple{typeof(MbedTLS.f_send), Ptr{Nothing}, Ptr{UInt8}, UInt64})
18+
precompile(Tuple{typeof(MbedTLS.f_recv), Ptr{Nothing}, Ptr{UInt8}, UInt64})
19+
precompile(Tuple{typeof(MbedTLS.__init__)})
20+
precompile(Tuple{typeof(URIs.__init__)})
21+
precompile(Tuple{typeof(HTTP.Parsers.__init__)})
22+
precompile(Tuple{typeof(HTTP.CookieRequest.__init__)})
23+
precompile(Tuple{typeof(HTTP.ConnectionRequest.__init__)})
24+
precompile(Tuple{typeof(HTTP.Servers.__init__)})
25+
precompile(Tuple{typeof(HTTP.MultiPartParsing.__init__)})
26+
precompile(Tuple{typeof(HTTP.get), String})
27+
precompile(Tuple{Type{NamedTuple{(:init,), T} where T<:Tuple}, Tuple{DataType}})
28+
precompile(Tuple{Base.var"#reduce##kw", NamedTuple{(:init,), Tuple{DataType}}, typeof(Base.reduce), Function, Base.Set{Tuple{Union{Type{Union{}}, UnionAll}, UnionAll}}})
29+
precompile(Tuple{typeof(Base.mapfoldl_impl), typeof(Base.identity), HTTP.var"#24#25", Type, Base.Set{Tuple{Union{Type{Union{}}, UnionAll}, UnionAll}}})
30+
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}})
31+
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}})
32+
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}})
33+
precompile(Tuple{typeof(Sockets.uv_getaddrinfocb), Ptr{Nothing}, Int32, Ptr{Nothing}})
34+
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}})
35+
precompile(Tuple{typeof(Sockets.uv_connectcb), Ptr{Nothing}, Int32})
36+
precompile(Tuple{typeof(Sockets.connect), Sockets.IPv4, UInt64})
37+
precompile(Tuple{typeof(Base.setproperty!), Sockets.TCPSocket, Symbol, Int64})
38+
precompile(Tuple{typeof(Base.notify), Base.GenericCondition{Base.Threads.SpinLock}})
39+
precompile(Tuple{typeof(MbedTLS.f_rng), MbedTLS.CtrDrbg, Ptr{UInt8}, UInt64})
40+
precompile(Tuple{typeof(Base.isopen), Sockets.TCPSocket})
41+
precompile(Tuple{typeof(Base.getproperty), Sockets.TCPSocket, Symbol})
42+
precompile(Tuple{typeof(Base.unsafe_write), Sockets.TCPSocket, Ptr{UInt8}, UInt64})
43+
precompile(Tuple{typeof(Base.bytesavailable), Sockets.TCPSocket})
44+
precompile(Tuple{typeof(Base.eof), Sockets.TCPSocket})
45+
precompile(Tuple{typeof(Base.alloc_buf_hook), Sockets.TCPSocket, UInt64})
46+
precompile(Tuple{Base.var"#readcb_specialized#671", Sockets.TCPSocket, Int64, UInt64})
47+
precompile(Tuple{typeof(Base.min), UInt64, Int64})
48+
precompile(Tuple{typeof(Base.unsafe_read), Sockets.TCPSocket, Ptr{UInt8}, UInt64})
49+
precompile(Tuple{Type{Int32}, UInt64})
50+
precompile(Tuple{typeof(HTTP.Messages.hasheader), HTTP.Messages.Request, String})
51+
precompile(Tuple{typeof(HTTP.Messages.ischunked), HTTP.Messages.Request})
52+
precompile(Tuple{typeof(HTTP.Messages.writeheaders), Base.GenericIOBuffer{Array{UInt8, 1}}, HTTP.Messages.Request})
53+
precompile(Tuple{typeof(Base.unsafe_write), MbedTLS.SSLContext, Ptr{UInt8}, UInt64})
54+
precompile(Tuple{typeof(Base.check_open), Sockets.TCPSocket})
55+
precompile(Tuple{MbedTLS.var"#25#26"{MbedTLS.SSLContext}})
56+
precompile(Tuple{typeof(Base.eof), MbedTLS.SSLContext})
57+
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}}})
58+
precompile(Tuple{typeof(Base.bytesavailable), MbedTLS.SSLContext})
59+
precompile(Tuple{typeof(Base.unsafe_read), MbedTLS.SSLContext, Ptr{UInt8}, Int64})
60+
precompile(Tuple{typeof(Base.readuntil), Base.GenericIOBuffer{Array{UInt8, 1}}, typeof(HTTP.Parsers.find_end_of_header)})
61+
precompile(Tuple{typeof(Base.release), HTTP.ConnectionPool.ConnectionPools.Pool{HTTP.ConnectionPool.Connection}, Tuple{DataType, String, String, Bool, Bool}, HTTP.ConnectionPool.Connection})
62+
precompile(Tuple{typeof(Base.isequal), Tuple{DataType, String, String, Bool, Bool}, Tuple{DataType, Base.SubString{String}, Base.SubString{String}, Bool, Bool}})
63+
precompile(Tuple{typeof(Base.isopen), MbedTLS.SSLContext})
64+
precompile(Tuple{MbedTLS.var"#21#23"{MbedTLS.SSLContext}, MbedTLS.SSLContext})
65+
precompile(Tuple{MbedTLS.var"#15#16", MbedTLS.CRT})
66+
precompile(Tuple{MbedTLS.var"#10#11", MbedTLS.CtrDrbg})
67+
precompile(Tuple{MbedTLS.var"#8#9", MbedTLS.Entropy})
68+
precompile(Tuple{MbedTLS.var"#17#19", MbedTLS.SSLConfig})
69+
precompile(Tuple{typeof(Base.uvfinalize), Sockets.TCPSocket})
70+
71+
return nothing
72+
end
73+

0 commit comments

Comments
 (0)