Skip to content

Commit 592152c

Browse files
vtjnashmaleadt
authored andcommitted
fix precompile process flag propagation (#56214)
CacheFlags could get set, but were never propagated to the target process, so the result would be unusable. Additionally, the debug and optimization levels were not synchronized with the sysimg, causing a regression in pkgimage usability after moving out stdlibs. Fixes #56207 Fixes #56054 Fixes #56206 (cherry picked from commit 82b1506)
1 parent cb575ab commit 592152c

File tree

9 files changed

+117
-68
lines changed

9 files changed

+117
-68
lines changed

base/Base.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,7 @@ include("deepcopy.jl")
508508
include("download.jl")
509509
include("summarysize.jl")
510510
include("errorshow.jl")
511+
include("util.jl")
511512

512513
include("initdefs.jl")
513514
Filesystem.__postinit__()
@@ -524,7 +525,6 @@ include("loading.jl")
524525

525526
# misc useful functions & macros
526527
include("timing.jl")
527-
include("util.jl")
528528
include("client.jl")
529529
include("asyncmap.jl")
530530

base/loading.jl

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,8 @@ function CacheFlags(cf::CacheFlags=CacheFlags(ccall(:jl_cache_flags, UInt8, ()))
16451645
opt_level === nothing ? cf.opt_level : opt_level
16461646
)
16471647
end
1648+
# reflecting jloptions.c defaults
1649+
const DefaultCacheFlags = CacheFlags(use_pkgimages=true, debug_level=isdebugbuild() ? 2 : 1, check_bounds=0, inline=true, opt_level=2)
16481650

16491651
function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
16501652
f = UInt8(0)
@@ -1656,12 +1658,29 @@ function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
16561658
return f
16571659
end
16581660

1661+
function translate_cache_flags(cacheflags::CacheFlags, defaultflags::CacheFlags)
1662+
opts = String[]
1663+
cacheflags.use_pkgimages != defaultflags.use_pkgimages && push!(opts, cacheflags.use_pkgimages ? "--pkgimages=yes" : "--pkgimages=no")
1664+
cacheflags.debug_level != defaultflags.debug_level && push!(opts, "-g$(cacheflags.debug_level)")
1665+
cacheflags.check_bounds != defaultflags.check_bounds && push!(opts, ("--check-bounds=auto", "--check-bounds=yes", "--check-bounds=no")[cacheflags.check_bounds + 1])
1666+
cacheflags.inline != defaultflags.inline && push!(opts, cacheflags.inline ? "--inline=yes" : "--inline=no")
1667+
cacheflags.opt_level != defaultflags.opt_level && push!(opts, "-O$(cacheflags.opt_level)")
1668+
return opts
1669+
end
1670+
16591671
function show(io::IO, cf::CacheFlags)
1660-
print(io, "use_pkgimages = ", cf.use_pkgimages)
1661-
print(io, ", debug_level = ", cf.debug_level)
1662-
print(io, ", check_bounds = ", cf.check_bounds)
1663-
print(io, ", inline = ", cf.inline)
1664-
print(io, ", opt_level = ", cf.opt_level)
1672+
print(io, "CacheFlags(")
1673+
print(io, "; use_pkgimages=")
1674+
print(io, cf.use_pkgimages)
1675+
print(io, ", debug_level=")
1676+
print(io, cf.debug_level)
1677+
print(io, ", check_bounds=")
1678+
print(io, cf.check_bounds)
1679+
print(io, ", inline=")
1680+
print(io, cf.inline)
1681+
print(io, ", opt_level=")
1682+
print(io, cf.opt_level)
1683+
print(io, ")")
16651684
end
16661685

16671686
struct ImageTarget
@@ -2848,7 +2867,8 @@ end
28482867

28492868
const PRECOMPILE_TRACE_COMPILE = Ref{String}()
28502869
function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::Union{Nothing, String},
2851-
concrete_deps::typeof(_concrete_dependencies), flags::Cmd=``, internal_stderr::IO = stderr, internal_stdout::IO = stdout, isext::Bool=false)
2870+
concrete_deps::typeof(_concrete_dependencies), flags::Cmd=``, cacheflags::CacheFlags=CacheFlags(),
2871+
internal_stderr::IO = stderr, internal_stdout::IO = stdout, isext::Bool=false)
28522872
@nospecialize internal_stderr internal_stdout
28532873
rm(output, force=true) # Remove file if it exists
28542874
output_o === nothing || rm(output_o, force=true)
@@ -2891,24 +2911,29 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
28912911
deps = deps_eltype * "[" * join(deps_strs, ",") * "]"
28922912
precomp_stack = "Base.PkgId[$(join(map(pkg_str, vcat(Base.precompilation_stack, pkg)), ", "))]"
28932913

