diff --git a/src/OpenCL.jl b/src/OpenCL.jl index 38a83779..345eb9f0 100644 --- a/src/OpenCL.jl +++ b/src/OpenCL.jl @@ -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 diff --git a/src/compiler/execution.jl b/src/compiler/execution.jl index 4cc7a24d..deecde26 100644 --- a/src/compiler/execution.jl +++ b/src/compiler/execution.jl @@ -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...)