Sanitizer-lite: memcheck / initcheck / racecheck / synccheck#
A CPU-single-thread simulator sees the whole interleaving, so it can flag bugs a real GPU hides — approximating NVIDIA compute-sanitizer with no GPU. All of it is behind SIM_CHECK (define it before including this header; only the CPU build does). Access the memory you want checked through SIM_LD / SIM_ST; the query API reports how many faults each checker saw. Without SIM_CHECK every hook is a no-op, SIM_LD/ST are a plain p[i], and the counters read zero.
Defined in code/simulator.h.
This page documents 17 symbols: 2 macros, 15 functions.
Macros#
Functions#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
sim only |
simulator.h:3721 |
||
|
sim only |
simulator.h:3729 |
||
|
sim only |
simulator.h:3693 |
||
|
sim only |
simulator.h:3690 |
||
|
Does [p, p+n) lie inside one tracked allocation (or the dynamic-shared buffer)? |
sim only |
simulator.h:3698 |
|
|
sim only |
simulator.h:3692 |
||
|
sim only |
simulator.h:3694 |
||
|
sim only |
simulator.h:3689 |
||
|
Record an access at byte address |
sim only |
simulator.h:3713 |
|
|
sim + nvcc |
simulator.h:3763 |
||
|
sim + nvcc |
simulator.h:3760 |
||
|
Public query API: number of faults each checker has seen since the last simCheckReset(). |
sim + nvcc |
simulator.h:3759 |
|
|
sim + nvcc |
simulator.h:3761 |
||
|
sim + nvcc |
simulator.h:3762 |
||
|
sim only |
simulator.h:3695 |
Examples#
Code from the repository’s example corpus (code\*.cu); the highlighted line is the call site. These blocks are what the View links above open.
SIM_LD (test_sanitizer.cu:38)
28 } \
29 } while (0)
30
31constexpr int BLK = 32;
32
33// memcheck: out-of-bounds store vs. in-bounds store.
34__global__ void kOOB(int* out, int n) { SIM_ST(out, threadIdx.x + n, 1); }
35__global__ void kInBounds(int* out, int n) { unsigned i = threadIdx.x; if (i < (unsigned)n) SIM_ST(out, i, 1); }
36
37// initcheck: read a buffer that was never written vs. one that was.
38__global__ void kReadInto(const int* in, int* out) { unsigned i = threadIdx.x; SIM_ST(out, i, SIM_LD(in, i)); }
39
40// racecheck: many threads write the same address with no sync vs. distinct addresses.
41__global__ void kRaceWrite(int* out) { SIM_ST(out, 0, (int)threadIdx.x); }
42__global__ void kNoRace(int* out) { unsigned i = threadIdx.x; SIM_ST(out, i, (int)i); }
43
44// synccheck: __syncthreads reached by only some threads vs. all.
45__global__ void kSyncDiverge(int* out) {
46 unsigned t = threadIdx.x;
47 if (t < 16) { SIM_ST(out, t, 1); return; } // these exit before the barrier
48 __syncthreads(); // only t >= 16 arrive -> divergence
49 SIM_ST(out, t, 2);
SIM_ST (test_sanitizer.cu:34)
24 std::fprintf(stderr, "CUDA error %s at %s:%d: %s\n", \
25 cudaGetErrorName(err_), __FILE__, __LINE__, \
26 cudaGetErrorString(err_)); \
27 std::exit(EXIT_FAILURE); \
28 } \
29 } while (0)
30
31constexpr int BLK = 32;
32
33// memcheck: out-of-bounds store vs. in-bounds store.
34__global__ void kOOB(int* out, int n) { SIM_ST(out, threadIdx.x + n, 1); }
35__global__ void kInBounds(int* out, int n) { unsigned i = threadIdx.x; if (i < (unsigned)n) SIM_ST(out, i, 1); }
36
37// initcheck: read a buffer that was never written vs. one that was.
38__global__ void kReadInto(const int* in, int* out) { unsigned i = threadIdx.x; SIM_ST(out, i, SIM_LD(in, i)); }
39
40// racecheck: many threads write the same address with no sync vs. distinct addresses.
41__global__ void kRaceWrite(int* out) { SIM_ST(out, 0, (int)threadIdx.x); }
42__global__ void kNoRace(int* out) { unsigned i = threadIdx.x; SIM_ST(out, i, (int)i); }
43
44// synccheck: __syncthreads reached by only some threads vs. all.
45__global__ void kSyncDiverge(int* out) {
simCheckReset (test_sanitizer.cu:76)
66 int deviceCount = 0;
67 if (cudaGetDeviceCount(&deviceCount) != cudaSuccess || deviceCount == 0) { std::printf("no device\n"); return 0; }
68 cudaDeviceProp prop{}; CUDA_CHECK(cudaGetDeviceProperties(&prop, 0));
69 std::printf("Device 0: %s (compute %d.%d)\n\n", prop.name, prop.major, prop.minor);
70
71 bool all = true;
72 int* out = nullptr; CUDA_CHECK(cudaMalloc(&out, BLK * sizeof(int)));
73 int* in = nullptr; CUDA_CHECK(cudaMalloc(&in, BLK * sizeof(int)));
74
75 // ---- memcheck --------------------------------------------------------
76 simCheckReset();
77 LAUNCH(kOOB, 1, BLK, out, BLK);
78 all &= expect("memcheck: OOB store", simMemcheckErrors() > 0, true);
79 simCheckReset();
80 LAUNCH(kInBounds, 1, BLK, out, BLK);
81 all &= expect("memcheck: in-bounds store", simMemcheckErrors() > 0, false);
82
83 // ---- initcheck -------------------------------------------------------
84 simCheckReset();
85 LAUNCH(kReadInto, 1, BLK, in, out); // `in` never initialised
86 all &= expect("initcheck: read uninitialised", simInitcheckErrors() > 0, true);
87 simCheckReset();
simInitcheckErrors (test_sanitizer.cu:86)
76 simCheckReset();
77 LAUNCH(kOOB, 1, BLK, out, BLK);
78 all &= expect("memcheck: OOB store", simMemcheckErrors() > 0, true);
79 simCheckReset();
80 LAUNCH(kInBounds, 1, BLK, out, BLK);
81 all &= expect("memcheck: in-bounds store", simMemcheckErrors() > 0, false);
82
83 // ---- initcheck -------------------------------------------------------
84 simCheckReset();
85 LAUNCH(kReadInto, 1, BLK, in, out); // `in` never initialised
86 all &= expect("initcheck: read uninitialised", simInitcheckErrors() > 0, true);
87 simCheckReset();
88 CUDA_CHECK(cudaMemset(in, 0, BLK * sizeof(int))); // now initialised
89 LAUNCH(kReadInto, 1, BLK, in, out);
90 all &= expect("initcheck: read initialised", simInitcheckErrors() > 0, false);
91
92 // ---- racecheck -------------------------------------------------------
93 simCheckReset();
94 LAUNCH(kRaceWrite, 1, BLK, out); // all write address 0, no sync
95 all &= expect("racecheck: unsynced same addr", simRacecheckErrors() > 0, true);
96 simCheckReset();
97 LAUNCH(kNoRace, 1, BLK, out); // distinct addresses
simMemcheckErrors (test_sanitizer.cu:78)
68 cudaDeviceProp prop{}; CUDA_CHECK(cudaGetDeviceProperties(&prop, 0));
69 std::printf("Device 0: %s (compute %d.%d)\n\n", prop.name, prop.major, prop.minor);
70
71 bool all = true;
72 int* out = nullptr; CUDA_CHECK(cudaMalloc(&out, BLK * sizeof(int)));
73 int* in = nullptr; CUDA_CHECK(cudaMalloc(&in, BLK * sizeof(int)));
74
75 // ---- memcheck --------------------------------------------------------
76 simCheckReset();
77 LAUNCH(kOOB, 1, BLK, out, BLK);
78 all &= expect("memcheck: OOB store", simMemcheckErrors() > 0, true);
79 simCheckReset();
80 LAUNCH(kInBounds, 1, BLK, out, BLK);
81 all &= expect("memcheck: in-bounds store", simMemcheckErrors() > 0, false);
82
83 // ---- initcheck -------------------------------------------------------
84 simCheckReset();
85 LAUNCH(kReadInto, 1, BLK, in, out); // `in` never initialised
86 all &= expect("initcheck: read uninitialised", simInitcheckErrors() > 0, true);
87 simCheckReset();
88 CUDA_CHECK(cudaMemset(in, 0, BLK * sizeof(int))); // now initialised
89 LAUNCH(kReadInto, 1, BLK, in, out);
simRacecheckErrors (test_sanitizer.cu:95)
85 LAUNCH(kReadInto, 1, BLK, in, out); // `in` never initialised
86 all &= expect("initcheck: read uninitialised", simInitcheckErrors() > 0, true);
87 simCheckReset();
88 CUDA_CHECK(cudaMemset(in, 0, BLK * sizeof(int))); // now initialised
89 LAUNCH(kReadInto, 1, BLK, in, out);
90 all &= expect("initcheck: read initialised", simInitcheckErrors() > 0, false);
91
92 // ---- racecheck -------------------------------------------------------
93 simCheckReset();
94 LAUNCH(kRaceWrite, 1, BLK, out); // all write address 0, no sync
95 all &= expect("racecheck: unsynced same addr", simRacecheckErrors() > 0, true);
96 simCheckReset();
97 LAUNCH(kNoRace, 1, BLK, out); // distinct addresses
98 all &= expect("racecheck: distinct addrs", simRacecheckErrors() > 0, false);
99
100 // ---- synccheck -------------------------------------------------------
101 simCheckReset();
102 LAUNCH(kSyncDiverge, 1, BLK, out);
103 all &= expect("synccheck: divergent barrier", simSynccheckErrors() > 0, true);
104 simCheckReset();
105 LAUNCH(kSyncClean, 1, BLK, out);
106 all &= expect("synccheck: uniform barrier", simSynccheckErrors() > 0, false);
simSynccheckErrors (test_sanitizer.cu:103)
93 simCheckReset();
94 LAUNCH(kRaceWrite, 1, BLK, out); // all write address 0, no sync
95 all &= expect("racecheck: unsynced same addr", simRacecheckErrors() > 0, true);
96 simCheckReset();
97 LAUNCH(kNoRace, 1, BLK, out); // distinct addresses
98 all &= expect("racecheck: distinct addrs", simRacecheckErrors() > 0, false);
99
100 // ---- synccheck -------------------------------------------------------
101 simCheckReset();
102 LAUNCH(kSyncDiverge, 1, BLK, out);
103 all &= expect("synccheck: divergent barrier", simSynccheckErrors() > 0, true);
104 simCheckReset();
105 LAUNCH(kSyncClean, 1, BLK, out);
106 all &= expect("synccheck: uniform barrier", simSynccheckErrors() > 0, false);
107
108 CUDA_CHECK(cudaFree(out));
109 CUDA_CHECK(cudaFree(in));
110
111 std::printf("\ntest_sanitizer: %s\n", all ? "ALL PASSED" : "FAILED");
112 return all ? 0 : 1;
113}