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

Add a testsuite for inference caching #567

Merged
merged 16 commits into from
Apr 16, 2024
Merged
6 changes: 6 additions & 0 deletions test/Native/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name = "Native"
uuid = "fdcda96a-3e7d-4dd7-839b-bda323ec0835"
version = "0.1.0"

[deps]
GPUCompiler = "61eb1bfa-7361-4325-ad38-22787b887f55"
5 changes: 5 additions & 0 deletions test/Native/src/Native.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Native

include("compiler.jl")

end # module Native
69 changes: 69 additions & 0 deletions test/Native/src/compiler.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using GPUCompiler

# create a native test compiler, and generate reflection methods for it

include("../../runtime.jl")

# local method table for device functions
Base.Experimental.@MethodTable(test_method_table)

struct CompilerParams <: AbstractCompilerParams
entry_safepoint::Bool
method_table

CompilerParams(entry_safepoint::Bool=false, method_table=test_method_table) =
new(entry_safepoint, method_table)
end

NativeCompilerJob = CompilerJob{NativeCompilerTarget,CompilerParams}
GPUCompiler.runtime_module(::NativeCompilerJob) = TestRuntime

GPUCompiler.method_table(@nospecialize(job::NativeCompilerJob)) = job.config.params.method_table
GPUCompiler.can_safepoint(@nospecialize(job::NativeCompilerJob)) = job.config.params.entry_safepoint

function create_job(@nospecialize(func), @nospecialize(types); kernel::Bool=false,
entry_abi=:specfunc, entry_safepoint::Bool=false, always_inline=false,
method_table=test_method_table, kwargs...)
source = methodinstance(typeof(func), Base.to_tuple_type(types), Base.get_world_counter())
target = NativeCompilerTarget()
params = CompilerParams(entry_safepoint, method_table)
config = CompilerConfig(target, params; kernel, entry_abi, always_inline)
CompilerJob(source, config), kwargs
end

