Cuda 如何实现包含多个变量的自定义原子函数?
我想在CUDA中实现这个原子函数:Cuda 如何实现包含多个变量的自定义原子函数?,cuda,atomic,gpu-atomics,ptxas,Cuda,Atomic,Gpu Atomics,Ptxas,我想在CUDA中实现这个原子函数: __device__ float lowest; // global var __device__ int lowIdx; // global var float realNum; // thread reg var int index; // thread reg var if(realNum < lowest) { lowest= realNum; // the new lowest lowIdx= index;
__device__ float lowest; // global var
__device__ int lowIdx; // global var
float realNum; // thread reg var
int index; // thread reg var
if(realNum < lowest) {
lowest= realNum; // the new lowest
lowIdx= index; // update the 'low' index
}
\uuuuuu设备\uuuuuuuuuuuuu浮动最低;//全局变量
__设备_u; int lowIdx;//全局变量
浮点realNum;//线程注册变量
整数索引;//线程注册变量
if(realNum<最低值){
loost=realNum;//新的最低值
lowIdx=index;//更新“low”索引
}
我不相信我能用任何原子函数做到这一点。我需要锁定几个全局内存loc,以获取几个指令。
我是否可以用PTXAS(汇编)代码实现这一点?正如我在上面的第二条评论中所述,可以将两个32位的数量组合成一个64位的原子管理数量,并以这种方式处理问题。然后,我们将使用作为粗略指南,以原子方式管理64位数量。显然,你不能把这个概念扩展到两个32位的量之外。下面是一个例子:
#include <stdio.h>
#define DSIZE 5000
#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]; // floats[0] = lowest
int ints[2]; // ints[1] = lowIdx
unsigned long long int ulong; // for atomic update
} my_atomics;
__device__ my_atomics test;
__device__ unsigned long long int my_atomicMin(unsigned long long int* address, float val1, int val2)
{
my_atomics loc, loctest;
loc.floats[0] = val1;
loc.ints[1] = val2;
loctest.ulong = *address;
while (loctest.floats[0] > val1)
loctest.ulong = atomicCAS(address, loctest.ulong, loc.ulong);
return loctest.ulong;
}
__global__ void min_test(const float* data)
{
int idx = (blockDim.x * blockIdx.x) + threadIdx.x;
if (idx < DSIZE)
my_atomicMin(&(test.ulong), data[idx],idx);
}
int main() {
float *d_data, *h_data;
my_atomics my_init;
my_init.floats[0] = 10.0f;
my_init.ints[1] = DSIZE;
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");
// create random floats between 0 and 1
for (int i = 0; i < DSIZE; i++) h_data[i] = rand()/(float)RAND_MAX;
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 min result = %f\n", my_init.floats[0]);
printf("device idx result = %d\n", my_init.ints[1]);
float host_val = 10.0f;
int host_idx = DSIZE;
for (int i=0; i<DSIZE; i++)
if (h_data[i] < host_val){
host_val = h_data[i];
host_idx = i;
}
printf("host min result = %f\n", host_val);
printf("host idx result = %d\n", host_idx);
return 0;
}
#包括
#定义DSIZE 5000
#定义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];//浮动[0]=最低
int ints[2];//ints[1]=lowIdx
unsigned long long int ulong;//用于原子更新
}我的原子学;
__设备原子测试;
__设备uuu无符号长整型my_atomicMin(无符号长整型*地址,浮点值1,整数值2)
{
my_atomics loc,loctest;
位置浮动[0]=值1;
loc.ints[1]=val2;
loctest.ulong=*地址;
while(loctest.floats[0]>val1)
loctest.ulong=atomicCAS(地址:loctest.ulong,loc.ulong);
返回loctest.ulong;
}
__全局无效最小值测试(常数浮点*数据)
{
intidx=(blockDim.x*blockIdx.x)+threadIdx.x;
if(idx 对于(int i=0;i@Robert Crovella:好主意,但我认为函数应该修改一点,如下所示:
__device__ unsigned long long int my_atomicMin(unsigned long long int* address, float val1, int val2)
{
my_atomics loc, loctest, old;
loc.floats[0] = val1;
loc.ints[1] = val2;
loctest.ulong = *address;
old.ulong = loctest.ulong;
while (loctest.floats[0] > val1){
old.ulong = loctest.ulong;
loctest.ulong = atomicCAS(address, loctest.ulong, loc.ulong);
}
return old.ulong;
}
我不认为有一种方法(PTX或其他)可以使用任何特定的GPU硬件一次自动更新多个位置。其他人可能有一个聪明的想法。通常我认为这类问题可以使用“关键部分”方法解决,您可能希望使用右上角的搜索框进行搜索“cuda临界段"看看这些问题中描述了什么。看起来您可能希望在每个线程的基础上运行它,并且每个线程的关键部分管理可能非常危险/困难。实际上,在这种有限的情况下,您只有两个32位的数量,您正试图管理,因此可以创建一个自定义原子函数,可能是围绕原子库构建的,利用64位量(通过巧妙地组合两个32位量),可能与文档中给出的内容一致。我不确定原因。我们似乎只在函数的返回值上存在分歧。在您的情况下,返回值模式与所建立的模式不匹配,后者返回从atomicCAS
函数返回的最新值(假设输入了while循环)。您的品种不会这样做。