diff options
| author | Callum Fare <callum@codeplay.com> | 2025-04-22 19:27:50 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-22 13:27:50 -0500 |
| commit | 800d949bb315349a116a980e99d0f36645ffefd3 (patch) | |
| tree | e13178e6c2d33cbe0235274e43a278d9b85e89d7 /offload/liboffload/API | |
| parent | fcb309715e4bd46d96dda7bdf99291ebf394d130 (diff) | |
[Offload] Implement the remaining initial Offload API (#122106)
Implement the complete initial version of the Offload API, to the extent
that is usable for simple offloading programs. Tested with a basic SYCL
program.
As far as possible, these are simple wrappers over existing
functionality in the plugins.
* Allocating and freeing memory (host, device, shared).
* Creating a program
* Creating a queue (wrapper over asynchronous stream resource)
* Enqueuing memcpy operations
* Enqueuing kernel executions
* Waiting on (optional) output events from the enqueue operations
* Waiting on a queue to finish
Objects created with the API have reference counting semantics to handle
their lifetime. They are created with an initial reference count of 1,
which can be incremented and decremented with retain and release
functions. They are freed when their reference count reaches 0. Platform
and device objects are not reference counted, as they are expected to
persist as long as the library is in use, and it's not meaningful for
users to create or destroy them.
Tests have been added to `offload.unittests`, including device code for
testing program and kernel related functionality.
The API should still be considered unstable and it's very likely we will
need to change the existing entry points.
Diffstat (limited to 'offload/liboffload/API')
| -rw-r--r-- | offload/liboffload/API/APIDefs.td | 2 | ||||
| -rw-r--r-- | offload/liboffload/API/Common.td | 28 | ||||
| -rw-r--r-- | offload/liboffload/API/Device.td | 37 | ||||
| -rw-r--r-- | offload/liboffload/API/Event.td | 31 | ||||
| -rw-r--r-- | offload/liboffload/API/Kernel.td | 61 | ||||
| -rw-r--r-- | offload/liboffload/API/Memory.td | 68 | ||||
| -rw-r--r-- | offload/liboffload/API/OffloadAPI.td | 5 | ||||
| -rw-r--r-- | offload/liboffload/API/Platform.td | 43 | ||||
| -rw-r--r-- | offload/liboffload/API/Program.td | 34 | ||||
| -rw-r--r-- | offload/liboffload/API/Queue.td | 42 | ||||
| -rw-r--r-- | offload/liboffload/API/README.md | 6 |
11 files changed, 290 insertions, 67 deletions
diff --git a/offload/liboffload/API/APIDefs.td b/offload/liboffload/API/APIDefs.td index cee4adea1d9f..640932dcf846 100644 --- a/offload/liboffload/API/APIDefs.td +++ b/offload/liboffload/API/APIDefs.td @@ -199,7 +199,7 @@ class Typedef : APIObject { string value; } class FptrTypedef : APIObject { list<Param> params; - list<Return> returns; + string return; } class Macro : APIObject { diff --git a/offload/liboffload/API/Common.td b/offload/liboffload/API/Common.td index 5b19d1d47129..de7502b54061 100644 --- a/offload/liboffload/API/Common.td +++ b/offload/liboffload/API/Common.td @@ -62,6 +62,27 @@ def : Handle { let desc = "Handle of context object"; } +def : Handle { + let name = "ol_queue_handle_t"; + let desc = "Handle of queue object"; +} + +def : Handle { + let name = "ol_event_handle_t"; + let desc = "Handle of event object"; +} + +def : Handle { + let name = "ol_program_handle_t"; + let desc = "Handle of program object"; +} + +def : Typedef { + let name = "ol_kernel_handle_t"; + let desc = "Handle of kernel object"; + let value = "void *"; +} + def : Enum { let name = "ol_errc_t"; let desc = "Defines Return/Error codes"; @@ -69,12 +90,11 @@ def : Enum { Etor<"SUCCESS", "Success">, Etor<"INVALID_VALUE", "Invalid Value">, Etor<"INVALID_PLATFORM", "Invalid platform">, - Etor<"DEVICE_NOT_FOUND", "Device not found">, Etor<"INVALID_DEVICE", "Invalid device">, - Etor<"DEVICE_LOST", "Device hung, reset, was removed, or driver update occurred">, - Etor<"UNINITIALIZED", "plugin is not initialized or specific entry-point is not implemented">, + Etor<"INVALID_QUEUE", "Invalid queue">, + Etor<"INVALID_EVENT", "Invalid event">, + Etor<"INVALID_KERNEL_NAME", "Named kernel not found in the program binary">, Etor<"OUT_OF_RESOURCES", "Out of resources">, - Etor<"UNSUPPORTED_VERSION", "generic error code for unsupported versions">, Etor<"UNSUPPORTED_FEATURE", "generic error code for unsupported features">, Etor<"INVALID_ARGUMENT", "generic error code for invalid arguments">, Etor<"INVALID_NULL_HANDLE", "handle argument is not valid">, diff --git a/offload/liboffload/API/Device.td b/offload/liboffload/API/Device.td index 30c0b71fe7b3..28c96bb5d291 100644 --- a/offload/liboffload/API/Device.td +++ b/offload/liboffload/API/Device.td @@ -12,7 +12,7 @@ def : Enum { let name = "ol_device_type_t"; - let desc = "Supported device types"; + let desc = "Supported device types."; let etors =[ Etor<"DEFAULT", "The default device type as preferred by the runtime">, Etor<"ALL", "Devices of all types">, @@ -23,7 +23,7 @@ def : Enum { def : Enum { let name = "ol_device_info_t"; - let desc = "Supported device info"; + let desc = "Supported device info."; let is_typed = 1; let etors =[ TaggedEtor<"TYPE", "ol_device_type_t", "type of the device">, @@ -34,39 +34,34 @@ def : Enum { ]; } -def : Function { - let name = "olGetDeviceCount"; - let desc = "Retrieves the number of available devices within a platform"; +def : FptrTypedef { + let name = "ol_device_iterate_cb_t"; + let desc = "User-provided function to be used with `olIterateDevices`"; let params = [ - Param<"ol_platform_handle_t", "Platform", "handle of the platform instance", PARAM_IN>, - Param<"uint32_t*", "NumDevices", "pointer to the number of devices.", PARAM_OUT> + Param<"ol_device_handle_t", "Device", "the device handle of the current iteration", PARAM_IN>, + Param<"void*", "UserData", "optional user data", PARAM_IN_OPTIONAL> ]; - let returns = []; + let return = "bool"; } def : Function { - let name = "olGetDevice"; - let desc = "Retrieves devices within a platform"; + let name = "olIterateDevices"; + let desc = "Iterates over all available devices, calling the callback for each device."; let details = [ - "Multiple calls to this function will return identical device handles, in the same order.", + "If the user-provided callback returns `false`, the iteration is stopped." ]; let params = [ - Param<"ol_platform_handle_t", "Platform", "handle of the platform instance", PARAM_IN>, - Param<"uint32_t", "NumEntries", "the number of devices to be added to phDevices, which must be greater than zero", PARAM_IN>, - RangedParam<"ol_device_handle_t*", "Devices", "Array of device handles. " - "If NumEntries is less than the number of devices available, then this function shall only retrieve that number of devices.", PARAM_OUT, - Range<"0", "NumEntries">> + Param<"ol_device_iterate_cb_t", "Callback", "User-provided function called for each available device", PARAM_IN>, + Param<"void*", "UserData", "Optional user data to pass to the callback", PARAM_IN_OPTIONAL> ]; let returns = [ - Return<"OL_ERRC_INVALID_SIZE", [ - "`NumEntries == 0`" - ]> + Return<"OL_ERRC_INVALID_DEVICE"> ]; } def : Function { let name = "olGetDeviceInfo"; - let desc = "Queries the given property of the device"; + let desc = "Queries the given property of the device."; let details = []; let params = [ Param<"ol_device_handle_t", "Device", "handle of the device instance", PARAM_IN>, @@ -90,7 +85,7 @@ def : Function { def : Function { let name = "olGetDeviceInfoSize"; - let desc = "Returns the storage size of the given device query"; + let desc = "Returns the storage size of the given device query."; let details = []; let params = [ Param<"ol_device_handle_t", "Device", "handle of the device instance", PARAM_IN>, diff --git a/offload/liboffload/API/Event.td b/offload/liboffload/API/Event.td new file mode 100644 index 000000000000..c9f79159cf26 --- /dev/null +++ b/offload/liboffload/API/Event.td @@ -0,0 +1,31 @@ +//===-- Event.td - Event definitions for Offload -----------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains Offload API definitions related to the event handle +// +//===----------------------------------------------------------------------===// + +def : Function { + let name = "olDestroyEvent"; + let desc = "Destroy the event and free all underlying resources."; + let details = []; + let params = [ + Param<"ol_event_handle_t", "Event", "handle of the event", PARAM_IN> + ]; + let returns = []; +} + +def : Function { + let name = "olWaitEvent"; + let desc = "Wait for the event to be complete."; + let details = []; + let params = [ + Param<"ol_event_handle_t", "Event", "handle of the event", PARAM_IN> + ]; + let returns = []; +} diff --git a/offload/liboffload/API/Kernel.td b/offload/liboffload/API/Kernel.td new file mode 100644 index 000000000000..247f9c1bf5b6 --- /dev/null +++ b/offload/liboffload/API/Kernel.td @@ -0,0 +1,61 @@ +//===-- Kernel.td - Kernel definitions for Offload ---------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains Offload API definitions related to the kernel handle +// +//===----------------------------------------------------------------------===// + +def : Function { + let name = "olGetKernel"; + let desc = "Get a kernel from the function identified by `KernelName` in the given program."; + let details = [ + "The kernel handle returned is owned by the device so does not need to be destroyed." + ]; + let params = [ + Param<"ol_program_handle_t", "Program", "handle of the program", PARAM_IN>, + Param<"const char*", "KernelName", "name of the kernel entry point in the program", PARAM_IN>, + Param<"ol_kernel_handle_t*", "Kernel", "output pointer for the fetched kernel", PARAM_OUT> + ]; + let returns = []; +} + +def : Struct { + let name = "ol_kernel_launch_size_args_t"; + let desc = "Size-related arguments for a kernel launch."; + let members = [ + StructMember<"size_t", "Dimensions", "Number of work dimensions">, + StructMember<"size_t", "NumGroupsX", "Number of work groups on the X dimension">, + StructMember<"size_t", "NumGroupsY", "Number of work groups on the Y dimension">, + StructMember<"size_t", "NumGroupsZ", "Number of work groups on the Z dimension">, + StructMember<"size_t", "GroupSizeX", "Size of a work group on the X dimension.">, + StructMember<"size_t", "GroupSizeY", "Size of a work group on the Y dimension.">, + StructMember<"size_t", "GroupSizeZ", "Size of a work group on the Z dimension.">, + StructMember<"size_t", "DynSharedMemory", "Size of dynamic shared memory in bytes."> + ]; +} + +def : Function { + let name = "olLaunchKernel"; + let desc = "Enqueue a kernel launch with the specified size and parameters."; + let details = [ + "If a queue is not specified, kernel execution happens synchronously" + ]; + let params = [ + Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN_OPTIONAL>, + Param<"ol_device_handle_t", "Device", "handle of the device to execute on", PARAM_IN>, + Param<"ol_kernel_handle_t", "Kernel", "handle of the kernel", PARAM_IN>, + Param<"const void*", "ArgumentsData", "pointer to the kernel argument struct", PARAM_IN>, + Param<"size_t", "ArgumentsSize", "size of the kernel argument struct", PARAM_IN>, + Param<"const ol_kernel_launch_size_args_t*", "LaunchSizeArgs", "pointer to the struct containing launch size parameters", PARAM_IN>, + Param<"ol_event_handle_t*", "EventOut", "optional recorded event for the enqueued operation", PARAM_OUT_OPTIONAL> + ]; + let returns = [ + Return<"OL_ERRC_INVALID_ARGUMENT", ["`Queue == NULL && EventOut != NULL`"]>, + Return<"OL_ERRC_INVALID_DEVICE", ["If Queue is non-null but does not belong to Device"]>, + ]; +} diff --git a/offload/liboffload/API/Memory.td b/offload/liboffload/API/Memory.td new file mode 100644 index 000000000000..9cd1ef6362e1 --- /dev/null +++ b/offload/liboffload/API/Memory.td @@ -0,0 +1,68 @@ +//===-- Memory.td - Memory definitions for Offload ---------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains Offload API definitions related to memory allocations +// +//===----------------------------------------------------------------------===// + +def : Enum { + let name = "ol_alloc_type_t"; + let desc = "Represents the type of allocation made with olMemAlloc."; + let etors = [ + Etor<"HOST", "Host allocation">, + Etor<"DEVICE", "Device allocation">, + Etor<"MANAGED", "Managed allocation"> + ]; +} + +def : Function { + let name = "olMemAlloc"; + let desc = "Creates a memory allocation on the specified device."; + let params = [ + Param<"ol_device_handle_t", "Device", "handle of the device to allocate on", PARAM_IN>, + Param<"ol_alloc_type_t", "Type", "type of the allocation", PARAM_IN>, + Param<"size_t", "Size", "size of the allocation in bytes", PARAM_IN>, + Param<"void**", "AllocationOut", "output for the allocated pointer", PARAM_OUT> + ]; + let returns = [ + Return<"OL_ERRC_INVALID_SIZE", [ + "`Size == 0`" + ]> + ]; +} + +def : Function { + let name = "olMemFree"; + let desc = "Frees a memory allocation previously made by olMemAlloc."; + let params = [ + Param<"void*", "Address", "address of the allocation to free", PARAM_IN>, + ]; + let returns = []; +} + +def : Function { + let name = "olMemcpy"; + let desc = "Enqueue a memcpy operation."; + let details = [ + "For host pointers, use the host device belonging to the OL_PLATFORM_BACKEND_HOST platform.", + "If a queue is specified, at least one device must be a non-host device", + "If a queue is not specified, the memcpy happens synchronously" + ]; + let params = [ + Param<"ol_queue_handle_t", "Queue", "handle of the queue.", PARAM_IN_OPTIONAL>, + Param<"void*", "DstPtr", "pointer to copy to", PARAM_IN>, + Param<"ol_device_handle_t", "DstDevice", "device that DstPtr belongs to", PARAM_IN>, + Param<"void*", "SrcPtr", "pointer to copy from", PARAM_IN>, + Param<"ol_device_handle_t", "SrcDevice", "device that SrcPtr belongs to", PARAM_IN>, + Param<"size_t", "Size", "size in bytes of data to copy", PARAM_IN>, + Param<"ol_event_handle_t*", "EventOut", "optional recorded event for the enqueued operation", PARAM_OUT_OPTIONAL> + ]; + let returns = [ + Return<"OL_ERRC_INVALID_ARGUMENT", ["`Queue == NULL && EventOut != NULL`"]> + ]; +} diff --git a/offload/liboffload/API/OffloadAPI.td b/offload/liboffload/API/OffloadAPI.td index 8a0c3c405812..f9829155b6ce 100644 --- a/offload/liboffload/API/OffloadAPI.td +++ b/offload/liboffload/API/OffloadAPI.td @@ -13,3 +13,8 @@ include "APIDefs.td" include "Common.td" include "Platform.td" include "Device.td" +include "Memory.td" +include "Queue.td" +include "Event.td" +include "Program.td" +include "Kernel.td" diff --git a/offload/liboffload/API/Platform.td b/offload/liboffload/API/Platform.td index 03e70cf96ac9..97c2cc2d0570 100644 --- a/offload/liboffload/API/Platform.td +++ b/offload/liboffload/API/Platform.td @@ -9,44 +9,10 @@ // This file contains Offload API definitions related to the Platform handle // //===----------------------------------------------------------------------===// -def : Function { - let name = "olGetPlatform"; - let desc = "Retrieves all available platforms"; - let details = [ - "Multiple calls to this function will return identical platforms handles, in the same order.", - ]; - let params = [ - Param<"uint32_t", "NumEntries", - "The number of platforms to be added to Platforms. NumEntries must be " - "greater than zero.", - PARAM_IN>, - RangedParam<"ol_platform_handle_t*", "Platforms", - "Array of handle of platforms. If NumEntries is less than the number of " - "platforms available, then olGetPlatform shall only retrieve that " - "number of platforms.", - PARAM_OUT, Range<"0", "NumEntries">> - ]; - let returns = [ - Return<"OL_ERRC_INVALID_SIZE", [ - "`NumEntries == 0`" - ]> - ]; -} - -def : Function { - let name = "olGetPlatformCount"; - let desc = "Retrieves the number of available platforms"; - let params = [ - Param<"uint32_t*", - "NumPlatforms", "returns the total number of platforms available.", - PARAM_OUT> - ]; - let returns = []; -} def : Enum { let name = "ol_platform_info_t"; - let desc = "Supported platform info"; + let desc = "Supported platform info."; let is_typed = 1; let etors = [ TaggedEtor<"NAME", "char[]", "The string denoting name of the platform. The size of the info needs to be dynamically queried.">, @@ -58,17 +24,18 @@ def : Enum { def : Enum { let name = "ol_platform_backend_t"; - let desc = "Identifies the native backend of the platform"; + let desc = "Identifies the native backend of the platform."; let etors =[ Etor<"UNKNOWN", "The backend is not recognized">, Etor<"CUDA", "The backend is CUDA">, Etor<"AMDGPU", "The backend is AMDGPU">, + Etor<"HOST", "The backend is the host">, ]; } def : Function { let name = "olGetPlatformInfo"; - let desc = "Queries the given property of the platform"; + let desc = "Queries the given property of the platform."; let details = [ "`olGetPlatformInfoSize` can be used to query the storage size " "required for the given query." @@ -96,7 +63,7 @@ def : Function { def : Function { let name = "olGetPlatformInfoSize"; - let desc = "Returns the storage size of the given platform query"; + let desc = "Returns the storage size of the given platform query."; let details = []; let params = [ Param<"ol_platform_handle_t", "Platform", "handle of the platform", PARAM_IN>, diff --git a/offload/liboffload/API/Program.td b/offload/liboffload/API/Program.td new file mode 100644 index 000000000000..8c88fe6e21e6 --- /dev/null +++ b/offload/liboffload/API/Program.td @@ -0,0 +1,34 @@ +//===-- Program.td - Program definitions for Offload -------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains Offload API definitions related to the program handle +// +//===----------------------------------------------------------------------===// + +def : Function { + let name = "olCreateProgram"; + let desc = "Create a program for the device from the binary image pointed to by `ProgData`."; + let details = []; + let params = [ + Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>, + Param<"const void*", "ProgData", "pointer to the program binary data", PARAM_IN>, + Param<"size_t", "ProgDataSize", "size of the program binary in bytes", PARAM_IN>, + Param<"ol_program_handle_t*", "Program", "output pointer for the created program", PARAM_OUT> + ]; + let returns = []; +} + +def : Function { + let name = "olDestroyProgram"; + let desc = "Destroy the program and free all underlying resources."; + let details = []; + let params = [ + Param<"ol_program_handle_t", "Program", "handle of the program", PARAM_IN> + ]; + let returns = []; +} diff --git a/offload/liboffload/API/Queue.td b/offload/liboffload/API/Queue.td new file mode 100644 index 000000000000..b5bb619c5751 --- /dev/null +++ b/offload/liboffload/API/Queue.td @@ -0,0 +1,42 @@ +//===-- Queue.td - Queue definitions for Offload -----------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains Offload API definitions related to the queue handle +// +//===----------------------------------------------------------------------===// + +def : Function { + let name = "olCreateQueue"; + let desc = "Create a queue for the given device."; + let details = []; + let params = [ + Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>, + Param<"ol_queue_handle_t*", "Queue", "output pointer for the created queue", PARAM_OUT> + ]; + let returns = []; +} + +def : Function { + let name = "olDestroyQueue"; + let desc = "Destroy the queue and free all underlying resources."; + let details = []; + let params = [ + Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN> + ]; + let returns = []; +} + +def : Function { + let name = "olWaitQueue"; + let desc = "Wait for the enqueued work on a queue to complete."; + let details = []; + let params = [ + Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN> + ]; + let returns = []; +} diff --git a/offload/liboffload/API/README.md b/offload/liboffload/API/README.md index b59ac2782a2b..fda1ad39fa93 100644 --- a/offload/liboffload/API/README.md +++ b/offload/liboffload/API/README.md @@ -138,8 +138,8 @@ allow more backends to be easily added in future. A new object can be added to the API by adding to one of the existing `.td` files. It is also possible to add a new tablegen file to the API by adding it -to the includes in `OffloadAPI.td`. When the offload target is rebuilt, the -new definition will be included in the generated files. +to the includes in `OffloadAPI.td`. When the `OffloadGenerate` target is +rebuilt, the new definition will be included in the generated files. ### Adding a new entry point @@ -147,4 +147,4 @@ When a new entry point is added (e.g. `offloadDeviceFoo`), the actual entry point is automatically generated, which contains validation and tracing code. It expects an implementation function (`offloadDeviceFoo_impl`) to be defined, which it will call into. The definition of this implementation function should -be added to `src/offload_impl.cpp` +be added to `src/OffloadImpl.cpp` |
