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

Trace type stability checks we do #39

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
25 changes: 19 additions & 6 deletions src/StabilityCheck.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export @stable, @stable!, @stable!_nop,
SkippedUnionAlls, UnboundedUnionAlls, SkipMandatory,
Stb, Uns,
UConstr, UConstrExist, AnyParam, VarargParam, TcFail, OutOfFuel, GenericMethod,
SearchCfg, build_typesdb_scfg, default_scfg,
SearchCfg, build_typesdb_scfg, default_scfg, trace_scfg,

# Utils
split_method # mostly for testing
Expand Down Expand Up @@ -124,6 +124,11 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin
@debug "is_stable_method: $m"
global stepCount = 0

# trace TS checks and store to a file
if scfg.trace_checks
fchecks = open("checks", "a")
end

# preemptively load types DB if available: we may need to sample
# unbounded exists any minute
if scfg.typesDBcfg.use_types_db
Expand All @@ -142,12 +147,14 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin
# Step 2a: run type inference with the input type even if abstract
# and party if we're concrete
@debug "is_stable_method: check against signature (2a)"
try
if is_stable_call(func, sig_types)
return Stb(1)
if ! scfg.trace_checks # we don't want the shortcut if we're in the tracing mode
try
if is_stable_call(func, sig_types)
return Stb(1)
end
catch e
return TcFail(sig_types, e)
end
catch e
return TcFail(sig_types, e)
end

# Shortcut:
Expand Down Expand Up @@ -187,17 +194,23 @@ is_stable_method(m::Method, scfg :: SearchCfg = default_scfg) :: StCheck = begin

# the actual stability check
try
scfg.trace_checks &&
print_check(fchecks, m, ts)
if ! is_stable_call(func, ts)
push!(unst, ts)
if scfg.failfast
break
end
end
catch e
scfg.trace_checks &&
close(fchecks)
return TcFail(ts, e)
end
end

scfg.trace_checks &&
close(fchecks)
result isa OutOfFuel &&
return result
return if isempty(unst)
Expand Down
5 changes: 5 additions & 0 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ Base.@kwdef struct SearchCfg

typesDBcfg :: TypesDBCfg = TypesDBCfg()
# ^--- Parameters of the types DB.

trace_checks :: Bool = false
# ^-- create a file recording all type stability checks of a method
end

#
Expand All @@ -131,6 +134,8 @@ default_scfg = SearchCfg()

fast_scfg = SearchCfg(fuel=30)

trace_scfg = SearchCfg(trace_checks=true)

build_typesdb_scfg(inFile = intypesCsvFileDefault; sample_count :: Int = 100000) = begin
tdbFull = typesDB(inFile)
sampleCountActual = min(length(tdbFull),sample_count)
Expand Down
7 changes: 7 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,10 @@ is_module_nested(m::Module, outer::Module) :: Bool = begin
m = parentmodule(m)
end
end

# Print type stability check in a form of pseudo-method declaration
print_check(io, m::Method, @nospecialize(types)) = begin
print(io, "function $(m.name)(")
print(io, join(map(t->"::$t", types), ", "))
println(io, ")")
end
56 changes: 29 additions & 27 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -92,39 +92,42 @@ unstable_funion(x::Bool, y::Union{TwoSubtypes, Bool}) = if x 1 else "" end
# Tests
#

test_scfg = default_scfg

@testset "Simple stable " begin
t1 = is_stable_method(@which add1s(1))
global test_scfg
t1 = is_stable_method((@which add1s(1)), test_scfg)
@test isa(t1, Stb)

@test isa(is_stable_method(@which plus2s(1,1)) , Stb)
@test isa(is_stable_method(@which add1typcase(1)), OutOfFuel)
@test isa(is_stable_method((@which plus2s(1,1)), test_scfg) , Stb)
@test isa(is_stable_method((@which add1typcase(1)), test_scfg), OutOfFuel)

# cf. Note: generic methods
#@test isa(is_stable_method(@which rational_plusi(1//1,1//1)) , Stb)
#@test isa(is_stable_method((@which rational_plusi(1//1,1//1)), test_scfg) , Stb)

@test isa(is_stable_method(@which add1c(1.0 + 1.0im)) , Stb)
@test isa(is_stable_method((@which add1c(1.0 + 1.0im)), test_scfg) , Stb)
end

@testset "Simple out-of-fuel " begin
t1 = is_stable_method(@which add1i(1))
t1 = is_stable_method((@which add1i(1)), test_scfg)
@test isa(t1, OutOfFuel)
# @test length(t1.skipexist) == 1 &&
# contains("$t1.skipexist", "SentinelArrays.ChainedVectorIndex")
# SentinelArrays.ChainedVectorIndex comes from CSV, which we depend upon for
# reporting. Would be nice to factor out reporting

