Skip to content

Give devices without PCI topology a stable cache identity - #68

Merged
galekseev merged 1 commit into
masterfrom
fix/opencl-cache-identity
Aug 8, 2026
Merged

Give devices without PCI topology a stable cache identity#68
galekseev merged 1 commit into
masterfrom
fix/opencl-cache-identity

Conversation

@galekseev

Copy link
Copy Markdown

Summary

The compiled-kernel cache never hit on an Apple GPU. getUniqueDeviceIdentifier asks for CL_DEVICE_PCI_BUS_ID_NV and CL_DEVICE_PCI_SLOT_ID_NV, which Apple's runtime does not implement, and clGetWrapper returned the value it declared without initializing it and without looking at the error code:

template <typename T, typename U, typename V, typename W>
T clGetWrapper(U function, V param, W param2) {
	T t;
	function(param, param2, sizeof(t), &t, NULL);
	return t;
}

So the identifier was whatever was on the stack. Three consecutive runs on an M4 Max wrote three different cache files and every one reported precompiled = no, meaning the kernel was recompiled on every start.

Queries now go through clGetWrapperChecked, which zeroes the value and reports whether the runtime answered. Where neither vendor extension is available, the identifier is an FNV-1a hash of the device name, vendor and driver version. Two identical GPUs hash to one entry, which is correct: the binary they need is the same. Devices that do report PCI topology keep the identifier they had, so caches already on disk stay valid and NVIDIA and AMD see no change.

The same missing check made clGetWrapperString size its buffer from an uninitialized length whenever a query failed.

Two smaller things ride along. The container smoke test had a blind spot: without a GPU the program exits before loading a kernel, so nothing verified the kernels were in the image at all - it now checks they sit next to the binary. And the two bench examples pointed at pr57-head, a branch that only ever existed on one laptop, rather than the portable pr/57.

Test plan

  • on an M4 Max, three runs now produce one cache file, with runs 2 and 3 reporting precompiled = yes; before the change it was three files and precompiled = no every time
  • make and make -C tests build without warnings, test_correctness_pr49.x64 passes
  • the PCI path is untouched, so cache filenames on NVIDIA and AMD are unchanged
  • CI builds the image and confirms the kernels are next to the binary in it

Made with Cursor

The kernel cache never hit on an Apple GPU. getUniqueDeviceIdentifier asks for
CL_DEVICE_PCI_BUS_ID_NV and CL_DEVICE_PCI_SLOT_ID_NV, which Apple's runtime
does not implement, and clGetWrapper returned the value it declared without
initializing it and without looking at the error code. The identifier was
therefore whatever happened to be on the stack: three consecutive runs on an
M4 Max wrote three cache files and every one of them reported
"precompiled = no".

Queries now go through clGetWrapperChecked, which zeroes the value and reports
whether the runtime answered. Where neither vendor extension is available the
identifier is an FNV-1a hash of the device name, vendor and driver version.
Two identical GPUs hash to one entry, which is what you want: the binary they
need is the same. Devices that do report PCI topology keep the identifier they
had, so caches already on disk stay valid.

The same missing check made clGetWrapperString size its buffer from an
uninitialized length whenever a query failed; it now returns an empty string.

Also drops the container smoke test's blind spot: without a GPU the program
exits before loading a kernel, so nothing verified the kernels were in the
image at all, and points the two bench examples at pr/57 rather than a branch
that only ever existed on one laptop.

Co-authored-by: Cursor <cursoragent@cursor.com>
@galekseev
galekseev merged commit d6c2e5e into master Aug 8, 2026
1 check passed
@galekseev
galekseev deleted the fix/opencl-cache-identity branch August 8, 2026 21:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant