编程模型和语言层
实现一个MUSA环境中运行的并行累加操作的示例。这段代码展示了在 GPU 上进行大规模数据计算的并行处理能力,利用了线程块、warp 内同步和原子操作等技术,适用于需要高效执行的累加操作等场景。
- 核函数(
sum
)- 该核函数通过线程块(block)和线程(thread)并行处理数组的部分元素,执行累加操作。
- 使用 warp 内部的规约操作加快累加速度,并通过原子加法确保不同线程的结果正确写入共享的输出变量。
- 主程序
- 在主函数中,首先定义了数组的大小、线程块和网格的配置。
- 使用
float
作为数据类型和long
作为索引类型(类型模板支持灵活替换其他数据类型)。 - 主机端分配和初始化输入数组
h_a
,并将其复制到设备端d_a
,然后为结果变量h_b
分配内存。 - 核函数在 GPU 上并行启动,计算完成后将结果从设备端复制回主机并打印。
- 并行计算
- 并行累加:多个线程块并行处理数组中的不同部分,每个线程累加自己负责的元素。
- warp 规约:在同一 warp 内使用
__shfl_down_sync
操作进行规约加速。 - 原子加法:使用
atomicAdd
确保多个线程同时更新输出变量时不产生冲突。
示例代码:
#include "musa_runtime.h"
__global__ void VectorAdd(int* a, int* b) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
a[idx] = a[idx] + b[idx];
}
int main() {
const size_t numElements = 4096;
const size_t sizeBytes = numElements * sizeof(int);
musaStream_t stream;
musaStreamCreate(&stream);
int *hA = nullptr, *hB = nullptr;
int *dA = nullptr, *dB = nullptr;
hA = reinterpret_cast<int*>(malloc(sizeBytes));
hB = reinterpret_cast<int*>(malloc(sizeBytes));
musaMalloc(&dA, sizeBytes);
musaMalloc(&dB, sizeBytes);
for (int i = 0; i < numElements; ++i) {
hA[i] = i;
hB[i] = 2 * i;
}
musaMemcpy(dA, hA, sizeBytes, musaMemcpyHostToDevice);
musaMemcpy(dB, hB, sizeBytes, musaMemcpyHostToDevice);
int threadsPerBlock = 1024;
int blocksPerGrid = (numElements + threadsPerBlock - 1) / threadsPerBlock;
VectorAdd<<<blocksPerGrid, threadsPerBlock>>>(dA, dB);
musaError_t err = musaGetLastError();
musaMemcpy(hA, dA, sizeBytes, musaMemcpyDeviceToHost);
musaStreamDestroy(stream);
free(hA);
free(hB);
musaFree(dA);
musaFree(dB);
return 0;
}
结果输出:
Sum result: 1e+06