Skip to content

Commit 924484f

Browse files
authored
build: improve precompile generation script (#37918)
1 parent 1f22caf commit 924484f

File tree

1 file changed

+59
-54
lines changed

1 file changed

+59
-54
lines changed

contrib/generate_precompile.jl

Lines changed: 59 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ hardcoded_precompile_statements = """
2929
@assert precompile(Tuple{typeof(Base.Experimental.register_error_hint), Any, Type})
3030
"""
3131

32-
precompile_script = """
32+
repl_script = """
3333
2+2
3434
print("")
3535
@time 1+1
@@ -45,6 +45,9 @@ f(x) = x03
4545
f(1,2)
4646
[][1]
4747
cd("complet_path\t\t$CTRL_C
48+
"""
49+
50+
precompile_script = """
4851
# Used by JuliaInterpreter
4952
push!(Set{Module}(), Main)
5053
push!(Set{Method}(), first(methods(collect)))
@@ -88,7 +91,7 @@ if Artifacts !== nothing
8891
precompile_script *= """
8992
using Artifacts, Base.BinaryPlatforms, Libdl
9093
artifacts_toml = abspath(joinpath(Sys.STDLIB, "Artifacts", "test", "Artifacts.toml"))
91-
cd(() -> @artifact_str("c_simple"), dirname(artifacts_toml))
94+
# cd(() -> (name = "c_simple"; @artifact_str(name)), dirname(artifacts_toml))
9295
artifacts = Artifacts.load_artifacts_toml(artifacts_toml)
9396
platforms = [Artifacts.unpack_platform(e, "c_simple", artifacts_toml) for e in artifacts["c_simple"]]
9497
best_platform = select_platform(Dict(p => triplet(p) for p in platforms))
@@ -102,7 +105,8 @@ Pkg = get(Base.loaded_modules,
102105
nothing)
103106

104107
if Pkg !== nothing
105-
precompile_script *= Pkg.precompile_script
108+
# TODO: Split Pkg precompile script into REPL and script part
109+
repl_script *= Pkg.precompile_script
106110
end
107111

108112
FileWatching = get(Base.loaded_modules,
@@ -141,10 +145,17 @@ function generate_precompile_statements()
141145
debug_output = devnull # or stdout
142146
sysimg = Base.unsafe_string(Base.JLOptions().image_file)
143147

144-
# Precompile a package
145-
global hardcoded_precompile_statements
148+
# Extract the precompile statements from the precompile file
149+
statements = Set{String}()
150+
151+
# From hardcoded statements
152+
for statement in split(hardcoded_precompile_statements::String, '\n')
153+
push!(statements, statement)
154+
end
146155

156+
# Collect statements from running the script
147157
mktempdir() do prec_path
158+
# Also precompile a package here
148159
pkgname = "__PackagePrecompilationStatementModule"
149160
mkpath(joinpath(prec_path, pkgname, "src"))
150161
path = joinpath(prec_path, pkgname, "src", "$pkgname.jl")
@@ -154,20 +165,20 @@ function generate_precompile_statements()
154165
end
155166
""")
156167
tmp = tempname()
157-
# Running compilecache on buildbots fails with
158-
# `More than one command line CPU targets specified without a `--output-` flag specified`
159-
# so start a new process without a CPU target specified
160168
s = """
161169
push!(DEPOT_PATH, $(repr(prec_path)));
162170
Base.PRECOMPILE_TRACE_COMPILE[] = $(repr(tmp));
163171
Base.compilecache(Base.PkgId($(repr(pkgname))), $(repr(path)))
172+
$precompile_script
164173
"""
165174
run(`$(julia_exepath()) -O0 --sysimage $sysimg --startup-file=no -Cnative -e $s`)
166-
hardcoded_precompile_statements *= "\n" * read(tmp, String)
175+
for statement in split(read(tmp, String), '\n')
176+
push!(statements, statement)
177+
end
167178
end
168179

169180
mktemp() do precompile_file, precompile_file_h
170-
# Run a repl process and replay our script
181+
# Collect statements from running a REPL process and replaying our REPL script
171182
pts, ptm = open_fake_pty()
172183
blackhole = Sys.isunix() ? "/dev/null" : "nul"
173184
if have_repl
@@ -212,12 +223,12 @@ function generate_precompile_statements()
212223
readavailable(output_copy)
213224
# Input our script
214225
if have_repl
215-
precompile_lines = split(precompile_script::String, '\n'; keepempty=false)
226+
precompile_lines = split(repl_script::String, '\n'; keepempty=false)
216227
curr = 0
217228
for l in precompile_lines
218229
sleep(0.1)
219230
curr += 1
220-
print("\rGenerating precompile statements... $curr/$(length(precompile_lines))")
231+
print("\rGenerating REPL precompile statements... $curr/$(length(precompile_lines))")
221232
# consume any other output
222233
bytesavailable(output_copy) > 0 && readavailable(output_copy)
223234
# push our input
@@ -237,57 +248,51 @@ function generate_precompile_statements()
237248
close(ptm)
238249
write(debug_output, "\n#### FINISHED ####\n")
239250

240-
# Extract the precompile statements from the precompile file
241-
statements = Set{String}()
242-
for statement in eachline(precompile_file_h)
251+
for statement in split(read(precompile_file, String), '\n')
243252
# Main should be completely clean
244253
occursin("Main.", statement) && continue
245254
push!(statements, statement)
246255
end
256+
end
247257

248-
for statement in split(hardcoded_precompile_statements::String, '\n')
249-
push!(statements, statement)
250-
end
251-
252-
# Create a staging area where all the loaded packages are available
253-
PrecompileStagingArea = Module()
254-
for (_pkgid, _mod) in Base.loaded_modules
255-
if !(_pkgid.name in ("Main", "Core", "Base"))
256-
eval(PrecompileStagingArea, :(const $(Symbol(_mod)) = $_mod))
257-
end
258+
# Create a staging area where all the loaded packages are available
259+
PrecompileStagingArea = Module()
260+
for (_pkgid, _mod) in Base.loaded_modules
261+
if !(_pkgid.name in ("Main", "Core", "Base"))
262+
eval(PrecompileStagingArea, :(const $(Symbol(_mod)) = $_mod))
258263
end
264+
end
259265

260-
# Execute the collected precompile statements
261-
n_succeeded = 0
262-
include_time = @elapsed for statement in sort(collect(statements))
263-
# println(statement)
264-
# The compiler has problem caching signatures with `Vararg{?, N}`. Replacing
265-
# N with a large number seems to work around it.
266-
statement = replace(statement, r"Vararg{(.*?), N} where N" => s"Vararg{\1, 100}")
267-
try
268-
Base.include_string(PrecompileStagingArea, statement)
269-
n_succeeded += 1
270-
print("\rExecuting precompile statements... $n_succeeded/$(length(statements))")
271-
catch
272-
# See #28808
273-
# @error "Failed to precompile $statement"
274-
end
266+
# Execute the collected precompile statements
267+
n_succeeded = 0
268+
include_time = @elapsed for statement in sort(collect(statements))
269+
# println(statement)
270+
# The compiler has problem caching signatures with `Vararg{?, N}`. Replacing
271+
# N with a large number seems to work around it.
272+
statement = replace(statement, r"Vararg{(.*?), N} where N" => s"Vararg{\1, 100}")
273+
try
274+
Base.include_string(PrecompileStagingArea, statement)
275+
n_succeeded += 1
276+
print("\rExecuting precompile statements... $n_succeeded/$(length(statements))")
277+
catch
278+
# See #28808
279+
# @error "Failed to precompile $statement"
275280
end
276-
println()
277-
if have_repl
278-
# Seems like a reasonable number right now, adjust as needed
279-
# comment out if debugging script
280-
@assert n_succeeded > 1200
281-
end
282-
283-
tot_time = time_ns() - start_time
284-
include_time *= 1e9
285-
gen_time = tot_time - include_time
286-
println("Precompilation complete. Summary:")
287-
print("Total ─────── "); Base.time_print(tot_time); println()
288-
print("Generation ── "); Base.time_print(gen_time); print(" "); show(IOContext(stdout, :compact=>true), gen_time / tot_time * 100); println("%")
289-
print("Execution ─── "); Base.time_print(include_time); print(" "); show(IOContext(stdout, :compact=>true), include_time / tot_time * 100); println("%")
290281
end
282+
println()
283+
if have_repl
284+
# Seems like a reasonable number right now, adjust as needed
285+
# comment out if debugging script
286+
@assert n_succeeded > 1200
287+
end
288+
289+
tot_time = time_ns() - start_time
290+
include_time *= 1e9
291+
gen_time = tot_time - include_time
292+
println("Precompilation complete. Summary:")
293+
print("Total ─────── "); Base.time_print(tot_time); println()
294+
print("Generation ── "); Base.time_print(gen_time); print(" "); show(IOContext(stdout, :compact=>true), gen_time / tot_time * 100); println("%")
295+
print("Execution ─── "); Base.time_print(include_time); print(" "); show(IOContext(stdout, :compact=>true), include_time / tot_time * 100); println("%")
291296

292297
return
293298
end

0 commit comments

Comments
 (0)