function code_typed(@nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_typed(job; kwargs...)
end

function code_warntype(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_warntype(io, job; kwargs...)
end

function code_llvm(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_llvm(io, job; kwargs...)
end

function code_native(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_native(io, job; kwargs...)
end

# aliases without ::IO argument
for method in (:code_warntype, :code_llvm, :code_native)
method = Symbol("$(method)")
@eval begin
$method(@nospecialize(func), @nospecialize(types); kwargs...) =
$method(stdout, func, types; kwargs...)
end
end

# simulates codegen for a kernel function: validates by default
function code_execution(@nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kernel=true, kwargs...)
JuliaContext() do ctx
GPUCompiler.compile(:asm, job; kwargs...)
end
end
73 changes: 1 addition & 72 deletions test/native_testsetup.jl
Original file line number Diff line number Diff line change
@@ -1,74 +1,3 @@
@testsetup module Native

using GPUCompiler


# create a native test compiler, and generate reflection methods for it

include("runtime.jl")

# local method table for device functions
Base.Experimental.@MethodTable(test_method_table)

struct CompilerParams <: AbstractCompilerParams
entry_safepoint::Bool
method_table

CompilerParams(entry_safepoint::Bool=false, method_table=test_method_table) =
new(entry_safepoint, method_table)
end

NativeCompilerJob = CompilerJob{NativeCompilerTarget,CompilerParams}
GPUCompiler.runtime_module(::NativeCompilerJob) = TestRuntime

GPUCompiler.method_table(@nospecialize(job::NativeCompilerJob)) = job.config.params.method_table
GPUCompiler.can_safepoint(@nospecialize(job::NativeCompilerJob)) = job.config.params.entry_safepoint

function create_job(@nospecialize(func), @nospecialize(types); kernel::Bool=false,
entry_abi=:specfunc, entry_safepoint::Bool=false, always_inline=false,
method_table=test_method_table, kwargs...)
source = methodinstance(typeof(func), Base.to_tuple_type(types), Base.get_world_counter())
target = NativeCompilerTarget()
params = CompilerParams(entry_safepoint, method_table)
config = CompilerConfig(target, params; kernel, entry_abi, always_inline)
CompilerJob(source, config), kwargs
end

function code_typed(@nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_typed(job; kwargs...)
end

function code_warntype(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_warntype(io, job; kwargs...)
end

function code_llvm(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_llvm(io, job; kwargs...)
end

function code_native(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kwargs...)
GPUCompiler.code_native(io, job; kwargs...)
end

# aliases without ::IO argument
for method in (:code_warntype, :code_llvm, :code_native)
method = Symbol("$(method)")
@eval begin
$method(@nospecialize(func), @nospecialize(types); kwargs...) =
$method(stdout, func, types; kwargs...)
end
end

# simulates codegen for a kernel function: validates by default
function code_execution(@nospecialize(func), @nospecialize(types); kwargs...)
job, kwargs = create_job(func, types; kernel=true, kwargs...)
JuliaContext() do ctx
GPUCompiler.compile(:asm, job; kwargs...)
end
end

include("Native/src/compiler.jl")
end
99 changes: 99 additions & 0 deletions test/precompile_tests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
@testitem "Precompile" begin

using GPUCompiler
pushfirst!(LOAD_PATH, joinpath(@__DIR__, "Native"))

import Native

function precompile_test_harness(@nospecialize(f), testset::String)
@testset "$testset" begin
precompile_test_harness(f, true)
end
end
function precompile_test_harness(@nospecialize(f), separate::Bool)
load_path = mktempdir()
load_cache_path = separate ? mktempdir() : load_path
try
pushfirst!(LOAD_PATH, load_path)
pushfirst!(DEPOT_PATH, load_cache_path)
f(load_path)
finally
try
rm(load_path, force=true, recursive=true)
catch err
@show err
end
if separate
try
rm(load_cache_path, force=true, recursive=true)
catch err
@show err
end
end
filter!((≠)(load_path), LOAD_PATH)
separate && filter!((≠)(load_cache_path), DEPOT_PATH)
end
nothing
end

function check_presence(mi, token)
found = false
ci = isdefined(mi, :cache) ? mi.cache : nothing
while ci !== nothing
if ci.owner === token && ci.max_world == typemax(UInt)
found = true
break
end
ci = isdefined(ci, :next) ? ci.next : nothing
end
return found
end

precompile_test_harness("Inference caching") do load_path
write(joinpath(load_path, "InferenceCaching.jl"), :(module InferenceCaching
import Native
import GPUCompiler

function kernel()
return
end

let
job, _ = Native.create_job(kernel, ())
GPUCompiler.code_typed(job)
end

# identity is foreign
# Maybe https://github.com/JuliaLang/julia/pull/49391
job, _ = Native.create_job(identity, (Int,))
vchuravy marked this conversation as resolved.
Show resolved Hide resolved
GPUCompiler.code_typed(job)
end) |> string)

Base.compilecache(Base.PkgId("InferenceCaching"))
@eval let
# Check that no cached entry is present
identity_mi = GPUCompiler.methodinstance(typeof(identity), Tuple{Int})

token = let
job, _ = Native.create_job(identity, (Int,))
GPUCompiler.ci_cache_token(job)
end
ci = isdefined(identity_mi, :cache) ? identity_mi.cache : nothing
while ci !== nothing
@test ci.owner === nothing
@test ci.owner !== token
ci = isdefined(ci, :next) ? ci.next : nothing
end

using InferenceCaching

# Check that kernel survived
kernel_mi = GPUCompiler.methodinstance(typeof(InferenceCaching.kernel), Tuple{})
@test check_presence(kernel_mi, token)

# check that identity survived
@test_broken check_presence(identity_mi, token)
end
end

end # testitem
5 changes: 5 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,10 @@ runtests(GPUCompiler; nworkers=min(Sys.CPU_THREADS,4), nworker_threads=1,
# SPIRV needs it's tools to be available
return false
end

if ti.name == "Precompile" && VERSION < v"1.11.0-"
return false
end

true
end
Loading