Skip to content

Commit 3c4af03

Browse files
authored
enhance the effectiveness of the test cases introduced in #53300 (#53478)
While experimenting with precompilation for external absints on builds just after #53300 was merged, I found that the test case for `CustomAbstractInterpreterCaching2.jl` fails if the test case for `CustomAbstractInterpreterCaching1.jl` isn't run in the same session beforehand. That is probably because of the previous lack of support for proper `CodeInstance` caching. To address this, I've changed the tests to run in separate processes in this commit. Note that it appears that a recent refactor concerning `CodeInstance` might have resolved this issue, so the new test cases runs successfully on master. However, I suspect the fix hasn't been applied to v1.11 yet, we would need more research.
1 parent b730d33 commit 3c4af03

File tree

4 files changed

+217
-182
lines changed

4 files changed

+217
-182
lines changed

test/precompile.jl

Lines changed: 7 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
original_depot_path = copy(Base.DEPOT_PATH)
4-
original_load_path = copy(Base.LOAD_PATH)
5-
63
using Test, Distributed, Random, Logging
74
using REPL # doc lookup function
85

6+
include("precompile_utils.jl")
7+
98
Foo_module = :Foo4b3a94a1a081a8cb
109
Foo2_module = :F2oo4b3a94a1a081a8cb
1110
FooBase_module = :FooBase4b3a94a1a081a8cb
@@ -16,37 +15,6 @@ FooBase_module = :FooBase4b3a94a1a081a8cb
1615
end
1716
using .ConflictingBindings
1817

19-
function precompile_test_harness(@nospecialize(f), testset::String)
20-
@testset "$testset" begin
21-
precompile_test_harness(f, true)
22-
end
23-
end
24-
function precompile_test_harness(@nospecialize(f), separate::Bool)
25-
load_path = mktempdir()
26-
load_cache_path = separate ? mktempdir() : load_path
27-
try
28-
pushfirst!(LOAD_PATH, load_path)
29-
pushfirst!(DEPOT_PATH, load_cache_path)
30-
f(load_path)
31-
finally
32-
try
33-
rm(load_path, force=true, recursive=true)
34-
catch err
35-
@show err
36-
end
37-
if separate
38-
try
39-
rm(load_cache_path, force=true, recursive=true)
40-
catch err
41-
@show err
42-
end
43-
end
44-
filter!(()(load_path), LOAD_PATH)
45-
separate && filter!(()(load_cache_path), DEPOT_PATH)
46-
end
47-
nothing
48-
end
49-
5018
# method root provenance
5119

5220
rootid(m::Module) = Base.module_build_id(Base.parentmodule(m)) % UInt64
@@ -1713,150 +1681,10 @@ precompile_test_harness("issue #46296") do load_path
17131681
(@eval (using CodeInstancePrecompile))
17141682
end
17151683

