Skip to content

Commit 01743fb

Browse files
committed
GPU: make the kernel entry-point signature work on Metal
MSL has no by-value kernel parameters: every one must carry an attribute naming a buffer or a builtin. It also has no ambient work-item builtins, so the grid dimensions arrive as attributes on the entry point too. GPUCA_KRNLGPU_DEF therefore gets two hooks, GPUCA_KRNL_SECTOR_ARG and GPUCA_KRNL_GRID_ARGS, which the Metal source fills in with a buffer and the four grid attributes. Both default to what the signature had, so CUDA, HIP and OpenCL generate exactly the same entry point as before. The attributes are named after the nBlocks, nThreads, iBlock and iThread that Thread() already takes, so the get_*() helpers resolve at the entry point and in everything it calls. Metal still needs its own definitions of them because the host ones assume one thread per block: get_local_id() is 0 and get_local_size() is 1 there. The generated arguments need an attribute too, each with a distinct buffer index, and the preprocessor cannot supply one: the kernel list splices arguments as a flat comma-separated list, and __COUNTER__ is monotonic across the translation unit rather than per kernel. o2_gpu_add_kernel already walks the arguments in pairs, so it emits the index there. Declarations go through GPUPtr1(idx, type, name) for pointers and GPUArg1(idx, type, name) for scalars, which each backend defines as it needs. Indices start at 3, after gpu_mem, the constant memory and the sector; the sector itself is nothing special, it just lives in the fixed part of the macro rather than in the generated list. Metal masks pointers as a 64-bit address exactly as OpenCL does, and for the same reason: GPUTRDTrackerKernels takes a GPUTRDTrackerGPU*, and a pointer to a derived class is not a valid kernel argument type there either. Binding POD pointers directly would have worked but would not have covered that case, so both go the same way. On the way back in, GPUPtr2 casts through device before handing the pointer to Thread(): the kernel's own buffers are device memory, but the Thread() entry points take the pointer unannotated, which in MSL means generic. Generated entry points are byte-identical for CUDA, HIP and OpenCL. Kernel list diagnostics: 408 to 0, and the translation unit 1108 to 881.
1 parent 7518d76 commit 01743fb

5 files changed

Lines changed: 52 additions & 11 deletions

File tree

‎GPU/Common/GPUCommonDefAPI.h‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,16 @@
277277
#define get_group_id(dim) (blockIdx.x)
278278
#elif defined(__OPENCL__)
279279
// Using OpenCL defaults
280+
#elif defined(__METAL__)
281+
// MSL has no work-item builtins. They arrive as attributes on the entry point,
282+
// named there after the nBlocks / nThreads / iBlock / iThread that Thread()
283+
// already takes, so these resolve both there and in every function below it.
284+
#define get_global_id(dim) (iBlock * nThreads + iThread)
285+
#define get_global_size(dim) (nBlocks * nThreads)
286+
#define get_num_groups(dim) (nBlocks)
287+
#define get_local_id(dim) (iThread)
288+
#define get_local_size(dim) (nThreads)
289+
#define get_group_id(dim) (iBlock)
280290
#else
281291
#define get_global_id(dim) iBlock
282292
#define get_global_size(dim) nBlocks

‎GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,17 @@
6363
#define GPUCA_ATTRRES(...) GPUCA_M_EXPAND(GPUCA_M_CAT(GPUCA_ATTRRES_, GPUCA_M_FIRST(__VA_ARGS__)))(__VA_ARGS__)
6464

6565
// GPU Kernel entry point
66+
// MSL requires every kernel parameter to carry an attribute, and supplies the
67+
// grid dimensions the same way, so the backend gets to shape both ends of the
68+
// parameter list.
69+
#ifndef GPUCA_KRNL_SECTOR_ARG
70+
#define GPUCA_KRNL_SECTOR_ARG int32_t _iSector_internal
71+
#endif
72+
#ifndef GPUCA_KRNL_GRID_ARGS
73+
#define GPUCA_KRNL_GRID_ARGS
74+
#endif
6675
#define GPUCA_KRNLGPU_DEF(x_class, x_attributes, x_arguments, ...) \
67-
GPUg() void GPUCA_ATTRRES(GPUCA_M_STRIP(x_attributes)) GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))(GPUCA_CONSMEM_PTR int32_t _iSector_internal GPUCA_M_STRIP(x_arguments))
76+
GPUg() void GPUCA_ATTRRES(GPUCA_M_STRIP(x_attributes)) GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))(GPUCA_CONSMEM_PTR GPUCA_KRNL_SECTOR_ARG GPUCA_M_STRIP(x_arguments) GPUCA_KRNL_GRID_ARGS)
6877

