xref: /llvm-project/libc/docs/gpu/testing.rst (revision 6818c7b8efef16ff373a1d8a6d7e35ecf14541be)
1.. _libc_gpu_testing:
2
3
4=========================
5Testing the GPU C library
6=========================
7
8.. note::
9   Running GPU tests with high parallelism is likely to cause spurious failures,
10   out of resource errors, or indefinite hangs. limiting the number of threads
11   used while testing using ``LIBC_GPU_TEST_JOBS=<N>`` is highly recommended.
12
13.. contents:: Table of Contents
14  :depth: 4
15  :local:
16
17Testing infrastructure
18======================
19
20The LLVM C library supports different kinds of :ref:`tests <build_and_test>`
21depending on the build configuration. The GPU target is considered a full build
22and therefore provides all of its own utilities to build and run the generated
23tests. Currently the GPU supports two kinds of tests.
24
25#. **Hermetic tests** - These are unit tests built with a test suite similar to
26   Google's ``gtest`` infrastructure. These use the same infrastructure as unit
27   tests except that the entire environment is self-hosted. This allows us to
28   run them on the GPU using our custom utilities. These are used to test the
29   majority of functional implementations.
30
31#. **Integration tests** - These are lightweight tests that simply call a
32   ``main`` function and checks if it returns non-zero. These are primarily used
33   to test interfaces that are sensitive to threading.
34
35The GPU uses the same testing infrastructure as the other supported ``libc``
36targets. We do this by treating the GPU as a standard hosted environment capable
37of launching a ``main`` function. Effectively, this means building our own
38startup libraries and loader.
39
40Testing utilities
41=================
42
43We provide two utilities to execute arbitrary programs on the GPU. That is the
44``loader`` and the ``start`` object.
45
46Startup object
47--------------
48
49This object mimics the standard object used by existing C library
50implementations. Its job is to perform the necessary setup prior to calling the
51``main`` function. In the GPU case, this means exporting GPU kernels that will
52perform the necessary operations. Here we use ``_begin`` and ``_end`` to handle
53calling global constructors and destructors while ``_start`` begins the standard
54execution. The following code block shows the implementation for AMDGPU
55architectures.
56
57.. code-block:: c++
58
59  extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
60  _begin(int argc, char **argv, char **env) {
61    LIBC_NAMESPACE::atexit(&LIBC_NAMESPACE::call_fini_array_callbacks);
62    LIBC_NAMESPACE::call_init_array_callbacks(argc, argv, env);
63  }
64
65  extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
66  _start(int argc, char **argv, char **envp, int *ret) {
67    __atomic_fetch_or(ret, main(argc, argv, envp), __ATOMIC_RELAXED);
68  }
69
70  extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
71  _end(int retval) {
72    LIBC_NAMESPACE::exit(retval);
73  }
74
75Loader runtime
76--------------
77
78The startup object provides a GPU executable with callable kernels for the
79respective runtime. We can then define a minimal runtime that will launch these
80kernels on the given device. Currently we provide the ``amdhsa-loader`` and
81``nvptx-loader`` targeting the AMD HSA runtime and CUDA driver runtime
82respectively. By default these will launch with a single thread on the GPU.
83
84.. code-block:: sh
85
86   $> clang++ crt1.o test.cpp --target=amdgcn-amd-amdhsa -mcpu=native -flto
87   $> amdhsa_loader --threads 1 --blocks 1 ./a.out
88   Test Passed!
89
90The loader utility will forward any arguments passed after the executable image
91to the program on the GPU as well as any set environment variables. The number
92of threads and blocks to be set can be controlled with ``--threads`` and
93``--blocks``. These also accept additional ``x``, ``y``, ``z`` variants for
94multidimensional grids.
95
96Running tests
97=============
98
99Tests will only be built and run if a GPU target architecture is set and the
100corresponding loader utility was built. These can be overridden with the
101``LIBC_GPU_TEST_ARCHITECTURE`` and ``LIBC_GPU_LOADER_EXECUTABLE`` :ref:`CMake
102options <gpu_cmake_options>`. Once built, they can be run like any other tests.
103The CMake target depends on how the library was built.
104
105#. **Cross build** - If the C library was built using ``LLVM_ENABLE_PROJECTS``
106   or a runtimes cross build, then the standard targets will be present in the
107   base CMake build directory.
108
109   #. All tests - You can run all supported tests with the command:
110
111      .. code-block:: sh
112
113        $> ninja check-libc
114
115   #. Hermetic tests - You can run hermetic with tests the command:
116
117      .. code-block:: sh
118
119        $> ninja libc-hermetic-tests
120
121   #. Integration tests - You can run integration tests by the command:
122
123      .. code-block:: sh
124
125        $> ninja libc-integration-tests
126
127#. **Runtimes build** - If the library was built using ``LLVM_ENABLE_RUNTIMES``
128   then the actual ``libc`` build will be in a separate directory.
129
130   #. All tests - You can run all supported tests with the command:
131
132      .. code-block:: sh
133
134        $> ninja check-libc-amdgcn-amd-amdhsa
135        $> ninja check-libc-nvptx64-nvidia-cuda
136
137   #. Specific tests - You can use the same targets as above by entering the
138      runtimes build directory.
139
140      .. code-block:: sh
141
142        $> ninja -C runtimes/runtimes-amdgcn-amd-amdhsa-bins check-libc
143        $> ninja -C runtimes/runtimes-nvptx64-nvidia-cuda-bins check-libc
144        $> cd runtimes/runtimes-amdgcn-amd-amdhsa-bins && ninja check-libc
145        $> cd runtimes/runtimes-nvptx64-nvidia-cuda-bins && ninja check-libc
146
147Tests can also be built and run manually using the respective loader utility.
148