在CUDA(C ++)中检查inf
/ nan
元素的大矩阵的有效方法是什么?矩阵作为float*
存储在GPU存储器中。我不需要这些元素的位置,如果存在至少一个错误条目,则只需要布尔值是/否答案。
选项包括:
谢谢!
答案 0 :(得分:4)
这有一些内容,但C99的可用功能应该没问题:
isnan()
要测试inf,您可以使用:
isinf()
让多个内核执行单个编写良好的内核的相同工作的速度很快,所以我不确定为什么你认为单个内核会很慢。该算法可能受内存限制,因此您希望专注于读取数据访问效率,即合并。在CUDA中,通过矩阵的简单方法是让每个线程处理一列。这可以通过for循环有效地实现,并产生完美的合并读取。
由于你只关心没有索引的单个结果,我们可以让多个线程写入(布尔)结果而不用原子,以提高效率,因为任何线程都可能写入结果都会写出相同的值。
人们可能会考虑的另一种优化策略是早期退出策略,但这不会优化最坏情况的时间,但实际上会延长时间,所以除非平均吞吐量是一个大问题,否则我会放弃它。 / p>
这是一个完整的工作示例(以nan为例):
$ cat t383.cu
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define DSIZEW 10000
#define DSIZEH 2000
#define nTPB 256
#define BLKS 16
__global__ void isnan_test(float *data, int width, int height, bool *result){
int idx = threadIdx.x+blockDim.x*blockIdx.x;
while (idx < width){
for (int i = 0; i < height; i++)
if (isnan(data[(i*width) + idx])) *result = false;
idx += gridDim.x+blockDim.x;
}
}
int main(){
float *d_data, *h_data;
bool *d_result, h_result=true;
const char type = '0';
cudaMalloc((void **)&d_data, sizeof(float)*DSIZEW*DSIZEH);
cudaMalloc((void **)&d_result, sizeof (bool));
h_data=(float *)malloc(sizeof(float)*DSIZEW*DSIZEH);
for (int i=0; i<DSIZEH*DSIZEW; i++)
h_data[i] = rand()/RAND_MAX;
cudaMemcpy(d_data, h_data, sizeof(float)*DSIZEW*DSIZEH, cudaMemcpyHostToDevice);
cudaMemcpy(d_result, &h_result, sizeof(bool), cudaMemcpyHostToDevice);
isnan_test<<<BLKS,nTPB>>>(d_data, DSIZEW, DSIZEH, d_result);
cudaMemcpy(&h_result, d_result, sizeof(bool), cudaMemcpyDeviceToHost);
if (!h_result) {printf("error in no-NAN check\n"); return 1;}
float my_nan = nanf(&type); // create a NAN value
cudaMemcpy(d_data, &my_nan, sizeof(float), cudaMemcpyHostToDevice);
isnan_test<<<BLKS,nTPB>>>(d_data, DSIZEW, DSIZEH, d_result);
cudaMemcpy(&h_result, d_result, sizeof(bool), cudaMemcpyDeviceToHost);
if (h_result) {printf("error in NAN check\n"); return 1;}
printf("Success\n");
return 0;
}
$ nvcc -arch=sm_20 -o t383 t383.cu
$ ./t383
Success
$
请注意,为了清晰/简洁,我已放弃proper cuda error checking,但始终建议这样做。
为了进一步优化,您可以使用每个网格块参数(BLKS
)和每个块的线程参数(nTPB
),但是,在某种程度上,这些参数的最佳值将取决于你正在运行哪个GPU。
答案 1 :(得分:2)
您的问题可以重新制作为减少操作。这可以通过 CUDA Thrust 有效实现。您可以使用CUDA的isnan
或isinf
将原始数组转换为布尔数组,然后缩小转换后的数组。所有这些都可以通过展示 thrust::transform_reduce
来执行。
下面是一个示例,围绕Robert Crovella已经呈现给您的示例构建。下面的代码在CUDA中实现了相当于 Matlab&#39; sum(isnan(array))
。
#include <thrust\device_vector.h>
#include <thrust\reduce.h>
#define DSIZEW 10000
#define DSIZEH 2000
// --- Operator for testing nan values
struct isnan_test {
__host__ __device__ bool operator()(const float a) const {
return isnan(a);
}
};
void main(){
thrust::host_vector<float> h_data(DSIZEW*DSIZEH);
for (int i=0; i<DSIZEH*DSIZEW; i++)
h_data[i] = rand()/RAND_MAX;
const char type = '0';
float my_nan = nanf(&type); // create a NAN value
h_data[0] = my_nan;
thrust::device_vector<float> d_data(h_data);
bool h_result = thrust::transform_reduce(d_data.begin(), d_data.end(), isnan_test(), 0, thrust::plus<bool>());
printf("Result = %d\n",h_result);
getchar();
}