| 213 | // executed in the kernel |
| 214 | template<typename T> |
| 215 | inline dim3 threadsMgt<T>::genBlocks(const dim3& threads, |
| 216 | const unsigned nrInputs, |
| 217 | const unsigned nrOutputs, |
| 218 | const size_t totalSize, |
| 219 | const size_t sizeofT) { |
| 220 | // The bottleneck of anykernel is dependent on the type of memory |
| 221 | // used. |
| 222 | // a) For very small arrays (elements < maxParallelThreads), each |
| 223 | // element receives it individual thread. |
| 224 | // b) For arrays (in+out) smaller than 3/2 L2cache, memory access no |
| 225 | // longer is the bottleneck, because enough L2cache is available at any |
| 226 | // time. Threads are limited to reduce scheduling overhead. |
| 227 | // c) For very large arrays and type sizes (<long double), 1 thread will |
| 228 | // not generate enough data to keep the memory sync mechanism |
| 229 | // saturated, so we start loooping inside each thread. |
| 230 | dim3 blocks{1}; |
| 231 | const int activeDeviceId{getActiveDeviceId()}; |
| 232 | const unsigned* maxGridSize{ |
| 233 | reinterpret_cast<const unsigned*>(getMaxGridSize(activeDeviceId))}; |
| 234 | const size_t L2CacheSize{getL2CacheSize(activeDeviceId)}; |
| 235 | const unsigned cacheLine{getMemoryBusWidth(activeDeviceId)}; |
| 236 | const unsigned multiProcessorCount{getMultiProcessorCount(activeDeviceId)}; |
| 237 | const unsigned maxThreads{maxParallelThreads * |
| 238 | (sizeofT * nrInputs * nrInputs > 8 ? 1 : 2)}; |
| 239 | |
| 240 | if (ndims == 1) { |
| 241 | if (d0 > maxThreads) { |
| 242 | if (totalSize * 2 > L2CacheSize * 3) { |
| 243 | // General formula to calculate best #loops |
| 244 | // Dedicated GPUs: |
| 245 | // 32/sizeof(T)**2/#outBuffers*(3/4)**(#inBuffers-1) |
| 246 | // Integrated GPUs: |
| 247 | // 4/sizeof(T)/#outBuffers*(3/4)**(#inBuffers-1) |
| 248 | unsigned largeVolDivider{cacheLine == 64 |
| 249 | ? sizeofT == 1 ? 4 |
| 250 | : sizeofT == 2 ? 2 |
| 251 | : 1 |
| 252 | : (sizeofT == 1 ? 32 |
| 253 | : sizeofT == 2 ? 8 |
| 254 | : 1) / |
| 255 | nrOutputs}; |
| 256 | for (unsigned i{1}; i < nrInputs; ++i) |
| 257 | largeVolDivider = largeVolDivider * 3 / 4; |
| 258 | if (largeVolDivider > 1) { |
| 259 | blocks.x = d0 / (largeVolDivider * threads.x); |
| 260 | if (blocks.x == 0) blocks.x = 1; |
| 261 | loop0 = true; |
| 262 | } |
| 263 | } else { |
| 264 | // A reduction to (1|2*)maxParallelThreads will be |
| 265 | // performed |
| 266 | blocks.x = maxThreads / threads.x; |
| 267 | if (blocks.x == 0) blocks.x = 1; |
| 268 | loop0 = true; |
| 269 | } |
| 270 | } |
| 271 | if (!loop0) { blocks.x = divup(d0, threads.x); } |
| 272 | } else { |
no test coverage detected