Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement REPL replayer for Windows #28608

Merged
merged 1 commit into from
Aug 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 53 additions & 35 deletions contrib/generate_precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if !isdefined(Base, :uv_eventloop)
Base.reinit_stdio()
end
Base.include(@__MODULE__, joinpath(Sys.BINDIR, "..", "share", "julia", "test", "testhelpers", "FakePTYs.jl"))
import .FakePTYs: with_fake_pty
import .FakePTYs: open_fake_pty

CTRL_C = '\x03'
UP_ARROW = "\e[A"
Expand Down Expand Up @@ -43,6 +43,12 @@ if Pkg !== nothing
precompile_script *= Pkg.precompile_script
end

push!(LOAD_PATH, Sys.STDLIB)
using Sockets
Sockets.__init__()
using Libdl
empty!(LOAD_PATH)

function generate_precompile_statements()
start_time = time()

Expand All @@ -62,55 +68,56 @@ function generate_precompile_statements()
empty!(DEPOT_PATH)
end

# Create a staging area where all the loaded packages are available
PrecompileStagingArea = Module()
for (_pkgid, _mod) in Base.loaded_modules
if !(_pkgid.name in ("Main", "Core", "Base"))
eval(PrecompileStagingArea, :($(Symbol(_mod)) = $_mod))
end
end

# TODO: Implement REPL replayer for Windows
@static if !Sys.iswindows()
print("Generating precompile statements...")
sysimg = isempty(ARGS) ? joinpath(dirname(Sys.BINDIR), "lib", "julia", "sys.ji") : ARGS[1]
sysimg = isempty(ARGS) ? joinpath(dirname(Sys.BINDIR), "lib", "julia", "sys." * Libdl.dlext) : ARGS[1]

mktemp() do precompile_file, _
# Run a repl process and replay our script
stdout_accumulator, stderr_accumulator = IOBuffer(), IOBuffer()
with_fake_pty() do slave, master
with_fake_pty() do slave_err, master_err
repl_output_buffer = IOBuffer()
@static if Sys.iswindows()
# Fake being cygwin
pipename = """\\\\?\\pipe\\cygwin-$("0"^16)-pty10-abcdef"""
server = listen(pipename)
slave = connect(pipename)
@assert ccall(:jl_ispty, Cint, (Ptr{Cvoid},), slave.handle) == 1
master = accept(server)
else
slave, master = open_fake_pty()
end
done = false
withenv("JULIA_HISTORY" => tempname(), "JULIA_PROJECT" => nothing,
"TERM" => "") do
p = run(`$(julia_cmd()) -O0 --trace-compile=$precompile_file --sysimage $sysimg
--startup-file=no --color=yes`,
slave, slave, slave_err; wait=false)
--compile=all --startup-file=no --color=yes
-e 'import REPL; REPL.Terminals.is_precompiling[] = true'
-i`,
slave, slave, slave; wait=false)
readuntil(master, "julia>", keep=true)
for (tty, accumulator) in (master => stdout_accumulator,
master_err => stderr_accumulator)
@async begin
while true
done && break
write(accumulator, readavailable(tty))
end
write(repl_output_buffer, readavailable(master))
end
end
if have_repl
for l in split(precompile_script, '\n'; keepempty=false)
write(master, l, '\n')
end
end
# TODO Figure out why exit() on Windows doesn't exit the process
if Sys.iswindows()
print(master, "ccall(:_exit, Cvoid, (Cint,), 0)\n")
else
write(master, "exit()\n")
end
wait(p)
done = true
end
end
end
close(master)

# Check what the REPL displayed
# stdout_output = String(take!(stdout_accumulator))
# println(stdout_output)
# repl_output = String(take!(repl_output_buffer))
# println(repl_output)

# Extract the precompile statements from stderr
statements = Set{String}()
Expand All @@ -119,24 +126,35 @@ function generate_precompile_statements()
push!(statements, statement)
end

# Load the precompile statements
statements_ordered = join(sort(collect(statements)), '\n')
# println(statements_ordered)
if have_repl
# Seems like a reasonable number right now, adjust as needed
# comment out if debugging script
@assert length(statements) > 700
end

Base.include_string(PrecompileStagingArea, statements_ordered)
print(" $(length(statements)) generated in ")
Base.time_print((time() - start_time) * 10^9)
println()
# Create a staging area where all the loaded packages are available
PrecompileStagingArea = Module()
for (_pkgid, _mod) in Base.loaded_modules
if !(_pkgid.name in ("Main", "Core", "Base"))
eval(PrecompileStagingArea, :($(Symbol(_mod)) = $_mod))
end
end

# Fall back to explicit list on Windows, might as well include them
# for everyone though
Base.include(PrecompileStagingArea, "precompile_explicit.jl")
# Execute the collected precompile statements
include_time = @elapsed for statement in sort(collect(statements))
# println(statement)
try
Base.include_string(PrecompileStagingArea, statement)
catch ex
@error "Failed to precompile $statement"
rethrow(ex)
end
end
print(" $(length(statements)) generated in ")
tot_time = time() - start_time
Base.time_print(tot_time * 10^9)
print(" (overhead "); Base.time_print((tot_time - include_time) * 10^9); println(")")
end

return
end
Expand Down
Loading