Bugfix - Use volatile accesses for HIP zero-copy loads/stores in gpu-copy-bw - #838
Bugfix - Use volatile accesses for HIP zero-copy loads/stores in gpu-copy-bw#838polarG wants to merge 2 commits into
Conversation
The HIP branch of FetchULong2/StoreULong2 used plain cacheable accesses for zero-copy host-mapped memory, unlike the CUDA path which uses ld/st.volatile.global. This could serve stale data and fail the CheckBuf memcmp for cpu_to_gpu*_by_sm (observed on MI300X/ROCm 6.4.4). Use volatile accesses to match the CUDA path.
There was a problem hiding this comment.
Pull request overview
This PR hardens the HIP implementation of gpu-copy-bw’s 16-byte zero-copy (host-mapped / peer) load/store helpers to better match the intent of the CUDA path by forcing volatile-qualified accesses.
Changes:
- Update HIP
FetchULong2()to read viaconst volatile ulong2*instead of a plain pointer dereference. - Update HIP
StoreULong2()to write viavolatile ulong2*instead of a plain pointer dereference.
Comments suppressed due to low confidence (1)
superbench/benchmarks/micro_benchmarks/gpu_copy_performance/gpu_copy.cu:622
- Similar to
FetchULong2, the comment here states the CUDA volatile store is "uncached". Volatile primarily constrains compiler optimizations/reordering; cache behavior can be architecture/toolchain dependent. Rewording would keep the intent accurate.
// Use a volatile access so the compiler does not cache/reorder this zero-copy write to
// host-mapped (or peer) memory, matching the uncached st.volatile.global on the CUDA path.
volatile ulong2 *vp = reinterpret_cast<volatile ulong2 *>(p);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Use a volatile access so the compiler does not cache/reorder this zero-copy read of | ||
| // host-mapped (or peer) memory, matching the uncached ld.volatile.global on the CUDA path. | ||
| const volatile ulong2 *vp = reinterpret_cast<const volatile ulong2 *>(p); |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #838 +/- ##
=======================================
Coverage 86.02% 86.02%
=======================================
Files 103 103
Lines 7950 7950
=======================================
Hits 6839 6839
Misses 1111 1111
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
torch pulls in an unpinned setuptools during 'pip install .[test,cpuworker]', which upgrades the 65.7 pinned by the pipeline to 83.0.0 and makes the setup.py guard raise VersionConflict on the python-3.10 lint job. setuptools 66+ only drops Python 3.7, so keep the cap there only.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (2)
superbench/benchmarks/micro_benchmarks/gpu_copy_performance/gpu_copy.cu:606
- The HIP path doesn’t need a reinterpret_cast to add volatile qualifiers; you can rely on the standard pointer qualification conversion. Also, the comment claims an "uncached" match to CUDA PTX, but
volatilein C++ primarily constrains compiler optimizations (it doesn’t necessarily imply a hardware cache-bypass), so the wording is misleading.
// Use a volatile access so the compiler does not cache/reorder this zero-copy read of
// host-mapped (or peer) memory, matching the uncached ld.volatile.global on the CUDA path.
const volatile ulong2 *vp = reinterpret_cast<const volatile ulong2 *>(p);
v.x = vp->x;
v.y = vp->y;
superbench/benchmarks/micro_benchmarks/gpu_copy_performance/gpu_copy.cu:624
- Same as the load side: the cast isn’t needed to add
volatile, and the comment’s "uncached" claim is stronger than what C++volatileguarantees on HIP (it constrains compiler reordering/caching, not necessarily the GPU cache hierarchy).
// Use a volatile access so the compiler does not cache/reorder this zero-copy write to
// host-mapped (or peer) memory, matching the uncached st.volatile.global on the CUDA path.
volatile ulong2 *vp = reinterpret_cast<volatile ulong2 *>(p);
vp->x = v.x;
vp->y = v.y;
Description
The
gpu-copy-bwmicro-benchmark's SM-copy kernels use two helper functions,FetchULong2()andStoreULong2()(superbench/benchmarks/micro_benchmarks/gpu_copy_performance/gpu_copy.cu), to read/write 16-byte chunks from/to zero-copy host-mapped (or peer) memory. On the CUDA path these already useld.volatile.global/st.volatile.globalinline PTX — uncached, non-reorderable accesses, which is the correct pattern for memory that can be concurrently written by another device/host and isn't guaranteed to be cache-coherent through the normal load/store path. On the HIP path, the same functions instead did a plain, cacheable pointer dereference (v.x = p->x; v.y = p->y;), so the compiler was free to cache, reorder, or otherwise not treat these as true "read what's actually there right now" accesses.This PR reinterprets the pointer as
volatile ulong2*before dereferencing on the HIP path, forcing an uncached, non-reorderable access that matches the CUDA behavior.Investigation context
This fix was originally written to explain a
gpu-copy-bw:correctnessfailure (CheckBuf: Memory check failedoncpu_to_gpu0_by_sm_under_numa0) observed during a full SuperBench run on an MI300X/ROCm 6.4.4 host. Follow-up in-container investigation (rebuildinggpu_copyfrom source with an explicit--offload-arch=gfx942) showed that the actual failure in that run was caused by a missingAMDGPU_TARGETSbuild flag in the ROCm 6.4 Dockerfile, which madehipccsilently default togfx906when no GPU was present atdocker buildtime — the resulting binary then ran wrong-architecture kernels on the gfx942 MI300X hardware and produced bad reads. That Dockerfile fix is tracked separately in #837.With the correct
gfx942arch, the correctness suite passes 321/321 with or without thisvolatilechange, so it was not the root cause of the specific failure observed. It is included here anyway as a genuine correctness hardening: the HIP path for zero-copy memory access should not silently diverge from the CUDA path's use of volatile/uncached semantics, and leaving it as a plain access is latent-bug-prone on any HIP toolchain/compiler version that becomes more aggressive about caching such reads.Major Revision
FetchULong2()(HIP branch): read through aconst volatile ulong2 *instead of a plainconst ulong2 *.StoreULong2()(HIP branch): write through avolatile ulong2 *instead of a plainulong2 *.Minor Revision
Testing
gpu_copyin-container on an 8x MI300X host with--offload-arch=gfx942; correctness suite (--check_data) passes 321/321 both with and without this change once the Dockerfile'sAMDGPU_TARGETSfix (Dockerfile - Add ROCm6.4 dockerfile #837) is applied.#if defined(__HIP_PLATFORM_HCC__) || defined(__HCC__) || defined(__HIPCC__)branch).