1716-
let newinterp_path = abspath("compiler/newinterp.jl")
1717-
precompile_test_harness("AbstractInterpreter caching") do load_path
1718-
write(joinpath(load_path, "SimpleModule.jl"), :(module SimpleModule
1719-
basic_callee(x) = x
1720-
basic_caller(x) = basic_callee(x)
1721-
end) |> string)
1722-
1723-
write(joinpath(load_path, "CustomAbstractInterpreterCaching.jl"), :(module CustomAbstractInterpreterCaching
1724-
import SimpleModule: basic_caller, basic_callee
1725-
1726-
module Custom
1727-
include("$($newinterp_path)")
1728-
@newinterp PrecompileInterpreter
1729-
end
1730-
1731-
Base.return_types((Float64,)) do x
1732-
basic_caller(x)
1733-
end
1734-
Base.return_types((Float64,); interp=Custom.PrecompileInterpreter()) do x
1735-
basic_caller(x)
1736-
end
1737-
Base.return_types((Vector{Float64},)) do x
1738-
sum(x)
1739-
end
1740-
Base.return_types((Vector{Float64},); interp=Custom.PrecompileInterpreter()) do x
1741-
sum(x)
1742-
end
1743-
end) |> string)
1744-
Base.compilecache(Base.PkgId("CustomAbstractInterpreterCaching"))
1745-
@eval let
1746-
using CustomAbstractInterpreterCaching
1747-
cache_owner = Core.Compiler.cache_owner(
1748-
CustomAbstractInterpreterCaching.Custom.PrecompileInterpreter())
1749-
let m = only(methods(CustomAbstractInterpreterCaching.basic_callee))
1750-
mi = only(Base.specializations(m))
1751-
ci = mi.cache
1752-
@test isdefined(ci, :next)
1753-
@test ci.owner === nothing
1754-
@test ci.max_world == typemax(UInt)
1755-
ci = ci.next
1756-
@test !isdefined(ci, :next)
1757-
@test ci.owner === cache_owner
1758-
@test ci.max_world == typemax(UInt)
1759-
end
1760-
let m = only(methods(sum, (Vector{Float64},)))
1761-
found = false
1762-
for mi in Base.specializations(m)
1763-
if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}}
1764-
ci = mi.cache
1765-
@test isdefined(ci, :next)
1766-
@test ci.owner === cache_owner
1767-
@test ci.max_world == typemax(UInt)
1768-
ci = ci.next
1769-
@test !isdefined(ci, :next)
1770-
@test ci.owner === nothing
1771-
@test ci.max_world == typemax(UInt)
1772-
found = true
1773-
break
1774-
end
1775-
end
1776-
@test found
1777-
end
1778-
end
1779-
1780-
write(joinpath(load_path, "CustomAbstractInterpreterCaching2.jl"), :(module CustomAbstractInterpreterCaching2
1781-
import SimpleModule: basic_caller, basic_callee
1782-
1783-
module Custom
1784-
const CC = Core.Compiler
1785-
include("$($newinterp_path)")
1786-
@newinterp PrecompileInterpreter
1787-
struct CustomData
1788-
inferred
1789-
CustomData(@nospecialize inferred) = new(inferred)
1790-
end
1791-
function CC.transform_result_for_cache(interp::PrecompileInterpreter,
1792-
mi::Core.MethodInstance, valid_worlds::CC.WorldRange, result::CC.InferenceResult)
1793-
inferred_result = @invoke CC.transform_result_for_cache(interp::CC.AbstractInterpreter,
1794-
mi::Core.MethodInstance, valid_worlds::CC.WorldRange, result::CC.InferenceResult)
1795-
return CustomData(inferred_result)
1796-
end
1797-
function CC.src_inlining_policy(interp::PrecompileInterpreter, @nospecialize(src),
1798-
@nospecialize(info::CC.CallInfo), stmt_flag::UInt32)
1799-
if src isa CustomData
1800-
src = src.inferred
1801-
end
1802-
return @invoke CC.src_inlining_policy(interp::CC.AbstractInterpreter, src::Any,
1803-
info::CC.CallInfo, stmt_flag::UInt32)
1804-
end
1805-
CC.retrieve_ir_for_inlining(cached_result::Core.CodeInstance, src::CustomData) =
1806-
CC.retrieve_ir_for_inlining(cached_result, src.inferred)
1807-
CC.retrieve_ir_for_inlining(mi::Core.MethodInstance, src::CustomData, preserve_local_sources::Bool) =
1808-
CC.retrieve_ir_for_inlining(mi, src.inferred, preserve_local_sources)
1809-
end
1810-
1811-
Base.return_types((Float64,)) do x
1812-
basic_caller(x)
1813-
end
1814-
Base.return_types((Float64,); interp=Custom.PrecompileInterpreter()) do x
1815-
basic_caller(x)
1816-
end
1817-
Base.return_types((Vector{Float64},)) do x
1818-
sum(x)
1819-
end
1820-
Base.return_types((Vector{Float64},); interp=Custom.PrecompileInterpreter()) do x
1821-
sum(x)
1822-
end
1823-
end) |> string)
1824-
Base.compilecache(Base.PkgId("CustomAbstractInterpreterCaching2"))
1825-
@eval let
1826-
using CustomAbstractInterpreterCaching2
1827-
cache_owner = Core.Compiler.cache_owner(
1828-
CustomAbstractInterpreterCaching2.Custom.PrecompileInterpreter())
1829-
let m = only(methods(CustomAbstractInterpreterCaching2.basic_callee))
1830-
mi = only(Base.specializations(m))
1831-
ci = mi.cache
1832-
@test isdefined(ci, :next)
1833-
@test ci.owner === nothing
1834-
@test ci.max_world == typemax(UInt)
1835-
ci = ci.next
1836-
@test !isdefined(ci, :next)
1837-
@test ci.owner === cache_owner
1838-
@test ci.max_world == typemax(UInt)
1839-
end
1840-
let m = only(methods(sum, (Vector{Float64},)))
1841-
found = false
1842-
for mi = Base.specializations(m)
1843-
if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}}
1844-
ci = mi.cache
1845-
@test isdefined(ci, :next)
1846-
@test ci.owner === cache_owner
1847-
@test ci.max_world == typemax(UInt)
1848-
ci = ci.next
1849-
@test !isdefined(ci, :next)
1850-
@test ci.owner === nothing
1851-
@test ci.max_world == typemax(UInt)
1852-
found = true
1853-
break
1854-
end
1855-
end
1856-
@test found
1857-
end
1858-
end
1859-
end
1684+
@testset "Precompile external abstract interpreter" begin
1685+
dir = @__DIR__
1686+
@test success(pipeline(Cmd(`$(Base.julia_cmd()) precompile_absint1.jl`; dir); stdout, stderr))
1687+
@test success(pipeline(Cmd(`$(Base.julia_cmd()) precompile_absint2.jl`; dir); stdout, stderr))
18601688
end
18611689