2914+
if output_o === nothing
2915+
# remove options that make no difference given the other cache options
2916+
cacheflags = CacheFlags(cacheflags, opt_level=0)
2917+
end
2918+
opts = translate_cache_flags(cacheflags, CacheFlags()) # julia_cmd is generated for the running system, and must be fixed if running for precompile instead
28942919
if output_o !== nothing
28952920
@debug "Generating object cache file for $(repr("text/plain", pkg))"
28962921
cpu_target = get(ENV, "JULIA_CPU_TARGET", nothing)
2897-
opts = `--output-o $(output_o) --output-ji $(output) --output-incremental=yes`
2922+
push!(opts, "--output-o", output_o)
28982923
else
28992924
@debug "Generating cache file for $(repr("text/plain", pkg))"
29002925
cpu_target = nothing
2901-
opts = `-O0 --output-ji $(output) --output-incremental=yes`
29022926
end
2927+
push!(opts, "--output-ji", output)
2928+
isassigned(PRECOMPILE_TRACE_COMPILE) && push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])")
29032929

2904-
trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[]) --trace-compile-timing` : ``
29052930
io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd)
2906-
$(flags)
2907-
$(opts)
2908-
--startup-file=no --history-file=no --warn-overwrite=yes
2909-
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
2910-
$trace
2911-
-`,
2931+
$(flags)
2932+
$(opts)
2933+
--output-incremental=yes
2934+
--startup-file=no --history-file=no --warn-overwrite=yes
2935+
$(have_color === nothing ? "--color=auto" : have_color ? "--color=yes" : "--color=no")
2936+
-`,
29122937
"OPENBLAS_NUM_THREADS" => 1,
29132938
"JULIA_NUM_THREADS" => 1),
29142939
stderr = internal_stderr, stdout = internal_stdout),
@@ -3026,7 +3051,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in
30263051
close(tmpio_o)
30273052
close(tmpio_so)
30283053
end
3029-
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, flags, internal_stderr, internal_stdout, isext)
3054+
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, flags, cacheflags, internal_stderr, internal_stdout, isext)
30303055

30313056
if success(p)
30323057
if cache_objects
@@ -3997,5 +4022,5 @@ end
39974022

39984023
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing)) || @assert false
39994024
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String)) || @assert false
4000-
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, IO, IO)) || @assert false
4001-
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, IO, IO)) || @assert false
4025+
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, CacheFlags, IO, IO)) || @assert false
4026+
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, CacheFlags, IO, IO)) || @assert false

base/precompilation.jl

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ function printpkgstyle(io, header, msg; color=:light_green)
349349
end
350350

351351
const Config = Pair{Cmd, Base.CacheFlags}
352-
const PkgConfig = Tuple{Base.PkgId,Config}
352+
const PkgConfig = Tuple{PkgId,Config}
353353

354354
function precompilepkgs(pkgs::Vector{String}=String[];
355355
internal_call::Bool=false,
@@ -360,10 +360,23 @@ function precompilepkgs(pkgs::Vector{String}=String[];
360360
configs::Union{Config,Vector{Config}}=(``=>Base.CacheFlags()),
361361
io::IO=stderr,
362362
# asking for timing disables fancy mode, as timing is shown in non-fancy mode
363-
fancyprint::Bool = can_fancyprint(io) && !timing
364-
)
363+
fancyprint::Bool = can_fancyprint(io) && !timing)
364+
# monomorphize this to avoid latency problems
365+
_precompilepkgs(pkgs, internal_call, strict, warn_loaded, timing, _from_loading,
366+
configs isa Vector{Config} ? configs : [configs],
367+
IOContext{IO}(io), fancyprint)
368+
end
365369

366-
configs = configs isa Config ? [configs] : configs
370+
function _precompilepkgs(pkgs::Vector{String},
371+
internal_call::Bool,
372+
strict::Bool,
373+
warn_loaded::Bool,
374+
timing::Bool,
375+
_from_loading::Bool,
376+
configs::Vector{Config},
377+
io::IOContext{IO},
378+
fancyprint::Bool)
379+
requested_pkgs = copy(pkgs) # for understanding user intent
367380

368381
time_start = time_ns()
369382

@@ -379,17 +392,32 @@ function precompilepkgs(pkgs::Vector{String}=String[];
379392

380393
if _from_loading && !Sys.isinteractive() && Base.get_bool_env("JULIA_TESTS", false)
381394
# suppress passive loading printing in julia test suite. `JULIA_TESTS` is set in Base.runtests
382-
io = devnull
395+
io = IOContext{IO}(devnull)
383396
end
384397

398+
nconfigs = length(configs)
385399
hascolor = get(io, :color, false)::Bool
386400
color_string(cstr::String, col::Union{Int64, Symbol}) = _color_string(cstr, col, hascolor)
387401

388402
stale_cache = Dict{StaleCacheKey, Bool}()
389-
exts = Dict{Base.PkgId, String}() # ext -> parent
403+
exts = Dict{PkgId, String}() # ext -> parent
390404
# make a flat map of each dep and its direct deps
391-
depsmap = Dict{Base.PkgId, Vector{Base.PkgId}}()
392-
pkg_exts_map = Dict{Base.PkgId, Vector{Base.PkgId}}()
405+
depsmap = Dict{PkgId, Vector{PkgId}}()
406+
pkg_exts_map = Dict{PkgId, Vector{PkgId}}()
407+
408+
function describe_pkg(pkg::PkgId, is_direct_dep::Bool, flags::Cmd, cacheflags::Base.CacheFlags)
409+
name = haskey(exts, pkg) ? string(exts[pkg], "", pkg.name) : pkg.name
410+
name = is_direct_dep ? name : color_string(name, :light_black)
411+
if nconfigs > 1 && !isempty(flags)
412+
config_str = join(flags, " ")
413+
name *= color_string(" `$config_str`", :light_black)
414+
end
415+
if nconfigs > 1
416+
config_str = join(Base.translate_cache_flags(cacheflags, Base.DefaultCacheFlags), " ")
417+
name *= color_string(" $config_str", :light_black)
418+
end
419+
return name
420+
end
393421

394422
for (dep, deps) in env.deps
395423
pkg = Base.PkgId(dep, env.names[dep])
@@ -554,7 +582,6 @@ function precompilepkgs(pkgs::Vector{String}=String[];
554582
else
555583
target = "project"
556584
end
557-
nconfigs = length(configs)
558585
if nconfigs == 1
559586
if !isempty(only(configs)[1])
560587
target *= " for configuration $(join(only(configs)[1], " "))"
@@ -569,7 +596,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
569596
failed_deps = Dict{PkgConfig, String}()
570597
precomperr_deps = PkgConfig[] # packages that may succeed after a restart (i.e. loaded packages with no cache file)
571598

572-
print_lock = io isa Base.LibuvStream ? io.lock::ReentrantLock : ReentrantLock()
599+
print_lock = io.io isa Base.LibuvStream ? io.io.lock::ReentrantLock : ReentrantLock()
573600
first_started = Base.Event()
574601
printloop_should_exit::Bool = !fancyprint # exit print loop immediately if not fancy printing
575602
interrupted_or_done = Base.Event()
@@ -658,7 +685,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
658685
n_print_rows = 0
659686
while !printloop_should_exit
660687
lock(print_lock) do
661-
term_size = Base.displaysize_(io)
688+
term_size = displaysize(io)
662689
num_deps_show = term_size[1] - 3
663690
pkg_queue_show = if !interrupted_or_done.set && length(pkg_queue) > num_deps_show
664691
last(pkg_queue, num_deps_show)
@@ -673,20 +700,16 @@ function precompilepkgs(pkgs::Vector{String}=String[];
673700
bar.max = n_total - n_already_precomp
674701
# when sizing to the terminal width subtract a little to give some tolerance to resizing the
675702
# window between print cycles
676-
termwidth = Base.displaysize_(io)[2] - 4
703+
termwidth = displaysize(io)[2] - 4
677704
if !final_loop
678705
str = sprint(io -> show_progress(io, bar; termwidth, carriagereturn=false); context=io)
679706
print(iostr, Base._truncate_at_width_or_chars(true, str, termwidth), "\n")
680707
end
681708
for pkg_config in pkg_queue_show
682709
dep, config = pkg_config
683710
loaded = warn_loaded && haskey(Base.loaded_modules, dep)
684-
_name = haskey(exts, dep) ? string(exts[dep], "", dep.name) : dep.name
685-
name = dep in direct_deps ? _name : string(color_string(_name, :light_black))
686-
if nconfigs > 1 && !isempty(config[1])
687-
config_str = "$(join(config[1], " "))"
688-
name *= color_string(" $(config_str)", :light_black)
689-
end
711+
flags, cacheflags = config
712+
name = describe_pkg(dep, dep in direct_deps, flags, cacheflags)
690713
line = if pkg_config in precomperr_deps
691714
string(color_string(" ? ", Base.warn_color()), name)
692715
elseif haskey(failed_deps, pkg_config)
@@ -774,14 +797,11 @@ function precompilepkgs(pkgs::Vector{String}=String[];
774797
std_pipe = Base.link_pipe!(Pipe(); reader_supports_async=true, writer_supports_async=true)
775798
t_monitor = @async monitor_std(pkg_config, std_pipe; single_requested_pkg)
776799

777-
_name = haskey(exts, pkg) ? string(exts[pkg], "", pkg.name) : pkg.name
778-
name = is_direct_dep ? _name : string(color_string(_name, :light_black))
779-
if nconfigs > 1 && !isempty(flags)
780-
config_str = "$(join(flags, " "))"
781-
name *= color_string(" $(config_str)", :light_black)
782-
end
783-
!fancyprint && lock(print_lock) do
784-
isempty(pkg_queue) && printpkgstyle(io, :Precompiling, target)
800+
name = describe_pkg(pkg, is_direct_dep, flags, cacheflags)
801+
lock(print_lock) do
802+
if !fancyprint && isempty(pkg_queue)
803+
printpkgstyle(io, :Precompiling, something(target, "packages..."))
804+
end
785805
end
786806
push!(pkg_queue, pkg_config)
787807
started[pkg_config] = true

base/show.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,11 @@ end
324324

325325
convert(::Type{IOContext}, io::IOContext) = io
326326
convert(::Type{IOContext}, io::IO) = IOContext(io, ioproperties(io))::IOContext
327+
convert(::Type{IOContext{IO_t}}, io::IOContext{IO_t}) where {IO_t} = io
328+
convert(::Type{IOContext{IO_t}}, io::IO) where {IO_t} = IOContext{IO_t}(io, ioproperties(io))::IOContext{IO_t}
327329

328330
IOContext(io::IO) = convert(IOContext, io)
331+
IOContext{IO_t}(io::IO) where {IO_t} = convert(IOContext{IO_t}, io)
329332

330333
function IOContext(io::IO, KV::Pair)
331334
d = ioproperties(io)
@@ -427,7 +430,7 @@ get(io::IO, key, default) = default
427430
keys(io::IOContext) = keys(io.dict)
428431
keys(io::IO) = keys(ImmutableDict{Symbol,Any}())
429432

430-
displaysize(io::IOContext) = haskey(io, :displaysize) ? io[:displaysize]::Tuple{Int,Int} : Base.displaysize_(io.io)
433+
displaysize(io::IOContext) = haskey(io, :displaysize) ? io[:displaysize]::Tuple{Int,Int} : displaysize(io.io)
431434

432435
show_circular(io::IO, @nospecialize(x)) = false
433436
function show_circular(io::IOContext, @nospecialize(x))

base/util.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()); cpu_target::Unio
249249
end
250250

251251
function julia_exename()
252-
if !Base.isdebugbuild()
252+
if !isdebugbuild()
253253
return @static Sys.iswindows() ? "julia.exe" : "julia"
254254
else
255255
return @static Sys.iswindows() ? "julia-debug.exe" : "julia-debug"
@@ -512,7 +512,6 @@ function _crc32c(io::IO, nb::Integer, crc::UInt32=0x00000000)
512512
end
513513
_crc32c(io::IO, crc::UInt32=0x00000000) = _crc32c(io, typemax(Int64), crc)
514514
_crc32c(io::IOStream, crc::UInt32=0x00000000) = _crc32c(io, filesize(io)-position(io), crc)
515-
_crc32c(uuid::UUID, crc::UInt32=0x00000000) = _crc32c(uuid.value, crc)
516515
_crc32c(x::UInt128, crc::UInt32=0x00000000) =
517516
ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt128}, Csize_t), crc, x, 16)
518517
_crc32c(x::UInt64, crc::UInt32=0x00000000) =

base/uuid.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ let
3636
Base.hash(uuid::UUID, h::UInt) = hash(uuid_hash_seed, hash(convert(NTuple{2, UInt64}, uuid), h))
3737
end
3838

39+
_crc32c(uuid::UUID, crc::UInt32=0x00000000) = _crc32c(uuid.value, crc)
40+
3941
let
4042
@inline function uuid_kernel(s, i, u)
4143
_c = UInt32(@inbounds codeunit(s, i))

pkgimage.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ print-depot-path:
2525
@$(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e '@show Base.DEPOT_PATH')
2626

2727
$(BUILDDIR)/stdlib/%.image: $(JULIAHOME)/stdlib/Project.toml $(JULIAHOME)/stdlib/Manifest.toml $(INDEPENDENT_STDLIBS_SRCS) $(JULIA_DEPOT_PATH)/compiled
28-
@$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e 'Base.Precompilation.precompilepkgs(;configs=[``=>Base.CacheFlags(), `--check-bounds=yes`=>Base.CacheFlags(;check_bounds=1)])')
28+
@$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e \
29+
'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)])')
2930
touch $@
3031

3132
$(BUILDDIR)/stdlib/release.image: $(build_private_libdir)/sys.$(SHLIB_EXT)

src/staticdata_utils.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -600,15 +600,15 @@ static void write_mod_list(ios_t *s, jl_array_t *a)
600600
write_int32(s, 0);
601601
}
602602

603-
// OPT_LEVEL should always be the upper bits
604603
#define OPT_LEVEL 6
604+
#define DEBUG_LEVEL 1
605605

606606
JL_DLLEXPORT uint8_t jl_cache_flags(void)
607607
{
608608
// OOICCDDP
609609
uint8_t flags = 0;
610610
flags |= (jl_options.use_pkgimages & 1); // 0-bit
611-
flags |= (jl_options.debug_level & 3) << 1; // 1-2 bit
611+
flags |= (jl_options.debug_level & 3) << DEBUG_LEVEL; // 1-2 bit
612612
flags |= (jl_options.check_bounds & 3) << 3; // 3-4 bit
613613
flags |= (jl_options.can_inline & 1) << 5; // 5-bit
614614
flags |= (jl_options.opt_level & 3) << OPT_LEVEL; // 6-7 bit
@@ -631,14 +631,13 @@ JL_DLLEXPORT uint8_t jl_match_cache_flags(uint8_t requested_flags, uint8_t actua
631631
actual_flags &= ~1;
632632
}
633633

634-
// 2. Check all flags, except opt level must be exact
635-
uint8_t mask = (1 << OPT_LEVEL)-1;
634+
// 2. Check all flags, except opt level and debug level must be exact
635+
uint8_t mask = (~(3u << OPT_LEVEL) & ~(3u << DEBUG_LEVEL)) & 0x7f;
636636
if ((actual_flags & mask) != (requested_flags & mask))
637637
return 0;
638-
// 3. allow for higher optimization flags in cache
639-
actual_flags >>= OPT_LEVEL;
640-
requested_flags >>= OPT_LEVEL;
641-
return actual_flags >= requested_flags;
638+
// 3. allow for higher optimization and debug level flags in cache to minimize required compile option combinations
639+
return ((actual_flags >> OPT_LEVEL) & 3) >= ((requested_flags >> OPT_LEVEL) & 3) &&
640+
((actual_flags >> DEBUG_LEVEL) & 3) >= ((requested_flags >> DEBUG_LEVEL) & 3);
642641
}
643642

644643
JL_DLLEXPORT uint8_t jl_match_cache_flags_current(uint8_t flags)

0 commit comments

Comments
 (0)