如何在CUDA上应用结构的原子操作?
让结构定义如下:如何在CUDA上应用结构的原子操作?,cuda,Cuda,让结构定义如下: typedef struct S { float x; float y; } T; __device__ T struct_add(T a1, T a2) { T result; result.x = a1.x + a2.x; result.y = a1.y + a2.y; } 操作struct\u add定义如下: typedef struct S { float x; float y; } T; __devi
typedef struct S {
float x;
float y;
} T;
__device__ T struct_add(T a1, T a2) {
T result;
result.x = a1.x + a2.x;
result.y = a1.y + a2.y;
}
操作struct\u add
定义如下:
typedef struct S {
float x;
float y;
} T;
__device__ T struct_add(T a1, T a2) {
T result;
result.x = a1.x + a2.x;
result.y = a1.y + a2.y;
}
如果我想以原子方式应用struct\u add
,如何在CUDA中实现这一点?例如,a
、b
和c
需要使用struct\u add
进行汇总,结果需要存储在d
中。(其中a
、b
、c
和d
的类型为T)
我听说不建议通过while循环进行“锁定和访问控制”。有没有合适的方法来实现这一点?CUDA没有提供涵盖任意结构原子更新的通用原子方法。一些可能性:
$ cat t56.cu
#include <stdio.h>
#define DSIZE 512
#define nTPB 256
#define cudaCheckErrors(msg) \
do { \
cudaError_t __err = cudaGetLastError(); \
if (__err != cudaSuccess) { \
fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
msg, cudaGetErrorString(__err), \
__FILE__, __LINE__); \
fprintf(stderr, "*** FAILED - ABORTING\n"); \
exit(1); \
} \
} while (0)
typedef union {
float floats[2];
unsigned long long int ulong; // for atomic update
} my_atomics;
__device__ my_atomics test;
__device__ unsigned long long int my_atomicAdd_2floats(unsigned long long int* address, float val0, float val1)
{
my_atomics loctest;
unsigned long long old = *address;
do {
loctest.ulong = old;
my_atomics loc;
loc.floats[0] = val0 + loctest.floats[0];
loc.floats[1] = val1 + loctest.floats[1];
old = atomicCAS(address, loctest.ulong, loc.ulong);}
while (old != loctest.ulong);
return old;
}
__global__ void min_test(const float* data)
{
int idx = (blockDim.x * blockIdx.x) + threadIdx.x;
if (idx < DSIZE)
my_atomicAdd_2floats(&(test.ulong), data[idx], (float)idx);
}
int main() {
float *d_data, *h_data;
my_atomics my_init;
my_init.floats[0] = 0.0f;
my_init.floats[1] = 0.0f;
h_data = (float *)malloc(DSIZE * sizeof(float));
if (h_data == 0) {printf("malloc fail\n"); return 1;}
cudaMalloc((void **)&d_data, DSIZE * sizeof(float));
cudaCheckErrors("cm1 fail");
for (int i = 0; i < DSIZE; i++) h_data[i] = 1.0f;
cudaMemcpy(d_data, h_data, DSIZE*sizeof(float), cudaMemcpyHostToDevice);
cudaCheckErrors("cmcp1 fail");
cudaMemcpyToSymbol(test, &(my_init.ulong), sizeof(unsigned long long int));
cudaCheckErrors("cmcp2 fail");
min_test<<<(DSIZE+nTPB-1)/nTPB, nTPB>>>(d_data);
cudaDeviceSynchronize();
cudaCheckErrors("kernel fail");
cudaMemcpyFromSymbol(&(my_init.ulong), test, sizeof(unsigned long long int));
cudaCheckErrors("cmcp3 fail");
printf("device float0 result = %f\n", my_init.floats[0]);
printf("device float1 result = %f\n", my_init.floats[1]);
float host_val0 = 0.0f;
float host_val1 = 0.0f;
for (int i=0; i<DSIZE; i++) {
host_val0 += h_data[i];
host_val1 += (float)(i);}
printf("host float0 result = %f\n", host_val0);
printf("host float1 result = %f\n", host_val1);
return 0;
}
$ nvcc -arch=sm_35 -o t56 t56.cu -Wno-deprecated-gpu-targets
$ cuda-memcheck ./t56
========= CUDA-MEMCHECK
device float0 result = 512.000000
device float1 result = 130816.000000
host float0 result = 512.000000
host float1 result = 130816.000000
========= ERROR SUMMARY: 0 errors
$
$cat t56.cu
#包括
#定义DSIZE512
#定义nTPB 256
#定义cudaCheckErrors(msg)\
做{\
cudaError\u t\u err=cudaGetLastError()\
如果(_err!=cudaSuccess){\
fprintf(标准,“致命错误:%s(%s位于%s:%d)\n”\
msg,cudaGetErrorString(_err)\
__文件(行)\
fprintf(stderr,“***失败-中止\n”)\
出口(1)\
} \
}而(0)
typedef联合{
浮动浮动[2];
unsigned long long int ulong;//用于原子更新
}我的原子学;
__设备原子测试;
__设备\uuuuu无符号长整型my_u原子添加\u2浮点(无符号长整型*地址,浮点值0,浮点值1)
{
我的原子学测试;
无符号long old=*地址;
做{
loctest.ulong=旧的;
我的原子学;
loc.floats[0]=val0+loctest.floats[0];
loc.floats[1]=val1+loctest.floats[1];
old=atomicCAS(地址,loctest.ulong,loc.ulong);}
while(old!=loctest.ulong);
返老还童;
}
__全局无效最小值测试(常数浮点*数据)
{
intidx=(blockDim.x*blockIdx.x)+threadIdx.x;
if(idx 对于(int i=0;i如果结构中有浮点数[4],该如何扩展?它不能,因为4个浮点数总共是128位,CUDA硬件原子机制目前停止在64位。对于更大的结构更新,您可能需要考虑另外两个建议之一:并行缩减方案(可能最好)或者是一个关键部分。或者重新构建您的算法,使其不需要同时进行4次原子更新。如果您正在执行atomicAdd
,我不清楚您为什么需要一个“耦合”原子操作,如本文所讨论的。在我看来,您的浮动[4]
case,您只需执行4个单独的float
atomicAdd
操作。