This PR changes olLaunchKernel to accept an array of pointers to
arguments:
```
void *ArgPtrs[] = {&A, &B, &C};
size_t ArgSizes[] = {sizeof(A), sizeof(B), sizeof(C)};
olLaunchKernel(Queue, Device, Kernel, &LaunchArgs, std::size(ArgPtrs), ArgPtrs, ArgSizes);
```
The newly proposed interface is implementable by existing and
anticipated
backends, is familiar to CUDA programmers, eliminates the extraneous
construction of a contiguous arguments buffer, replacing it with
constructing
an array of pointers, sidesteps the alignment requirements, does not
require reading program image metadata where it's impractical, and
enables
a compliant SYCL implementation to be built on top of it.
The ArgSizes array is required to support OpenCL, which does not have
native support for launching a kernel with an argument pointer array, or
a reliable way of retrieving argument sizes for a kernel.
## Mapping the proposed API to backends
CUDA and Level-Zero both support accepting an array of pointers to
kernel arguments, through `cuLaunchKernel`
(https://docs.nvidia.com/cuda/cuda-driver-api/group__CUDA__EXEC.html#group__CUDA__EXEC_1gb8f3dc3031b40da29d5f9a7139e52e15)
and `zeCommandListAppendLaunchKernelWithArguments`
(https://oneapi-src.github.io/level-zero-spec/level-zero/latest/core/api.html#zecommandlistappendlaunchkernelwitharguments)
respectively.
For OpenCL, which requires the kernel arguments to be set separately
from the kernel launch, a potential implementation can extract the
number of arguments from the OpenCL API, and then iterate over the
argument pointer and size arrays:
```
cl_uint num_args = 0;
cl_int err = clGetKernelInfo(kernel, CL_KERNEL_NUM_ARGS,
sizeof(num_args), &num_args, NULL);
for (cl_uint i = 0; i < num_args; ++i) {
clSetKernelArg(kernel, i, ArgSizes[i], ArgPtrs[i]);
}
```
The AMDGPU plugin needs to construct a contiguous buffer using the array
of argument pointers. To do this conversion, we need to have offsets
at which to place the arguments. Here, luckily, as mentioned before,
the AMD plugin already reads kernel metadata from the program image.
The implementation simply retrieves size and offset for each argument
from the kernel image, and then uses it to populate a buffer.
GPU Math Conformance Tests
Overview
This test suite provides a framework to systematically measure the accuracy of math functions on GPUs and verify their conformance with standards like OpenCL.
While the primary focus is validating the implementations in the C standard math library (LLVM-libm), these tests can also be executed against other math library providers, such as CUDA Math and HIP Math, for comparison.
The goals of this project are to empower LLVM-libm contributors with a robust tool for validating their implementations and to build trust with end-users by providing transparent accuracy data.
Table of Contents
Getting Started
This guide covers how to build the necessary dependencies, which include the new Offload API and the C standard library for both host and GPU targets.
System Requirements
Before you begin, ensure your system meets the following requirements:
- A system with an AMD or NVIDIA GPU.
- The latest proprietary GPU drivers installed.
- The corresponding development SDK for your hardware:
- AMD: ROCm SDK
- NVIDIA: CUDA Toolkit
Building the Dependencies
The official documentation for building LLVM-libc for GPUs provides a detailed guide and should be considered the primary reference. Please follow the instructions in the "Standard runtimes build" section of that guide:
Important
For the conformance tests, the standard
cmakecommand from the official documentation must be adapted slightly. You must also addlibcto the main-DLLVM_ENABLE_RUNTIMESlist. This is a crucial step because the tests need a host-side build oflibcto use as the reference oracle for validating GPU results.
Running the Tests
Default Test
To build and run the conformance test for a given function (e.g., logf) against the default C standard math library llvm-libm provider, use the following command. This will execute the test on all available and supported platforms.
ninja -C build/runtimes/runtimes-bins offload.conformance.logf
Testing Other Providers
Once the test binary has been built, you can run it against other math library providers using the --test-configs flag.
-
For
cuda-mathon an NVIDIA GPU:./build/runtimes/runtimes-bins/offload/logf.conformance --test-configs=cuda-math:cuda -
For
hip-mathon an AMD GPU:./build/runtimes/runtimes-bins/offload/logf.conformance --test-configs=hip-math:amdgpu
You can also run all available configurations for a test with:
./build/runtimes/runtimes-bins/offload/logf.conformance --test-configs=all
Adding New Tests
To add a conformance test for a new math function, follow these steps:
-
Implement the Device Kernels: Create a kernel wrapper for the new function in each provider's source file. For CUDA Math and HIP Math, you must also add a forward declaration for the vendor function in
/device_code/DeviceAPIs.hpp. -
Implement the Host Test: Create a new
.cppfile in/tests. This file defines theFunctionConfig(function and kernel names, as well as ULP tolerance) and the input generation strategy.- Use exhaustive testing (
ExhaustiveGenerator) for functions with small input spaces (e.g., half-precision functions and single-precision univariate functions). This strategy iterates over every representable point in the input space, ensuring complete coverage. - Use randomized testing (
RandomGenerator) for functions with large input spaces (e.g., single-precision bivariate and double-precision functions), where exhaustive testing is computationally infeasible. Although not exhaustive, this strategy is deterministic, using a fixed seed to sample a large, reproducible subset of points from the input space.
- Use exhaustive testing (
-
Add the Build Target: Add a new
add_conformance_test(...)entry to/tests/CMakeLists.txtto make the test buildable.