Step-debugger hook (reproducible mid-launch inspection)#
Install a callback the scheduler runs at the start of every block and after each __syncthreads() release. It gets a SimDebug handle to read which block / barrier-segment is executing and — the point of it — to CHANGE the thread visit order for the UPCOMING segment. So an agent can “break at the 2nd reduction, reorder the threads, continue one iteration” deterministically, then combine it with a printf/SIM_LD in the kernel to display values (e.g. tid). CPU-sim only; a no-op under nvcc (real GPUs schedule in hardware).
Defined in code/simulator.h.
This page documents 12 symbols: 1 classes, 11 functions.
Classes#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
Step-debugger hook — CPU-sim only; stubbed so a debugging harness compiles and runs on a real GPU (the hook simply never fires there). |
sim + nvcc |
simulator.h:694 |
Functions#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
blockIdx.x of the running block. |
sim + nvcc |
simulator.h:698 |
|
|
sim only |
simulator.h:713 |
||
|
__syncthreads() barriers passed in this block so far: 0 = block start (before the first barrier), 1 = after the first, 2 = after the second, … |
sim + nvcc |
simulator.h:701 |
|
|
Pin the visit order for the upcoming segment(s) of THIS block. |
sim + nvcc |
simulator.h:711 |
|
|
sim + nvcc |
simulator.h:722 |
||
|
sim + nvcc |
simulator.h:738 |
||
|
sim only |
simulator.h:696 |
||
|
Install / remove the step hook (call before a LAUNCH). |
sim + nvcc |
simulator.h:737 |
|
|
sim + nvcc |
simulator.h:702 |
||
|
The visit order the upcoming segment will use (linear thread ids). |
sim + nvcc |
simulator.h:704 |
|
|
sim only |
simulator.h:724 |
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.
block (test_debug.cu:97)
87 // The hook: break at the 2nd reduction (segment 2), print the block/segment,
88 // and reorder the threads for that reduction only.
89 const std::vector<int> custom = {3, 0, 1, 2, 7, 4, 5, 6};
90 std::vector<int> segmentsSeen;
91
92 simSetThreadOrder(OrderThread::sequential()); // default order for all segments
93 simSetStepHook([&](SimDebug& d) {
94 segmentsSeen.push_back(d.segment());
95 if (d.segment() == 2) {
96 std::printf(" [hook] break at block %u, segment %d (2nd reduction): "
97 "reorder threads -> {3,0,1,2,7,4,5,6}\n", d.block(), d.segment());
98 d.setThreadOrder(custom);
99 }
100 });
101
102 std::vector<int> rank = run();
103 simClearStepHook();
104
105 // Show the recorded visit order of each reduction.
106 std::printf("\n visit ranks per reduction (rank[reduction][tid]):\n");
107 for (int s = 0; s < NSEG; ++s) {
108 std::printf(" reduction %d:", s + 1);
seen (test_debug.cu:60)
50 CUDA_CHECK(cudaMalloc(&dCtr, NSEG * sizeof(int)));
51 CUDA_CHECK(cudaMemset(dCtr, 0, NSEG * sizeof(int)));
52 LAUNCH(kReductions, 1, BLOCK, dRank, dCtr);
53 std::vector<int> rank(NSEG * BLOCK);
54 CUDA_CHECK(cudaMemcpy(rank.data(), dRank, rank.size() * sizeof(int), cudaMemcpyDeviceToHost));
55 CUDA_CHECK(cudaFree(dRank)); CUDA_CHECK(cudaFree(dCtr));
56 return rank;
57}
58
59static bool isPermutation(const int* v, int n) {
60 std::vector<char> seen(n, 0);
61 for (int i = 0; i < n; ++i) { int x = v[i]; if (x < 0 || x >= n || seen[x]) return false; seen[x] = 1; }
62 return true;
63}
64static bool matchesOrder(const int* rank, const std::vector<int>& perm) {
65 for (int k = 0; k < static_cast<int>(perm.size()); ++k) if (rank[perm[k]] != k) return false;
66 return true;
67}
68
69int main() {
70 int deviceCount = 0;
71 cudaError_t err = cudaGetDeviceCount(&deviceCount);
segment (test_debug.cu:94)
84 true;
85#endif
86
87 // The hook: break at the 2nd reduction (segment 2), print the block/segment,
88 // and reorder the threads for that reduction only.
89 const std::vector<int> custom = {3, 0, 1, 2, 7, 4, 5, 6};
90 std::vector<int> segmentsSeen;
91
92 simSetThreadOrder(OrderThread::sequential()); // default order for all segments
93 simSetStepHook([&](SimDebug& d) {
94 segmentsSeen.push_back(d.segment());
95 if (d.segment() == 2) {
96 std::printf(" [hook] break at block %u, segment %d (2nd reduction): "
97 "reorder threads -> {3,0,1,2,7,4,5,6}\n", d.block(), d.segment());
98 d.setThreadOrder(custom);
99 }
100 });
101
102 std::vector<int> rank = run();
103 simClearStepHook();
104
105 // Show the recorded visit order of each reduction.
setThreadOrder (test_debug.cu:98)
88 // and reorder the threads for that reduction only.
89 const std::vector<int> custom = {3, 0, 1, 2, 7, 4, 5, 6};
90 std::vector<int> segmentsSeen;
91
92 simSetThreadOrder(OrderThread::sequential()); // default order for all segments
93 simSetStepHook([&](SimDebug& d) {
94 segmentsSeen.push_back(d.segment());
95 if (d.segment() == 2) {
96 std::printf(" [hook] break at block %u, segment %d (2nd reduction): "
97 "reorder threads -> {3,0,1,2,7,4,5,6}\n", d.block(), d.segment());
98 d.setThreadOrder(custom);
99 }
100 });
101
102 std::vector<int> rank = run();
103 simClearStepHook();
104
105 // Show the recorded visit order of each reduction.
106 std::printf("\n visit ranks per reduction (rank[reduction][tid]):\n");
107 for (int s = 0; s < NSEG; ++s) {
108 std::printf(" reduction %d:", s + 1);
109 for (int t = 0; t < BLOCK; ++t) std::printf(" %d", rank[s * BLOCK + t]);
setThreadOrder (test_debug.cu:98)
88 // and reorder the threads for that reduction only.
89 const std::vector<int> custom = {3, 0, 1, 2, 7, 4, 5, 6};
90 std::vector<int> segmentsSeen;
91
92 simSetThreadOrder(OrderThread::sequential()); // default order for all segments
93 simSetStepHook([&](SimDebug& d) {
94 segmentsSeen.push_back(d.segment());
95 if (d.segment() == 2) {
96 std::printf(" [hook] break at block %u, segment %d (2nd reduction): "
97 "reorder threads -> {3,0,1,2,7,4,5,6}\n", d.block(), d.segment());
98 d.setThreadOrder(custom);
99 }
100 });
101
102 std::vector<int> rank = run();
103 simClearStepHook();
104
105 // Show the recorded visit order of each reduction.
106 std::printf("\n visit ranks per reduction (rank[reduction][tid]):\n");
107 for (int s = 0; s < NSEG; ++s) {
108 std::printf(" reduction %d:", s + 1);
109 for (int t = 0; t < BLOCK; ++t) std::printf(" %d", rank[s * BLOCK + t]);
simClearStepHook (test_debug.cu:103)
93 simSetStepHook([&](SimDebug& d) {
94 segmentsSeen.push_back(d.segment());
95 if (d.segment() == 2) {
96 std::printf(" [hook] break at block %u, segment %d (2nd reduction): "
97 "reorder threads -> {3,0,1,2,7,4,5,6}\n", d.block(), d.segment());
98 d.setThreadOrder(custom);
99 }
100 });
101
102 std::vector<int> rank = run();
103 simClearStepHook();
104
105 // Show the recorded visit order of each reduction.
106 std::printf("\n visit ranks per reduction (rank[reduction][tid]):\n");
107 for (int s = 0; s < NSEG; ++s) {
108 std::printf(" reduction %d:", s + 1);
109 for (int t = 0; t < BLOCK; ++t) std::printf(" %d", rank[s * BLOCK + t]);
110 std::printf("\n");
111 }
112 std::printf(" hook fired at segments:");
113 for (int s : segmentsSeen) std::printf(" %d", s);
114 std::printf("\n\n");
simSetStepHook (test_debug.cu:93)
83#else
84 true;
85#endif
86
87 // The hook: break at the 2nd reduction (segment 2), print the block/segment,
88 // and reorder the threads for that reduction only.
89 const std::vector<int> custom = {3, 0, 1, 2, 7, 4, 5, 6};
90 std::vector<int> segmentsSeen;
91
92 simSetThreadOrder(OrderThread::sequential()); // default order for all segments
93 simSetStepHook([&](SimDebug& d) {
94 segmentsSeen.push_back(d.segment());
95 if (d.segment() == 2) {
96 std::printf(" [hook] break at block %u, segment %d (2nd reduction): "
97 "reorder threads -> {3,0,1,2,7,4,5,6}\n", d.block(), d.segment());
98 d.setThreadOrder(custom);
99 }
100 });
101
102 std::vector<int> rank = run();
103 simClearStepHook();