Cooperative launch#
A cooperative launch guarantees every block is resident at once, which is what makes this_grid().sync() a legal grid-wide barrier. The sim honours that by giving EVERY thread of EVERY block its own fiber up front, then running in “phases”: each phase visits the blocks in a random order and runs each one until all of its threads have reached the grid barrier (or exited); when the whole grid has arrived, every thread is released and the next phase starts.
CAVEAT (documented, not fixed): __shared__ is static in the sim, so a block’s static shared memory is one buffer reused by every block. Between two grid barriers that is still correct — a block runs to completion of the phase before the next one starts — but shared data does NOT survive a grid.sync(). Kernels that coordinate across a grid barrier do so through global memory, which is modelled exactly.
Defined in code/simulator.h.
This page documents 7 symbols: 2 macros, 5 functions.
Macros#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
Portable spelling for a cooperative launch (the counterpart of LAUNCH): LAUNCH_COOP(kernel, grid, block, args…) becomes cudaLaunchCooperativeKernel under nvcc and the co-resident scheduler above … |
sim + nvcc |
simulator.h:1886 |
|
|
Expands to |
sim + nvcc |
simulator.h:1888 |
Functions#
Signature |
Description |
Availability |
Location |
Example |
|---|---|---|---|---|
|
sim only |
simulator.h:1871 |
||
|
CAVEAT (documented, not fixed): __shared__ is |
sim only |
simulator.h:1718 |
|
|
sim only |
simulator.h:1876 |
||
|
sim only |
simulator.h:1758 |
||
|
sim only |
simulator.h:1748 |
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.
LAUNCH_COOP (test_web_olcf_hw9_task2.cu:137)
127 std::printf("cooperative grid: %d blocks of %d threads\n", nBlocks, nTPB);
128
129 bool ok = true;
130
131 // Test 1: nothing is removed.
132 for (int i = 0; i < test_dsize; i++) h_data[i] = i;
133 cudaMemcpy(d_idata, h_data.data(), tsize, cudaMemcpyHostToDevice);
134 mytype remove_val = -1;
135 unsigned ds = test_dsize;
136 const mytype* c_idata = d_idata;
137 LAUNCH_COOP(my_remove_if<mytype>, grid, block, c_idata, remove_val, d_odata, d_idxs, ds);
138 cudaDeviceSynchronize();
139 cudaMemcpy(h_data.data(), d_odata, tsize, cudaMemcpyDeviceToHost);
140 for (int i = 0; i < test_dsize; i++)
141 if (h_data[i] != i) {
142 std::printf("mismatch 1 at %d, was: %d, should be: %d\n", i, h_data[i], i);
143 ok = false; break;
144 }
145
146 // Test 2: remove the -1 entries.
147 std::vector<mytype> h_in(test_dsize);
148 int val = 0;
LAUNCH_DYN_COOP (test_web_cs_awbarrier.cu:191)
181 int smemSize = ((blockSize / 32) + 1) * (int)sizeof(double);
182 check(cudaMalloc(reinterpret_cast<void**>(&d_partialResults), numBlocks * sizeof(double)),
183 "cudaMalloc partialResults");
184 check(cudaStreamSynchronize(stream), "cudaStreamSynchronize (H2D)");
185
186 std::printf("Launching normVecByDotProductAWBarrier kernel with numBlocks = %d blockSize = %d\n",
187 numBlocks, blockSize);
188
189 dim3 dimGrid(numBlocks, 1, 1), dimBlock(blockSize, 1, 1);
190 int kSize = size;
191 LAUNCH_DYN_COOP(normVecByDotProductAWBarrier, dimGrid, dimBlock, (size_t)smemSize,
192 d_vecA, d_vecB, d_partialResults, kSize);
193 check(cudaDeviceSynchronize(), "cudaDeviceSynchronize");
194
195 check(cudaMemcpy(vecA, d_vecA, sizeof(float) * size, cudaMemcpyDeviceToHost), "D2H A");
196
197 const float expectedResult = (float)(baseVal / std::sqrt((double)size * baseVal * baseVal));
198 unsigned int matches = 0;
199 double maxErr = 0.0;
200 for (int i = 0; i < size; i++) {
201 maxErr = std::max(maxErr, std::fabs((double)vecA[i] - expectedResult));
202 if ((vecA[i] - expectedResult) > 0.00001) {