Manual block / thread execution order (for reproducible debugging)#

By default blocks and threads run in a RANDOM order (see the header overview) — great for finding order-dependent bugs, but you can’t replay one. Set an explicit order to pin the exact interleaving: simSetThreadOrder(OrderThread{3, 0, 1, 2}); // this permutation, every barrier simSetBlockOrder(OrderBlock::sequential()); // 0,1,2,… (count-agnostic) simResetOrder(); // back to random default The setting is global and persists across launches until changed. OrderBlock and OrderThread are distinct types so the two can’t be swapped by mistake.

Defined in code/simulator.h.

This page documents 20 symbols: 2 classes, 6 constructors, 12 functions.

Classes#

Signature

Description

Availability

Location

Example

class OrderBlock : public simdetail::VisitOrder

By default blocks and threads run in a RANDOM order (see the header overview) — great for finding order-dependent bugs, but you can’t replay one.

sim + nvcc

simulator.h:639

View

class OrderThread : public simdetail::VisitOrder

sim + nvcc

simulator.h:650

View

Constructors#

Signature

Description

Availability

Location

Example

OrderBlock() = default

sim + nvcc

simulator.h:641

View

OrderBlock(std::initializer_list<int> perm) : simdetail::VisitOrder(perm)

sim + nvcc

simulator.h:642

View

OrderBlock(std::vector<int> perm) : simdetail::VisitOrder(std::move(perm))

sim + nvcc

simulator.h:643

View

OrderThread() = default

sim + nvcc

simulator.h:652

View

OrderThread(std::initializer_list<int> perm) : simdetail::VisitOrder(perm)

sim + nvcc

simulator.h:653

View

OrderThread(std::vector<int> perm) : simdetail::VisitOrder(std::move(perm))

sim + nvcc

simulator.h:654

View

Functions#

Signature

Description

Availability

Location

Example

explicit OrderBlock(Mode m) : simdetail::VisitOrder(m)

sim + nvcc

simulator.h:648

View

explicit OrderThread(Mode m) : simdetail::VisitOrder(m)

sim + nvcc

simulator.h:659

View

static OrderBlock random()

sim + nvcc

simulator.h:644

View

static OrderThread random()

sim + nvcc

simulator.h:655

View

static OrderBlock reverse()

sim + nvcc

simulator.h:646

View

static OrderThread reverse()

sim + nvcc

simulator.h:657

View

static OrderBlock sequential()

sim + nvcc

simulator.h:645

View

static OrderThread sequential()

sim + nvcc

simulator.h:656

View

inline void simResetOrder()

sim + nvcc

simulator.h:673

View

inline void simSetBlockOrder(const OrderBlock& o)

Runtime setters — call before a LAUNCH (or between launches) to pin ordering.

sim + nvcc

simulator.h:668

View

inline void simSetOrder(const OrderBlock& b, const OrderThread& t)

sim + nvcc

simulator.h:670

inline void simSetThreadOrder(const OrderThread& o)

sim + nvcc

simulator.h:669

View

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.