@test isa(is_stable_method(@which plus2i(1,1)) , OutOfFuel)
@test isa(is_stable_method(@which add1typcase(1)), OutOfFuel)
@test isa(is_stable_method((@which plus2i(1,1)), test_scfg) , OutOfFuel)
@test isa(is_stable_method((@which add1typcase(1)), test_scfg), OutOfFuel)

# cf. Note: generic methods
#@test isa(is_stable_method(@which rational_plusi(1//1,1//1)) , Stb)
#@test isa(is_stable_method((@which rational_plusi(1//1,1//1)), test_scfg) , Stb)
end

@testset "Simple unstable " begin
@test isa(is_stable_method(@which add1n(1)), UConstr)
@test isa(is_stable_method(@which plus2n(1,1)), UConstr)
@test isa(is_stable_method(@which trivial_unstable(1)), Uns)
res = is_stable_method(@which trivial_unstable2(true, SubtypeA()))
@test isa(is_stable_method((@which add1n(1)), test_scfg), UConstr)
@test isa(is_stable_method((@which plus2n(1,1)), test_scfg), UConstr)
@test isa(is_stable_method((@which trivial_unstable(1)), test_scfg), Uns)
res = is_stable_method((@which trivial_unstable2(true, SubtypeA())), test_scfg)
@test res isa Uns # &&
# TODO: fix the test by switching failfast off and uncomment
# length(res.fails) == 2 &&
Expand All @@ -134,16 +137,16 @@ end
# cf. Note: generic methods
# Alos, this used to fail when abstract instantiations are ON
# (compare to the similar test in the "stable" examples)
#@test isa(is_stable_method((@which rational_plusi(1//1,1//1)), SearchCfg(abstract_args=true)), Stb)
#@test isa(is_stable_method(((@which rational_plusi(1//1,1//1)), test_scfg), SearchCfg(abstract_args=true)), Stb)

# TODO: not sure why this one lives under unstable, needs investigation:
# @test isa(is_stable_method((@which add1c(1.0 + 1.0im)), SearchCfg(abstract_args=true)) , OutOfFuel)
# @test isa(is_stable_method(((@which add1c(1.0 + 1.0im)), test_scfg), SearchCfg(abstract_args=true)) , OutOfFuel)
end

@testset "Unions " begin
res = is_stable_method(@which stable_funion(true, true))
res = is_stable_method((@which stable_funion(true, true)), test_scfg)
@test res isa Stb
res = is_stable_method(@which unstable_funion(true, true))
res = is_stable_method((@which unstable_funion(true, true)), test_scfg)
@test res isa Uns # &&
# TODO: fix the test by switching failfast off and uncomment
# length(res.fails) == 3 &&
Expand All @@ -154,24 +157,24 @@ end

@testset "Special (Any, Varargs, Generic)" begin
f(x)=x
@test is_stable_method(@which f(2)) == AnyParam()
@test is_stable_method((@which f(2)), test_scfg) == AnyParam()
g(x...)=x[1]
@test is_stable_method(@which g(2)) == VarargParam()
@test is_stable_method((@which g(2)), test_scfg) == VarargParam()
gen(x::T) where T = 1
@test is_stable_method(@which gen(1)) == GenericMethod()
@test is_stable_method((@which gen(1)), test_scfg) == GenericMethod()
end

@testset "Fuel " begin
g(x::Int)=2
@test isa(is_stable_method((@which g(2)), SearchCfg(fuel=1)) , Stb)
@test isa(is_stable_method(((@which g(2))), SearchCfg(fuel=1)) , Stb)

h(x::Integer)=x
res = is_stable_method((@which h(2)), SearchCfg(fuel=1))
res = is_stable_method(((@which h(2))), SearchCfg(fuel=1))
@test res == OutOfFuel()

# Instantiations fuel
k(x::Complex{T} where T<:Integer)=x+1
t3 = is_stable_method((@which k(1+1im)), SearchCfg(fuel=1))
t3 = is_stable_method(((@which k(1+1im))), SearchCfg(fuel=1))
@test t3 isa OutOfFuel # &&
# TODO: decide if the rest is needed
# length(t3.skipexist) == 2 && # one for TooManyInst and
Expand Down Expand Up @@ -290,15 +293,14 @@ end
# See also "Special (Any, Varargs, Generic)" testset above.
#
typesdb_cfg = build_typesdb_scfg("merged-small.csv")
@test is_stable_method((@which id1(1)), typesdb_cfg) isa Stb
@test is_stable_method(((@which id1(1))), typesdb_cfg) isa Stb

myplus(x,y)=x+y
res = is_stable_method((@which myplus(1,2)), typesdb_cfg)
res = is_stable_method(((@which myplus(1,2))), typesdb_cfg)
@test res isa Stb

uns(x)=if x>1; x+1; else x+1.0 end
resUns = is_stable_method((@which uns(1)), typesdb_cfg)
@info resUns
resUns = is_stable_method(((@which uns(1))), typesdb_cfg)
@test resUns isa Uns
end

Expand Down
Loading