| 548 | |
| 549 | template <int32_t THREADS_PER_CTA> |
| 550 | static inline __device__ void parallelSums_8x4(float* smem, float (&x)[4], int32_t nhw) |
| 551 | { |
| 552 | // The size of a warp. |
| 553 | int32_t const THREADS_PER_WARP = 32; |
| 554 | // The number of warps in a CTA. |
| 555 | int32_t const WARPS_PER_CTA = THREADS_PER_CTA / THREADS_PER_WARP; |
| 556 | // The number of threads per pixel. |
| 557 | int32_t const THREADS_PER_PIXEL = 8; |
| 558 | // The number of elements per ldg. |
| 559 | int32_t const ELEMENTS_PER_LDG = 4; |
| 560 | // The warp decomposition. |
| 561 | int32_t const warp_id = threadIdx.x / THREADS_PER_WARP; |
| 562 | int32_t const lane_id = threadIdx.x % THREADS_PER_WARP; |
| 563 | |
| 564 | #pragma unroll |
| 565 | for (int32_t i = 0; i < ELEMENTS_PER_LDG; ++i) |
| 566 | { |
| 567 | x[i] += __shfl_sync(0xffffffffU, x[i], THREADS_PER_PIXEL + lane_id); |
| 568 | x[i] += __shfl_sync(0xffffffffU, x[i], THREADS_PER_PIXEL * 2 + lane_id); |
| 569 | } |
| 570 | |
| 571 | // The warp leaders, write to SMEM. |
| 572 | if (lane_id < THREADS_PER_PIXEL) |
| 573 | { |
| 574 | writeToSmem(smem, warp_id * THREADS_PER_PIXEL + lane_id, x); |
| 575 | } |
| 576 | |
| 577 | // The data is in SMEM. Do the final reduction. |
| 578 | __syncthreads(); |
| 579 | |
| 580 | // The 1st warp does all the work. |
| 581 | // We do the final reduction each half-warp sequentially reduces the final values. |
| 582 | if (warp_id == 0) |
| 583 | { |
| 584 | readFromSmem(x, smem, threadIdx.x); |
| 585 | |
| 586 | #pragma unroll |
| 587 | for (int32_t offset = 1; offset < WARPS_PER_CTA / (THREADS_PER_WARP / THREADS_PER_PIXEL); ++offset) |
| 588 | { |
| 589 | float y[ELEMENTS_PER_LDG]; |
| 590 | // Read the mean and variance from the other pixel. |
| 591 | readFromSmem(y, smem, threadIdx.x + offset * THREADS_PER_WARP); |
| 592 | // Compute the updated sum. |
| 593 | add(x, y); |
| 594 | } |
| 595 | |
| 596 | for (int32_t i = 0; i < ELEMENTS_PER_LDG; ++i) |
| 597 | { |
| 598 | x[i] += __shfl_sync(0xffffffffU, x[i], THREADS_PER_PIXEL + lane_id); |
| 599 | x[i] += __shfl_sync(0xffffffffU, x[i], THREADS_PER_PIXEL * 2 + lane_id); |
| 600 | } |
| 601 | |
| 602 | // Make sure the data was read from SMEM. |
| 603 | __syncwarp(); |
| 604 | |
| 605 | // Store the final values. |
| 606 | if (threadIdx.x < THREADS_PER_PIXEL) |
| 607 | { |
nothing calls this directly
no test coverage detected