summaryrefslogtreecommitdiffstats
path: root/tools/cuda-ab/memset_probe.cu
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-21 10:58:58 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-21 10:58:58 -0400
commit9f68e5e304416a7d2148903eada9caffd7b0779e (patch)
treee4f0ce258497a38ba9235e8e5680a222373e8799 /tools/cuda-ab/memset_probe.cu
parent7685d1b315d0a5435374c8c6b9ca1a3a4eab39fa (diff)
downloadopen-iov-9f68e5e304416a7d2148903eada9caffd7b0779e.tar.gz
open-iov-9f68e5e304416a7d2148903eada9caffd7b0779e.zip
tools/cuda-ab: memset_probe + wedge_recover forensics clients (session 10)
memset_probe: linear 8 MB cudaMemset + D2H with first-bad offset and a 4 KB page map (correct / other / malloc-prefill) - separates 'fill under-delivered' from 'readback delivered wrong pages'; standalone green, bisects the memcpy_roundtrip memset phase. wedge_recover: launch+verify loop that on failure sleeps N seconds and retries the same iteration (same context), reporting per-iteration attempts and launch times - tests whether an idle gap heals the per-boot no-execute wedge (r409 log shows a ~37 s client-side gap healed a wedged run). Also ships the missing inplace_scale run binary (its source landed in 7685d1b3).
Diffstat (limited to 'tools/cuda-ab/memset_probe.cu')
-rw-r--r--tools/cuda-ab/memset_probe.cu87
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/cuda-ab/memset_probe.cu b/tools/cuda-ab/memset_probe.cu
new file mode 100644
index 0000000..a6a12e0
--- /dev/null
+++ b/tools/cuda-ab/memset_probe.cu
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * memset_probe.cu - isolate the memcpy_roundtrip memset-phase failure.
+ *
+ * cudaMemset(8 MB, 0x5A) -> D2H -> byte verify, with a run-length report:
+ * the first bad offset, and a coverage map at 4 KB granularity (correct /
+ * wrong / untouched-malloc-prefill) so "fill under-delivered" is
+ * distinguishable from "readback delivered wrong pages".
+ *
+ * Build: nvcc -O2 --cudart=static -o memset_probe memset_probe.cu
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cuda_runtime.h>
+
+#define CHECK(x) \
+ do { \
+ cudaError_t e_ = (x); \
+ if (e_ != cudaSuccess) { \
+ printf("CUDA_ERROR %s at line %d\n", \
+ cudaGetErrorString(e_), __LINE__); \
+ printf("STATUS FAIL\n"); \
+ return 1; \
+ } \
+ } while (0)
+
+#define PAGE 4096
+#define MemsetByte 0x5A
+
+int main(void)
+{
+ const size_t bytes = 8u << 20;
+ unsigned char *h;
+ unsigned char *d;
+ size_t i;
+ int bad = 0;
+ size_t first_bad = (size_t)-1;
+ size_t n_pages, p;
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+ h = (unsigned char *)malloc(bytes);
+ if (!h)
+ return 1;
+ memset(h, 0xEE, bytes);
+
+ CHECK(cudaMalloc(&d, bytes));
+ printf("DPTR d=%p bytes=%zu\n", (void *)d, bytes);
+
+ CHECK(cudaMemset(d, MemsetByte, bytes));
+ CHECK(cudaDeviceSynchronize());
+ CHECK(cudaMemcpy(h, d, bytes, cudaMemcpyDeviceToHost));
+
+ for (i = 0; i < bytes; i++) {
+ if (h[i] != (unsigned char)MemsetByte) {
+ if (first_bad == (size_t)-1)
+ first_bad = i;
+ bad++;
+ }
+ }
+ printf("FIRST_BAD off=%zu (0x%zx) bad=%d total=%zu\n",
+ first_bad, first_bad, bad, bytes);
+ n_pages = bytes / PAGE;
+ for (p = 0; p < n_pages; p++) {
+ int good = 1, prefill = 1;
+
+ for (i = 0; i < PAGE; i++) {
+ if (h[p * PAGE + i] != (unsigned char)MemsetByte)
+ good = 0;
+ if (h[p * PAGE + i] != 0xEE)
+ prefill = 0;
+ if (!good && !prefill)
+ break;
+ }
+ if (!good) {
+ printf("PAGE %zu %s b0=%02x b1=%02x b2=%02x b3=%02x b4095=%02x\n",
+ p, prefill ? "PREFILL" : "OTHER",
+ h[p * PAGE], h[p * PAGE + 1],
+ h[p * PAGE + 2], h[p * PAGE + 3],
+ h[p * PAGE + 4095]);
+ if (p > 24)
+ break;
+ }
+ }
+ printf("STATUS %s\n", bad == 0 ? "OK" : "FAIL");
+ return 0;
+}