Reference

Contents

Index

OpenCL.llvm_to_spirv_backend — Constant
OpenCL.llvm_to_spirv_backend :: Symbol

The backend used to compile LLVM IR to SPIRV (:llvm (default), or :khronos). This is a load-time preference, as compiler configurations are cached across compilations:

using OpenCL, Preferencesset_preferences!(OpenCL, "llvm_to_spirv_backend" => "khronos")

Changing it requires restarting Julia. The :khronos backend additionally requires SPIRV_LLVM_Translator_jll (or SPIRV_LLVM_Translator_unified_jll) to be loaded.

source
OpenCL.Const — Type
Const(A::CLDeviceArray)

Mark a CLDeviceArray as constant/read-only. The invariant guaranteed is that you will not modify an CLDeviceArray for the duration of the current kernel. Loads from it are emitted as !invariant.load, so violating that invariant is undefined behavior.

Warning

Experimental API. Subject to change without deprecation.

source
OpenCL.KernelException — Type
KernelException

An exception thrown during kernel execution on dev, detected when synchronizing (cl.finish, a blocking copy, Array(x), ...).

How much is known about the exception depends on the debug level the kernel was compiled with (the session's -g level, or @opencl debug_level=):

  • 0: only that an exception was thrown;
  • 1: additionally its type name and reason, for exceptions thrown by Julia's runtime (bounds errors, domain errors, ...);
  • 2: additionally the position of the faulting work-item (work_item is its local id, work_group the id of its work-group), the name of any other exception, and a device-side backtrace as (function, file, line) tuples.

dev identifies the device whose mailbox reported the exception. Fields that were not recorded are empty strings, empty vectors, or all-zero tuples.

source
OpenCL.OpenCLResults — Type
OpenCLResults

Cached compilation results for an OpenCL kernel job, managed by GPUCompiler.cached_results. Fields are populated through the compile pipeline: obj (SPIR-V bytes) + entry + device_rng after codegen, and kernels after the session-local link onto an OpenCL context. The first three are session-portable (cached through precompilation, except when GPUCompiler marks the job session-dependent and wipes its entries before image serialization); kernels is session-local and never populated during precompilation. obj === nothing identifies a job that has not been compiled yet.

kernels is a small linear cache of (cl.Context, cl.Kernel) pairs. The cache partition already covers everything that affects codegen via GPUCompiler.cache_owner, so the only runtime-visible dimension left is the OpenCL context that owns the linked cl.Kernel. A linear scan with === is fastest in the common case (n=1) and stays cheap for the rare workload that bounces between a handful of contexts on the same device.

source
Base.rand — Method
Random.rand(rng::Philox2x32, UInt32)

Generate a byte of random data using the on-device Tausworthe generator.

source
Base.resize! — Method

resize!(a::CLVector, n::Integer)

Resize a to contain n elements. If n is smaller than the current collection length, the first n elements will be retained. If n is larger, the new elements are not guaranteed to be initialized.

source
Base.unsafe_wrap — Method
unsafe_wrap(CLArray, a::Array)
unsafe_wrap(CLArray, ptr::Ptr{T}, dims)
unsafe_wrap(CLArray{T,N,M}, ...)

Wrap a CLArray around host memory, without copying, so that it can be used on the device, e.g., in kernels or broadcasts. Changes made through the CLArray are visible in the original array, and vice versa.

This requires a device that can directly access ordinary host memory, i.e., one that supports fine-grained system shared virtual memory (like PoCL's CPU device), or shared system allocations in the cl_intel_unified_shared_memory extension. On other devices an ArgumentError is thrown; use CLArray(a) to copy the data instead. The memory type M of the resulting array is either cl.SharedVirtualMemory or cl.UnifiedSharedMemory, depending on what the device supports. It can be selected explicitly by passing the full array type.

When wrapping an Array, the returned CLArray keeps it alive. When wrapping a pointer, the caller has to make sure the memory stays valid for as long as the CLArray is used. In both cases, the memory must not be freed or reallocated while it is wrapped (e.g., by calling resize! on the original array), and resizing the wrapper is not supported.

8- and 16-bit atomic operations access the entire aligned 4-byte word that contains the element, so when using them, every such word that overlaps the wrapped memory must be accessible, even if it extends past the end of that memory. CLArrays allocated by OpenCL.jl are padded to guarantee this.

Device operations execute asynchronously, so wait for them to finish (e.g., using cl.finish(cl.queue())) before accessing the original memory on the host. Wrapping the same memory multiple times results in independent arrays whose operations are not synchronized with each other.

a = rand(Float32, 1024)b = unsafe_wrap(CLArray, a)b .= sin.(b)        # executes on the device, updating `a`cl.finish(cl.queue())
source
Base.unsafe_wrap — Method
unsafe_wrap(Array, arr::CLArray)

Wrap a Julia Array around the memory that backs a CLArray, without copying. This is only possible if that memory is accessible from the host: unified host or shared memory, shared virtual memory, or host memory that was itself wrapped using unsafe_wrap(CLArray, ...).

Device operations execute asynchronously, so wait for them to finish (e.g., using cl.finish(cl.queue())) before accessing the returned array after using arr on the device.

Warning

The returned Array does not keep arr alive. If arr is garbage collected (or freed using unsafe_free!), its memory is released and the Array refers to invalid memory. The caller must keep a reference to arr for as long as the Array, or anything derived from it, is used.

Warning

Coarse-grained shared virtual memory is only accessible from the host while it is mapped. Using arr on the device unmaps it, after which the returned array must not be accessed until an operation on arr has mapped it again (e.g., indexing it, or calling unsafe_wrap(Array, arr) again).

source
OpenCL.check_exceptions — Method
check_exceptions(queue::cl.CmdQueue)

Synchronize queue and every other queue recorded against its device's mailbox, then check whether a kernel threw an exception and, if so, rethrow it host-side as a KernelException.

The exception mailbox is shared by queues targeting the same device in a context, so this may wait for and surface an exception from another queue on that device.

source
OpenCL.device_atomics — Method
device_atomics(dev::cl.Device; source::Bool=false) -> SPIRVAtomics

The atomic capabilities of dev and its toolchain, i.e., the atomic operations GPUCompiler may select SPIR-V instructions for; it implements the others with compare-and-swap loops. source restricts them to what the OpenCL C source path (spirv2clc) can translate.

This is the default for the atomics compiler keyword (e.g., @opencl atomics=...), which overrides the atomic capabilities GPUCompiler may select directly: it replaces the whole device-derived OpenCL.SPIRVAtomics (from GPUCompiler). Enabling capabilities the device or toolchain doesn't support can make compilation fail, or terminate the driver's compiler. Disabling them relies on integer compare-and-swap for the fallback.

source
OpenCL.format — Method

Format string using dict-like variables, replacing all accurancies of %(key) with value.

Example: s = "Hello, %(name)" format(s, name="Tom") ==> "Hello, Tom"

source
OpenCL.has_feature — Method
has_feature(name::Symbol) -> Bool

Compile-time query (device side): does the kernel's target device support optional feature name (see FEATURES)? Folds to a constant, so if has_feature(:subgroups) … else … end keeps only the live branch. Host-side, use feature_supported(dev, name).

source
OpenCL.kernel_convert — Function
kernel_convert(x)

This function is called for every argument to be passed to a kernel, allowing it to be converted to a GPU-friendly format. By default, the function does nothing and returns the input object x as-is.

Do not add methods to this function, but instead extend the underlying Adapt.jl package and register methods for the the OpenCL.KernelAdaptor type.

source
OpenCL.launch_tuple — Method
OpenCL.launch_tuple(kernel, args::Tuple; kwargs...)

Launch kernel, as calling it with the arguments args... and the launch keywords kwargs does, without splatting the arguments.

source
OpenCL.managed_alloc — Method
managed_alloc(M, bytes; alignment=0)

Allocate bytes of memory of type M, wrapped in a Managed.

GPUCompiler implements 8- and 16-bit atomics with 32-bit atomics on the containing aligned word, so the allocation is rounded up to a multiple of 4 bytes and aligned to at least 4 bytes. Its size can thus exceed bytes; callers keep track of the logical size themselves.

source
OpenCL.program_backend! — Method
program_backend!(mode::Symbol)
program_backend!(f::Function, mode::Symbol)

Select how kernels are fed to the driver for the current task: :auto (default), :spirv (SPIR-V IL), or :opencl (OpenCL C source). The second form applies mode only for the duration of f.

source
OpenCL.program_backend — Method
program_backend() -> Symbol

The requested program backend for the current task (:auto, :spirv, or :opencl).

source
OpenCL.return_type — Method
OpenCL.return_type(f, tt) -> r::Type

Return a type r such that f(args...)::r where args::tt.

source
OpenCL.synchronize — Function
OpenCL.synchronize([queue::cl.CmdQueue])

Wait for all operations submitted to queue to finish. By default, this is the command queue of the current task, cl.queue(); operations submitted by other tasks, which use their own queues, are not waited for.

While waiting, the current task yields, so other tasks can run on its thread. Waiting can be interrupted, in which case the device keeps executing the operations.

If a kernel threw an exception, it is reported here as a KernelException. Because queues targeting the same device share their exception state, this may also wait for, and report a failure from, another queue on that device.

See also: OpenCL.@sync.

source
Random.seed! — Function
Random.seed!(rng::Philox2x32, seed::Integer, [counter::Integer=0])

Seed the on-device Philox2x32 generator with an UInt32 number. Should be called by at least one thread per warp.

source
OpenCL.@opencl — Macro
@opencl [kwargs...] func(args...)

High-level interface for executing code on an OpenCL device.

The @opencl macro should prefix a call, with func a callable function or object that should return nothing. It will be compiled to an OpenCL kernel upon first use, and to a certain extent arguments will be converted and managed automatically using kernel_convert. Finally, the kernel is launched on the current queue.

There are a few keyword arguments that influence the behavior of @opencl:

  • launch: whether to launch this kernel, defaults to true. If false, the returned kernel object should be launched by calling it and passing arguments again.
  • name: the name of the kernel in the generated code. Defaults to an automatically- generated name.
  • debug_level: how much a device-side exception reports, from 0 (only that one was thrown) to 2 (its type, reason, position and backtrace). Defaults to the session's -g level; see KernelException.
  • atomics: override the atomic capabilities that GPUCompiler may select instructions for, as an OpenCL.SPIRVAtomics. This replaces the whole descriptor derived from the device and toolchain, see OpenCL.device_atomics, which is the default.
  • global_size, local_size: the launch configuration, as in OpenCL.
source
OpenCL.@sync — Macro
OpenCL.@sync ex

Run expression ex, then wait for the operations it submitted to the current task's queue to finish, using OpenCL.synchronize. Returns the value of ex.

Only the current task's queue is waited for: work that ex submits to other queues, e.g., inside a cl.queue!(q) do ... end block, or from Julia tasks it spawns (unlike Base.@sync), needs to be synchronized separately.

source
OpenCL.cl.CLPtr — Type
CLPtr{T}

A memory address that refers to data of type T that is accessible from q device. A CLPtr is ABI compatible with regular Ptr objects, e.g. it can be used to ccall a function that expects a Ptr to device memory, but it prevents erroneous conversions between the two.

source
OpenCL.cl.PtrOrCLPtr — Type
PtrOrCLPtr{T}

A special pointer type, ABI-compatible with both Ptr and CLPtr, for use in ccall expressions to convert values to either a device or a host type (in that order). This is required for APIs which accept pointers that either point to host or device memory.

source
OpenCL.cl.UnifiedDeviceMemory — Type
UnifiedDeviceMemory

A buffer of device memory, owned by a specific device. Generally, may only be accessed by the device that owns it.

source
OpenCL.cl.UnifiedHostMemory — Type
UnifiedHostMemory

A buffer of memory on the host. May be accessed by the host, and all devices within the host driver. Frequently used as staging areas to transfer data to or from devices.

source
Base.wait — Method
wait(evt::cl.AbstractEvent)
wait(evts::Vector{cl.AbstractEvent})

Wait for the commands associated with the event(s) to complete, throwing a CLError if a command was terminated abnormally.

While waiting, the current task yields to others. Waiting is interruptible, in which case the commands keep executing.

source
OpenCL.cl.clcall — Method
clcall(kernel, types, args...; kwargs...)

Set the arguments of kernel and enqueue it as one atomic operation with respect to other uses of the same kernel object. Manual use of cl.set_arg!, cl.set_args!, or cl.enqueue_kernel is not internally synchronized; hold lock(kernel) across the complete argument-setup and enqueue sequence.

source
OpenCL.cl.driver_uuid — Method
driver_uuid(d::Device)

Return the universally unique identifier of the driver backing the device as a Base.UUID, or missing if the device does not support the cl_khr_device_uuid extension. Devices using the same driver report the same driver UUID.

source
OpenCL.cl.pci_bus_info — Method
pci_bus_info(d::Device)

Return the PCI address of the device as a named tuple (; domain, bus, device, func), or missing if the device does not support the cl_khr_pci_bus_info extension.

source
OpenCL.cl.uuid — Method
uuid(d::Device)

Return the universally unique identifier of the device as a Base.UUID, or missing if the device does not support the cl_khr_device_uuid extension.

source
OpenCL.cl.@checked — Macro
@checked function foo(...)
    rv = ...
    return rv
end

Macro for wrapping a function definition returning a status code. Two versions of the function will be generated: foo, with the function body wrapped by an invocation of the check function (to be implemented by the caller of this macro), and unchecked_foo where no such invocation is present and the status code is returned to the caller.

source
OpenCL.OpenCLKernels.OpenCLBackend — Type
OpenCLBackend(; platform=cl.platform())

KernelInterface back end for the OpenCL devices of platform.

A backend works with the task's active device if that is on its platform. Otherwise, work for the backend (allocations, copies, compilation and launches) first activates the default device of its platform, as KernelInterface.device! would, so that the arrays it creates can be used afterwards.

Sub-groups

KernelInterface's sub-groups need a width that is the same for every kernel. For now, they are only supported on devices with cl_intel_required_subgroup_size, through which kernels request the width that KernelInterface.sub_group_size reports (at most 64). The shuffles also need cl_khr_subgroup_shuffle.

OpenCL doesn't specify which work-items form a sub-group, so KernelInterface.supports_linear_subgroups is only true on runtimes known to form them from consecutive work-items: PoCL and Intel's CPU and GPU runtimes. On PoCL, sub-group operations are work-group barriers, so KernelInterface.supports_independent_subgroups is false: all sub-groups of a work-group have to execute the same sub-group operations, in the same order. It is also false on Intel's CPU runtime, which loses the writes after a sub_group_barrier that other sub-groups returned before (intel/llvm#23449).

OpenCL has no barrier for part of a sub-group, so KernelInterface.supports_partitionable_subgroups is only true on Intel's GPU runtime, where a sub-group is the SIMD lanes of one hardware thread (and with cl_khr_subgroup_ballot). Elsewhere, the segments of a sub-group have to execute the sub-group functions with a width together, like the ones without.

source