18621690
precompile_test_harness("Recursive types") do load_path
@@ -2098,7 +1926,4 @@ precompile_test_harness("Test flags") do load_path
20981926
@test !Base.isprecompiled(id, ;flags=current_flags)
20991927
end
21001928

2101-
empty!(Base.DEPOT_PATH)
2102-
append!(Base.DEPOT_PATH, original_depot_path)
2103-
empty!(Base.LOAD_PATH)
2104-
append!(Base.LOAD_PATH, original_load_path)
1929+
finish_precompile_test!()

test/precompile_absint1.jl

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
using Test
4+
5+
include("precompile_utils.jl")
6+
7+
precompile_test_harness() do load_path
8+
write(joinpath(load_path, "SimpleModule.jl"), :(module SimpleModule
9+
basic_callee(x) = x
10+
basic_caller(x) = basic_callee(x)
11+
end) |> string)
12+
13+
newinterp_path = abspath("compiler/newinterp.jl")
14+
write(joinpath(load_path, "TestAbsIntPrecompile1.jl"), :(module TestAbsIntPrecompile1
15+
import SimpleModule: basic_caller, basic_callee
16+
17+
module Custom
18+
include("$($newinterp_path)")
19+
@newinterp PrecompileInterpreter
20+
end
21+
22+
Base.return_types((Float64,)) do x
23+
basic_caller(x)
24+
end
25+
Base.return_types((Float64,); interp=Custom.PrecompileInterpreter()) do x
26+
basic_caller(x)
27+
end
28+
Base.return_types((Vector{Float64},)) do x
29+
sum(x)
30+
end
31+
Base.return_types((Vector{Float64},); interp=Custom.PrecompileInterpreter()) do x
32+
sum(x)
33+
end
34+
end) |> string)
35+
Base.compilecache(Base.PkgId("TestAbsIntPrecompile1"))
36+
37+
@eval let
38+
using TestAbsIntPrecompile1
39+
cache_owner = Core.Compiler.cache_owner(
40+
TestAbsIntPrecompile1.Custom.PrecompileInterpreter())
41+
let m = only(methods(TestAbsIntPrecompile1.basic_callee))
42+
mi = only(Base.specializations(m))
43+
ci = mi.cache
44+
@test isdefined(ci, :next)
45+
@test ci.owner === nothing
46+
@test ci.max_world == typemax(UInt)
47+
ci = ci.next
48+
@test !isdefined(ci, :next)
49+
@test ci.owner === cache_owner
50+
@test ci.max_world == typemax(UInt)
51+
end
52+
let m = only(methods(sum, (Vector{Float64},)))
53+
found = false
54+
for mi in Base.specializations(m)
55+
if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}}
56+
ci = mi.cache
57+
@test isdefined(ci, :next)
58+
@test ci.owner === cache_owner
59+
@test ci.max_world == typemax(UInt)
60+
ci = ci.next
61+
@test !isdefined(ci, :next)
62+
@test ci.owner === nothing
63+
@test ci.max_world == typemax(UInt)
64+
found = true
65+
break
66+
end
67+
end
68+
@test found
69+
end
70+
end
71+
end
72+
73+
finish_precompile_test!()