6978
#ifdef GPUCA_KRNL_DEFONLY
7079
#define GPUCA_KRNLGPU(...) GPUCA_KRNLGPU_DEF(__VA_ARGS__);

‎GPU/GPUTracking/Base/metal/GPUReconstructionMETAL.metal‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ using namespace metal;
7070
device char* pConstantRaw [[buffer(1)]],
7171
#define GPUCA_CONSMEM (*(device GPUConstantMem*)pConstantRaw)
7272

73+
// Every kernel parameter needs an attribute, so the sector index arrives as a
74+
// buffer rather than by value, and the grid dimensions come in at the end, where
75+
// GPUCommonDefAPI.h's get_group_id() and friends pick them up.
76+
#define GPUCA_KRNL_SECTOR_ARG constant int32_t& _iSector_internal [[buffer(2)]]
77+
#define GPUCA_KRNL_GRID_ARGS \
78+
, uint iBlock [[threadgroup_position_in_grid]] \
79+
, uint iThread [[thread_position_in_threadgroup]] \
80+
, uint nThreads [[threads_per_threadgroup]] \
81+
, uint nBlocks [[threadgroups_per_grid]]
82+
7383
#include "GPUReconstructionKernelList.h"
7484

7585
// clang-format on

‎GPU/GPUTracking/Definitions/GPUDef.h‎

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,27 @@
2121
#include "GPUDefParametersWrapper.h"
2222
#include "GPUCommonRtypes.h"
2323

24-
// Macros for masking ptrs in OpenCL kernel calls as uint64_t (The API only allows us to pass buffer objects)
24+
// Macros for kernel arguments. OpenCL can only pass buffer objects, so pointers
25+
// are masked as uint64_t and cast back inside the kernel. MSL needs an explicit
26+
// buffer index on every parameter, but can bind a pointer directly. The index is
27+
// emitted per argument by o2_gpu_add_kernel; 0, 1 and 2 are taken by gpu_mem,
28+
// the constant memory and the sector index.
2529
#ifdef __OPENCL__
26-
#define GPUPtr1(a, b) uint64_t b
27-
#ifdef __OPENCL__
28-
#define GPUPtr2(a, b) ((__generic a) (a) b)
29-
#else
30-
#define GPUPtr2(a, b) ((__global a) (a) b)
31-
#endif
30+
#define GPUPtr1(idx, a, b) uint64_t b
31+
#define GPUPtr2(a, b) ((__generic a) (a) b)
32+
#define GPUArg1(idx, a, b) a b
33+
#elif defined(__METAL__)
34+
// As for OpenCL, pointers travel as a 64-bit address: a pointer to a derived
35+
// class is not a valid kernel argument type in MSL either.
36+
#define GPUPtr1(idx, a, b) constant uint64_t& b [[buffer(idx)]]
37+
// through device and then to generic: the kernel's own buffers are device
38+
// memory, but the Thread() entry points take the pointer unannotated
39+
#define GPUPtr2(a, b) ((a)((device a)(b)))
40+
#define GPUArg1(idx, a, b) constant a& b [[buffer(idx)]]
3241
#else
33-
#define GPUPtr1(a, b) a b
42+
#define GPUPtr1(idx, a, b) a b
3443
#define GPUPtr2(a, b) b
44+
#define GPUArg1(idx, a, b) a b
3545
#endif
3646

3747
#define GPUCA_EVDUMP_FILE "event"

‎GPU/GPUTracking/cmake/kernel_helpers.cmake‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,13 @@ function(o2_gpu_add_kernel kernel_name kernel_files)
5555
math(EXPR n "${n} - 1")
5656
foreach(i RANGE 3 ${n} 2)
5757
math(EXPR j "${i} + 1")
58+
# buffer indices 0, 1 and 2 are gpu_mem, the constant memory and the sector
59+
math(EXPR TMP_ARG_IDX "3 + (${i} - 3) / 2")
5860
if(${ARGV${i}} MATCHES "\\*$")
59-
string(APPEND OPT1 ",GPUPtr1(${ARGV${i}},${ARGV${j}})")
61+
string(APPEND OPT1 ",GPUPtr1(${TMP_ARG_IDX},${ARGV${i}},${ARGV${j}})")
6062
string(APPEND OPT2 ",GPUPtr2(${ARGV${i}},${ARGV${j}})")
6163
else()
62-
string(APPEND OPT1 ",${ARGV${i}} ${ARGV${j}}")
64+
string(APPEND OPT1 ",GPUArg1(${TMP_ARG_IDX},${ARGV${i}},${ARGV${j}})")
6365
string(APPEND OPT2 ",${ARGV${j}}")
6466
endif()
6567
string(APPEND OPT3 ",${ARGV${i}}")

0 commit comments

Comments
 (0)