#include <stdio.h>
#include <cuda_runtime.h>
#define CUDA_CHECK(call) do { cudaError_t e = call; if(e != cudaSuccess) { \
fprintf(stderr, "CUDA Error: %s\n", cudaGetErrorString(e)); exit(1); } } while(0)
__global__ void reduce_naive(const float* input, float* output, int n) {
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (threadIdx.x == 0) {
float sum = 0.0f;
for (int i = blockIdx.x * blockDim.x;
i < min((int)(blockIdx.x * blockDim.x + blockDim.x), n);
i++) {
sum += input[i];
}
output[blockIdx.x] = sum;
}
}
__global__ void reduce_shared(const float* input, float* output, int n) {
extern __shared__ float sdata[];
int tid = threadIdx.x;
int i = blockIdx.x * blockDim.x + threadIdx.x;
sdata[tid] = (i < n) ? input[i] : 0.0f;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (tid < s) {
sdata[tid] += sdata[tid + s];
}
__syncthreads();
}
if (tid == 0) {
output[blockIdx.x] = sdata[0];
}
}
__device__ float warp_reduce_sum(float val) {
for (int offset = 16; offset > 0; offset >>= 1) {
val += __shfl_down_sync(0xFFFFFFFF, val, offset);
}
return val;
}
__global__ void reduce_warp_shuffle(const float* input, float* output, int n) {
extern __shared__ float sdata[];
int tid = threadIdx.x;
int i = blockIdx.x * blockDim.x + threadIdx.x;
float val = (i < n) ? input[i] : 0.0f;
int warp_id = tid / 32;
int lane_id = tid % 32;
val = warp_reduce_sum(val);
if (lane_id == 0) {
sdata[warp_id] = val;
}
__syncthreads();
if (warp_id == 0) {
val = (tid < blockDim.x / 32) ? sdata[tid] : 0.0f;
val = warp_reduce_sum(val);
}
if (tid == 0) {
output[blockIdx.x] = val;
}
}
int main() {
const int N = 1 << 20;
const int block_size = 256;
const int grid_size = (N + block_size - 1) / block_size;
float *h_input = (float*)malloc(N * sizeof(float));
float *h_output = (float*)malloc(grid_size * sizeof(float));
for (int i = 0; i < N; i++) h_input[i] = 1.0f;
float *d_input, *d_output;
CUDA_CHECK(cudaMalloc(&d_input, N * sizeof(float)));
CUDA_CHECK(cudaMalloc(&d_output, grid_size * sizeof(float)));
CUDA_CHECK(cudaMemcpy(d_input, h_input, N * sizeof(float), cudaMemcpyHostToDevice));
printf("向量归约求和: N = %d\n", N);
reduce_shared<<<grid_size, block_size, block_size * sizeof(float)>>>(
d_input, d_output, N);
CUDA_CHECK(cudaDeviceSynchronize());
CUDA_CHECK(cudaMemcpy(h_output, d_output, grid_size * sizeof(float), cudaMemcpyDeviceToHost));
float sum = 0;
for (int i = 0; i < grid_size; i++) sum += h_output[i];
printf("Shared Memory Result: %.0f (expected %d)\n", sum, N);
cudaFree(d_input); cudaFree(d_output);
free(h_input); free(h_output);
return 0;
}