test/precompile_absint2.jl

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# This file is a part of Julia. License is MIT: https://julialang.org/license
2+
3+
using Test
4+
5+
include("precompile_utils.jl")
6+
7+
precompile_test_harness() do load_path
8+
write(joinpath(load_path, "SimpleModule.jl"), :(module SimpleModule
9+
basic_callee(x) = x
10+
basic_caller(x) = basic_callee(x)
11+
end) |> string)
12+
13+
newinterp_path = abspath("compiler/newinterp.jl")
14+
write(joinpath(load_path, "TestAbsIntPrecompile2.jl"), :(module TestAbsIntPrecompile2
15+
import SimpleModule: basic_caller, basic_callee
16+
17+
module Custom
18+
const CC = Core.Compiler
19+
include("$($newinterp_path)")
20+
@newinterp PrecompileInterpreter
21+
struct CustomData
22+
inferred
23+
CustomData(@nospecialize inferred) = new(inferred)
24+
end
25+
function CC.transform_result_for_cache(interp::PrecompileInterpreter,
26+
mi::Core.MethodInstance, valid_worlds::CC.WorldRange, result::CC.InferenceResult)
27+
inferred_result = @invoke CC.transform_result_for_cache(interp::CC.AbstractInterpreter,
28+
mi::Core.MethodInstance, valid_worlds::CC.WorldRange, result::CC.InferenceResult)
29+
return CustomData(inferred_result)
30+
end
31+
function CC.src_inlining_policy(interp::PrecompileInterpreter, @nospecialize(src),
32+
@nospecialize(info::CC.CallInfo), stmt_flag::UInt32)
33+
if src isa CustomData
34+
src = src.inferred
35+
end
36+
return @invoke CC.src_inlining_policy(interp::CC.AbstractInterpreter, src::Any,
37+
info::CC.CallInfo, stmt_flag::UInt32)
38+
end
39+
CC.retrieve_ir_for_inlining(cached_result::Core.CodeInstance, src::CustomData) =
40+
CC.retrieve_ir_for_inlining(cached_result, src.inferred)
41+
CC.retrieve_ir_for_inlining(mi::Core.MethodInstance, src::CustomData, preserve_local_sources::Bool) =
42+
CC.retrieve_ir_for_inlining(mi, src.inferred, preserve_local_sources)
43+
end
44+
45+
Base.return_types((Float64,)) do x
46+
basic_caller(x)
47+
end
48+
Base.return_types((Float64,); interp=Custom.PrecompileInterpreter()) do x
49+
basic_caller(x)
50+
end
51+
Base.return_types((Vector{Float64},)) do x
52+
sum(x)
53+
end
54+
Base.return_types((Vector{Float64},); interp=Custom.PrecompileInterpreter()) do x
55+
sum(x)
56+
end
57+
end) |> string)
58+
Base.compilecache(Base.PkgId("TestAbsIntPrecompile2"))
59+
60+
@eval let
61+
using TestAbsIntPrecompile2
62+
cache_owner = Core.Compiler.cache_owner(
63+
TestAbsIntPrecompile2.Custom.PrecompileInterpreter())
64+
let m = only(methods(TestAbsIntPrecompile2.basic_callee))
65+
mi = only(Base.specializations(m))
66+
ci = mi.cache
67+
@test isdefined(ci, :next)
68+
@test ci.owner === nothing
69+
@test ci.max_world == typemax(UInt)
70+
ci = ci.next
71+
@test !isdefined(ci, :next)
72+
@test ci.owner === cache_owner
73+
@test ci.max_world == typemax(UInt)
74+
end
75+
let m = only(methods(sum, (Vector{Float64},)))
76+
found = false
77+
for mi = Base.specializations(m)
78+
if mi isa Core.MethodInstance && mi.specTypes == Tuple{typeof(sum),Vector{Float64}}
79+
ci = mi.cache
80+
@test isdefined(ci, :next)
81+
@test ci.owner === cache_owner
82+
@test ci.max_world == typemax(UInt)
83+
ci = ci.next
84+
@test !isdefined(ci, :next)
85+
@test ci.owner === nothing
86+
@test ci.max_world == typemax(UInt)
87+
found = true
88+
break
89+
end
90+
end
91+
@test found
92+
end
93+
end
94+
end
95+
96+
finish_precompile_test!()

0 commit comments

Comments
 (0)