OrderBlock (test_order.cu:153)
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
149        all &= report("block order: reverse", ok);
150    }
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
157    }
158
159    // ---- Reset restores the random default -----------------------------------
160    {
161        simResetOrder();
162        std::vector<int> t = runThreads(BLOCK);
163        std::vector<int> b = runBlocks(GRID);
164        all &= report("reset -> random default (valid perms)",
OrderThread (test_order.cu:124)
114    // ---- Thread order --------------------------------------------------------
115    {
116        simSetThreadOrder(OrderThread::sequential());
117        std::vector<int> out = runThreads(BLOCK);
118        std::vector<int> seq(BLOCK); for (int i = 0; i < BLOCK; ++i) seq[i] = i;
119        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, seq));
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
OrderBlock (test_order.cu:153)
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
149        all &= report("block order: reverse", ok);
150    }
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
157    }
158
159    // ---- Reset restores the random default -----------------------------------
160    {
161        simResetOrder();
162        std::vector<int> t = runThreads(BLOCK);
163        std::vector<int> b = runBlocks(GRID);
164        all &= report("reset -> random default (valid perms)",
OrderBlock (test_order.cu:153)
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
149        all &= report("block order: reverse", ok);
150    }
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
157    }
158
159    // ---- Reset restores the random default -----------------------------------
160    {
161        simResetOrder();
162        std::vector<int> t = runThreads(BLOCK);
163        std::vector<int> b = runBlocks(GRID);
164        all &= report("reset -> random default (valid perms)",
OrderBlock (test_order.cu:153)
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
149        all &= report("block order: reverse", ok);
150    }
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
157    }
158
159    // ---- Reset restores the random default -----------------------------------
160    {
161        simResetOrder();
162        std::vector<int> t = runThreads(BLOCK);
163        std::vector<int> b = runBlocks(GRID);
164        all &= report("reset -> random default (valid perms)",
OrderThread (test_order.cu:124)
114    // ---- Thread order --------------------------------------------------------
115    {
116        simSetThreadOrder(OrderThread::sequential());
117        std::vector<int> out = runThreads(BLOCK);
118        std::vector<int> seq(BLOCK); for (int i = 0; i < BLOCK; ++i) seq[i] = i;
119        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, seq));
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
OrderThread (test_order.cu:124)
114    // ---- Thread order --------------------------------------------------------
115    {
116        simSetThreadOrder(OrderThread::sequential());
117        std::vector<int> out = runThreads(BLOCK);
118        std::vector<int> seq(BLOCK); for (int i = 0; i < BLOCK; ++i) seq[i] = i;
119        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, seq));
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
OrderThread (test_order.cu:124)
114    // ---- Thread order --------------------------------------------------------
115    {
116        simSetThreadOrder(OrderThread::sequential());
117        std::vector<int> out = runThreads(BLOCK);
118        std::vector<int> seq(BLOCK); for (int i = 0; i < BLOCK; ++i) seq[i] = i;
119        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, seq));
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
OrderBlock (test_order.cu:153)
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
149        all &= report("block order: reverse", ok);
150    }
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
157    }
158
159    // ---- Reset restores the random default -----------------------------------
160    {
161        simResetOrder();
162        std::vector<int> t = runThreads(BLOCK);
163        std::vector<int> b = runBlocks(GRID);
164        all &= report("reset -> random default (valid perms)",
OrderThread (test_order.cu:124)
114    // ---- Thread order --------------------------------------------------------
115    {
116        simSetThreadOrder(OrderThread::sequential());
117        std::vector<int> out = runThreads(BLOCK);
118        std::vector<int> seq(BLOCK); for (int i = 0; i < BLOCK; ++i) seq[i] = i;
119        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, seq));
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
random (test_order.cu:137)
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
136    {
137        simSetThreadOrder(OrderThread::random());
138        simSetSeed(7);
139        std::vector<int> out = runThreads(BLOCK);
140        all &= report("thread order: random is a permutation", isPermutation(out));
141    }
142
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
random (test_order.cu:137)
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
136    {
137        simSetThreadOrder(OrderThread::random());
138        simSetSeed(7);
139        std::vector<int> out = runThreads(BLOCK);
140        all &= report("thread order: random is a permutation", isPermutation(out));
141    }
142
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
reverse (test_order.cu:130)
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
136    {
137        simSetThreadOrder(OrderThread::random());
138        simSetSeed(7);
139        std::vector<int> out = runThreads(BLOCK);
140        all &= report("thread order: random is a permutation", isPermutation(out));
141    }
reverse (test_order.cu:130)
120        all &= report("thread order: sequential", ok);
121    }
122    {
123        std::vector<int> perm = {3, 0, 1, 2, 7, 4, 5, 6};   // explicit permutation
124        simSetThreadOrder(OrderThread(perm));
125        std::vector<int> out = runThreads(BLOCK);
126        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
127        all &= report("thread order: custom {3,0,1,2,7,4,5,6}", ok);
128    }
129    {
130        simSetThreadOrder(OrderThread::reverse());
131        std::vector<int> out = runThreads(BLOCK);
132        std::vector<int> rev(BLOCK); for (int i = 0; i < BLOCK; ++i) rev[i] = BLOCK - 1 - i;
133        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
134        all &= report("thread order: reverse", ok);
135    }
136    {
137        simSetThreadOrder(OrderThread::random());
138        simSetSeed(7);
139        std::vector<int> out = runThreads(BLOCK);
140        all &= report("thread order: random is a permutation", isPermutation(out));
141    }
sequential (test_debug.cu:92)
 82        false;
 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();
sequential (test_debug.cu:92)
 82        false;
 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();
simResetOrder (test_order.cu:161)
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
157    }
158
159    // ---- Reset restores the random default -----------------------------------
160    {
161        simResetOrder();
162        std::vector<int> t = runThreads(BLOCK);
163        std::vector<int> b = runBlocks(GRID);
164        all &= report("reset -> random default (valid perms)",
165                      isPermutation(t) && isPermutation(b));
166    }
167
168    // ---- Determinism: same pinned order twice -> identical visit order -------
169    {
170        simSetThreadOrder(OrderThread({2, 5, 1, 0, 7, 3, 6, 4}));
171        std::vector<int> a = runThreads(BLOCK);
172        std::vector<int> b = runThreads(BLOCK);
simSetBlockOrder (test_order.cu:145)
135    }
136    {
137        simSetThreadOrder(OrderThread::random());
138        simSetSeed(7);
139        std::vector<int> out = runThreads(BLOCK);
140        all &= report("thread order: random is a permutation", isPermutation(out));
141    }
142
143    // ---- Block order ---------------------------------------------------------
144    {
145        simSetBlockOrder(OrderBlock::reverse());
146        std::vector<int> out = runBlocks(GRID);
147        std::vector<int> rev(GRID); for (int i = 0; i < GRID; ++i) rev[i] = GRID - 1 - i;
148        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, rev));
149        all &= report("block order: reverse", ok);
150    }
151    {
152        std::vector<int> perm = {5, 2, 7, 0, 3, 6, 1, 4};
153        simSetBlockOrder(OrderBlock(perm));
154        std::vector<int> out = runBlocks(GRID);
155        bool ok = isPermutation(out) && (!onSim || matchesOrder(out, perm));
156        all &= report("block order: custom {5,2,7,0,3,6,1,4}", ok);
simSetThreadOrder (test_debug.cu:92)
 82        false;
 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();