-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wip: generate precompile as part of build process
Whoa there!
You have triggered an abuse detection mechanism.
Please wait a few minutes before you try again;
in some cases this may take up to an hour.
1 parent
565bd4d
commit fd07681
Showing
14 changed files
with
212 additions
and
877 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
Base.__init__() | ||
|
||
function create_precompile_file() | ||
println("Generating precompile statements...") | ||
t = time() | ||
|
||
sysimg = joinpath(dirname(Sys.BINDIR), "lib", "julia", "sys") | ||
tmp = tempname() | ||
if haskey(Base.loaded_modules, Base.PkgId(Base.UUID("3fa0cd96-eef1-5676-8a61-b3b8758bbffb"), "REPL")) | ||
setup = """ | ||
@async while true | ||
sleep(0.01) | ||
if isdefined(Base, :active_repl) | ||
exit(0) | ||
end | ||
end | ||
""" | ||
# Record precompile statements when starting a julia session with a repl | ||
run(pipeline(`$(Base.julia_cmd()) --sysimage $sysimg.ji --trace-compile=yes -O0 --banner=no --startup-file=no -e $setup -i`; stderr=tmp)) | ||
|
||
# Replay a REPL script | ||
repl_replay = joinpath(@__DIR__, "precompile_replay.jl") | ||
if isfile(repl_replay) | ||
run(pipeline(`$(Base.julia_cmd()) --sysimage $sysimg.ji --trace-compile=yes -O0 --startup-file=no $repl_replay`; stderr=tmp, append=true)) | ||
end | ||
else | ||
# No REPL, just record the startup | ||
run(pipeline(`$(Base.julia_cmd()) --sysimage $sysimg.ji --trace-compile=yes -O0 --startup-file=no -e0`; stderr=tmp)) | ||
end | ||
|
||
isfile(tmp) || return | ||
|
||
# Replace the FakeTermiaal with a TTYYerminal and filter out everything we compiled in Main | ||
precompiles = readlines(tmp) | ||
new_precompiles = Set{String}() | ||
for statement in precompiles | ||
startswith(statement, "precompile(Tuple{") || continue | ||
statement = replace(statement, "FakeTerminals.FakeTerminal" => "REPL.Terminals.TTYTerminal") | ||
(occursin(r"Main.", statement) || occursin(r"FakeTerminals.", statement)) && continue | ||
push!(new_precompiles, statement) | ||
end | ||
|
||
write(tmp, join(sort(collect(new_precompiles)), '\n')) | ||
# Load the precompile statements | ||
let | ||
PrecompileStagingArea = Module() | ||
for (_pkgid, _mod) in Base.loaded_modules | ||
if !(_pkgid.name in ("Main", "Core", "Base")) | ||
@eval PrecompileStagingArea $(Symbol(_mod)) = $_mod | ||
end | ||
end | ||
|
||
Base.include(PrecompileStagingArea, tmp) | ||
@eval PrecompileStagingArea begin | ||
# Could startup with REPL banner instead but it is a bit visually noisy, so just precompile it here. | ||
precompile(Tuple{typeof(REPL.banner), REPL.Terminals.TTYTerminal, REPL.Terminals.TTYTerminal}) | ||
end | ||
|
||
end | ||
|
||
print("Precompile statements generated in "), Base.time_print((time() - t) * 10^9) | ||
println() | ||
return | ||
end | ||
|
||
create_precompile_file() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
Base.__init__() | ||
|
||
import REPL | ||
include(joinpath(Sys.STDLIB, "REPL", "test", "FakeTerminals.jl")) | ||
import .FakeTerminals.FakeTerminal | ||
include(joinpath(Sys.STDLIB, "REPL", "test", "fake_repl.jl")) | ||
|
||
const CTRL_C = '\x03' | ||
const UP_ARROW = "\e[A" | ||
const DOWN_ARROW = "\e[B" | ||
|
||
# TODO: Have a utility to generate this from a real REPL session? | ||
precompile_script = """ | ||
2+2 | ||
println("Hello World") | ||
@time 1+1 | ||
?reinterpret | ||
;pwd | ||
using Ra\t$CTRL_C | ||
\\alpha\t$CTRL_C | ||
\e[200~paste here ;)\e[201~"$CTRL_C | ||
$UP_ARROW$DOWN_ARROW | ||
123\b\b\b$CTRL_C | ||
f(x) = x03 | ||
f(1,2) | ||
[][1] | ||
""" | ||
|
||
|
||
function run_repl() | ||
# Writing ^C to the repl will cause sigint, so let's not die on that | ||
ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0) | ||
|
||
fake_repl() do stdin_write, stdout_read, repl | ||
repl.specialdisplay = REPL.REPLDisplay(repl) | ||
repl.history_file = false | ||
|
||
repltask = @async begin | ||
REPL.run_repl(repl) | ||
end | ||
|
||
global inc = false | ||
global b = Condition() | ||
global c = Condition() | ||
mod = @__MODULE__ | ||
let cmd = "\"Hello REPL\"" | ||
write(stdin_write, "$mod.inc || wait($mod.b); r = $cmd; notify($mod.c); r\r") | ||
end | ||
inc = true | ||
notify(b) | ||
wait(c) | ||
|
||
write(stdin_write, precompile_script) | ||
|
||
s = readavailable(stdout_read) | ||
|
||
# Close REPL ^D | ||
write(stdin_write, '\x04') | ||
Base._wait(repltask) | ||
|
||
nothing | ||
end | ||
ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 1) | ||
end | ||
|
||
|
||
run_repl() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
|
||
using Test | ||
|
||
function kill_timer(delay) | ||
# Give ourselves a generous timer here, just to prevent | ||
# this causing e.g. a CI hang when there's something unexpected in the output. | ||
# This is really messy and leaves the process in an undefined state. | ||
# the proper and correct way to do this in real code would be to destroy the | ||
# IO handles: `close(stdout_read); close(stdin_write)` | ||
test_task = current_task() | ||
function kill_test(t) | ||
# **DON'T COPY ME.** | ||
# The correct way to handle timeouts is to close the handle: | ||
# e.g. `close(stdout_read); close(stdin_write)` | ||
schedule(test_task, "hard kill repl test"; error=true) | ||
print(stderr, "WARNING: attempting hard kill of repl test after exceeding timeout\n") | ||
end | ||
return Timer(kill_test, delay) | ||
end | ||
|
||
# REPL tests | ||
function fake_repl(@nospecialize(f); options::REPL.Options=REPL.Options(confirm_exit=false)) | ||
# Use pipes so we can easily do blocking reads | ||
# In the future if we want we can add a test that the right object | ||
# gets displayed by intercepting the display | ||
input = Pipe() | ||
output = Pipe() | ||
err = Pipe() | ||
Base.link_pipe!(input, reader_supports_async=true, writer_supports_async=true) | ||
Base.link_pipe!(output, reader_supports_async=true, writer_supports_async=true) | ||
Base.link_pipe!(err, reader_supports_async=true, writer_supports_async=true) | ||
|
||
repl = REPL.LineEditREPL(FakeTerminal(input.out, output.in, err.in), true) | ||
repl.options = options | ||
|
||
hard_kill = kill_timer(900) # Your debugging session starts now. You have 15 minutes. Go. | ||
f(input.in, output.out, repl) | ||
t = @async begin | ||
close(input.in) | ||
close(output.in) | ||
close(err.in) | ||
end | ||
@test read(err.out, String) == "" | ||
#display(read(output.out, String)) | ||
#print(read(output.out, String)) | ||
Base._wait(t) | ||
close(hard_kill) | ||
nothing | ||
end |
Whoa there!
You have triggered an abuse detection mechanism.
Please wait a few minutes before you try again;
in some cases this may take up to an hour.