Skip to content
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
16 changes: 16 additions & 0 deletions src/OpenCL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,20 @@ export OpenCLBackend
eval(Expr(:public, :synchronize, Symbol("@sync")))
end

# displaying an array (in USM, the preferred memory back-end where supported), which the
# device-free workload can't do, compiles for 150 to 400 ms otherwise. the REPL displays on
# a `TTYTerminal`, which is part of Base on 1.12+.
let ios = @static isdefined(Base, :Terminals) ? (IOBuffer, Base.Terminals.TTYTerminal) :
(IOBuffer,)
for io in ios, N in (1, 2)
precompile(Tuple{typeof(show), IOContext{io}, MIME"text/plain",
CLArray{Float32,N,cl.UnifiedDeviceMemory}})
end
end

# freeing an array, which otherwise compiles in the first garbage collection that frees one
for M in (cl.UnifiedDeviceMemory, cl.SharedVirtualMemory, cl.Buffer)
precompile(Tuple{typeof(free), Managed{M}})
end

end
15 changes: 12 additions & 3 deletions src/compiler/execution.jl
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,21 @@ function clfunction(f::F, tt::TT=Tuple{}; source::S=f, kwargs...) where {F,TT,S}
# copies of arrays, like `extensions`, which the caller may mutate.
options = map(v -> v isa AbstractArray ? copy(v) : v, kw)
key = (cl.context(), cl.device(), program_backend(), options)
kernel, device_rng = GPUCompiler.cached_lookup(Tuple{cl.Kernel,Bool}, F, tt, key) do
clfunction_link(methodinstance(F, tt); kw...)
end
kernel, device_rng = GPUCompiler.cached_lookup(KernelLinker(F, tt, kw),
Tuple{cl.Kernel,Bool}, F, tt, key)
HostKernel{F,S,tt}(f, source, kernel, device_rng)
end

# what `clfunction` calls when the kernel isn't cached: a callable struct rather than a
# closure, whose type would depend on the kernel's, compiling it (and the inlined
# `methodinstance`) again for every kernel.
struct KernelLinker{K}
ft::Type
tt::Type
kw::K
end
(l::KernelLinker)() = clfunction_link(methodinstance(l.ft, l.tt); l.kw...)

# the part of `clfunction` that doesn't depend on the kernel's function and argument types,
# kept separate so that it's compiled once rather than for every kernel
function clfunction_link(mi::Core.MethodInstance; kwargs...)
Expand Down
Loading