我是 CUDA 的新手,正在努力掌握基础知识,所以如果我问或说的问题听起来过于简单,我深表歉意。我用 C 编写了一些串行代码,用于生成一个包含随机数的数组,然后找到该数组中的最大值。
#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#define num 100000
int *arr,max = -1;
int getRand() {
double r1=rand()/(double)RAND_MAX; // Generates value between 0 & 1
return (r1 * num) + 1;
}
void generateRandom(int M) {
int i;
for(i=0;i<M;i++) {
arr[i] = getRand();
}
}
void getMax(int M) {
int i;
for(i=0;i<M;i++) {
if(arr[i] > max)
max = arr[i];
}
}
int main(int argc, char *argv[] ){
if (argc == 2) {
int M;
/* initialize random seed: */
srand (time(NULL));
M = atoi(argv[1]);
//int arr[M];
arr = (int*)calloc(M,sizeof(int));;
//printf("M = %d MAX = %d\n", M, RAND_MAX);
generateRandom(M);
getMax(M);
printf("Max value: %d",max);
}
else
printf("Invalid arguments.");
return 0;
}
我现在正尝试将此代码转换为简单的 CUDA 程序。我尝试让 generateRandom 函数作为内核运行,但我遇到了内存管理问题。
#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <cuda.h>
#define num 100000
int *arr,max = -1;
int getRand() {
double r1=rand()/(double)RAND_MAX; // Generates value between 0 & 1
return (r1 * num) + 1;
}
void generateRandom(int M) {
int i;
for(i=0;i<M;i++) {
arr[i] = getRand();
}
}
__global__ void getMax(int M) {
int i;
for(i=0;i<M;i++) {
if(arr[i] > max)
max = arr[i];
}
}
int main(int argc, char *argv[] ){
if (argc == 2) {
int M;
/* initialize random seed: */
srand (time(NULL));
M = atoi(argv[1]);
//int arr[M];
arr = (int*)calloc(M,sizeof(int));
//printf("M = %d MAX = %d\n", M, RAND_MAX);
generateRandom(M);
getMax<<<1,1>>>(M);
printf("Max value: %d",max);
}
else
printf("Invalid arguments.");
return 0;
}
该代码导致以下错误。
cudabasic.cu(23): warning: a host variable "arr" cannot be directly read in >a device function
cudabasic.cu(23): warning: a host variable "max" cannot be directly read in >a device function
cudabasic.cu(24): warning: a host variable "arr" cannot be directly read in >a device function
cudabasic.cu(24): warning: a host variable "max" cannot be directly written >in a device function
我用谷歌搜索了这个错误,发现问题是我将全局变量传递给内核,因此设备无法读取它。根据在线建议,我尝试通过使用指针而不是传递实际变量来解决此问题,但我仍然遇到错误。
#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <cuda.h>
#define num 100000
int *arr,max = -1;
int getRand() {
double r1=rand()/(double)RAND_MAX; // Generates value between 0 & 1
return (r1 * num) + 1;
}
void generateRandom(int M) {
int i;
for(i=0;i<M;i++) {
arr[i] = getRand();
}
}
__global__ void getMax(int M, int *dArr, int *dMax) {
int i = threadIdx.x;
int a = dArr[i];
for(i=0;i<M;i++) {
if(a > dMax)
dMax = a;
}
}
int main(int argc, char *argv[] ){
if (argc == 2) {
int M;
/* initialize random seed: */
srand (time(NULL));
M = atoi(argv[1]);
//int arr[M];
arr = (int*)calloc(M,sizeof(int));
devArr = (int*)cudaMalloc(M,sizeof(int));
//printf("M = %d MAX = %d\n", M, RAND_MAX);
generateRandom(M);
getMax<<<1,1>>>(M, arr, max);
printf("Max value: %d",max);
}
else
printf("Invalid arguments.");
return 0;
}
cudabasic.cu(24): error: operand types are incompatible ("int" and "int *")
cudabasic.cu(25): error: a value of type "int" cannot be assigned to an >entity of type "int *"
有人可以指出正确的方向,告诉我如何最好地做到这一点吗?
我是 CUDA 的新手,正在努力掌握基础知识,所以如果我问或说的问题听起来过于简单,我深表歉意。
最佳答案
我能提供的最好建议是学习一些介绍性的 CUDA 编程 Material ,例如 this .您的代码不仅缺乏对 CUDA 的理解,而且缺乏对基本 C 概念的理解(例如变量必须在表达式中使用之前定义。)作为 CUDA 程序员,不要“刷新”您对如何编写正确 C 的知识或 C++ 代码。如果你用谷歌搜索“gtc cuda intro”或“gtc cuda optimization”之类的东西,你会找到很好的 CUDA 学习 Material 。
您采用的方法是采用单线程 C/C++ 代码,并将其转换为使用单个 CUDA 线程运行,这可能会让您对“学习 CUDA”产生一些温暖而模糊的感觉,但您没有真正解决任何重要概念 - 它显示在您现在正在努力处理的代码中。
要让您提供的最后一段代码发挥作用,还需要几个步骤:
在 CUDA 中,设备指针通常不能在主机代码中取消引用,并且通常主机指针不能在设备代码中使用。这意味着您通常不应将主机指针传递给设备内核:
getMax<<<1,1>>>(M, arr, max); ^^^ ^^^
您正在解决
devArray
的arr
问题(尽管您的cudaMalloc
设置不正确),我们只是需要修复它并通过额外的cudaMemcpy
操作将主机数据复制到设备来完成它。如果你不确定如何使用像cudaMalloc
这样的函数,不要只是猜测你的方法并使用强制转换将类型强制转换为其他类型 - 这通常表明你没有处理它正确:devArr = (int*)cudaMalloc(M,sizeof(int));
而是引用 documentation .我们还需要正确处理
max
- 它目前是一个主机指针,我们需要该数据的设备副本。您的内核也有点困惑。由于您只启动一个 CUDA 线程,因此您的
threadIdx.x
变量将仅(永远)为零:int i = threadIdx.x; int a = dArr[i];
但内核中的 for 循环会起作用,我们只需要移动一些行即可。
虽然您还没有达到可编译、可运行代码的地步,但做 proper cuda error checking 总是一个好主意.我已经在下面的代码中添加了我自己的版本。
以下代码解决了上述问题,似乎返回了一个合理的结果:
#include <stdio.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <cuda.h>
#define num 100000
#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)
int *arr,my_max = -1;
int getRand() {
double r1=rand()/(double)RAND_MAX; // Generates value between 0 & 1
return (r1 * num) + 1;
}
void generateRandom(int M) {
int i;
for(i=0;i<M;i++) {
arr[i] = getRand();
}
}
__global__ void getMax(int M, int *dArr, int *dMax) {
for(int i=0;i<M;i++) {
int a = dArr[i];
if(a > *dMax)
*dMax = a;
}
}
int main(int argc, char *argv[] ){
if (argc == 2) {
int M;
int *devArr, *devMax;
/* initialize random seed: */
srand (time(NULL));
M = atoi(argv[1]);
//int arr[M];
arr = (int*)calloc(M,sizeof(int));
cudaMalloc(&devArr,M*sizeof(int));
cudaCheckErrors("cudaMalloc 1 fail");
cudaMalloc(&devMax,sizeof(int));
cudaCheckErrors("cudaMalloc 2 fail");
cudaMemset(devMax, 0, sizeof(int));
cudaCheckErrors("cudaMemset fail");
//printf("M = %d MAX = %d\n", M, RAND_MAX);
generateRandom(M);
cudaMemcpy(devArr, arr, M*sizeof(int), cudaMemcpyHostToDevice);
cudaCheckErrors("cudaMemcpy 1 fail");
getMax<<<1,1>>>(M, devArr, devMax);
cudaMemcpy(&my_max, devMax, sizeof(int), cudaMemcpyDeviceToHost);
cudaCheckErrors("cudaMemcpy 2/kernel fail");
printf("Max value: %d \n", my_max);
}
else
printf("Invalid arguments.");
return 0;
}
理解了上述变化后,您会想要回到我最初的建议并进行一些有组织的 CUDA 学习。在这一点上,如果您想重新访问最大值查找,那么“好的”方法就是使用适当的并行缩减技术。 “减少”是一种算法,它采用(大)数据集并返回单个数字或一小组数字作为结果。查找数组中的最大值是“减少”的一个示例。您可以通过研究 this 了解更多关于正确的 CUDA 并行缩减的信息。并通过 CUDA 并行缩减 sample code .
关于将 C 程序转换为 CUDA(最大缩减),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30042464/