关于CPU连续发射kernel的问题

记得之前ice或者是横扫千军曾经跟我讲过:

    1:推荐尽量把工作都放在GPU上执行,避免来回copy数据。
    2:把工作都放在GPU上执行也可以是CPU连续发射kernel,并非一定要GPU程序自己反复循环。

问题:1. 我对于CPU连续发射不太理解,能举个例子吗?

         2. 另外,我的”矩阵求逆“和“矩阵相乘”用的都是CULA的库,我的显卡是Fermi构架,不支持GPU调用GPU函数,那这样的话,我只能在CPU端调用CULA库,这样就很难避免数据的来回copy啊!

楼主您好,

(1)根据当时对您说话的人的上下文,可能是指连续<<<>>>启动kernel。
(2)CULA是商业软件。请联系它们公司的技术支持。

1.连续启动,是下面这种情况吗?
for(int i=0;i<100;i++)
{
kernel<<<512,256>>>(A,i);
}
2.我下载的是CULA的免费版,好像里面只有6个常用的函数,我们导师没有花钱买它。我这样表达吧:假设不用CULA,就用自带的库cublas,里面也有矩阵相乘,这些库的矩阵相乘肯定比我写的优化的好,所以,有现成的库我想尽量利用现成的库。但是,这样的库只能在CPU端调用,也就是说就不能全部在GPU上运行了,怎么办呢?我的程序里面有很多的矩阵相乘,向量相乘,而且是在循环里面。

CULA我不懂,但是你说cublas在CPU端运行我不是很懂。
cublas库的函数参数基本都是GPU上的数据,只要你不把这些数据范虎拷回CPU,它就是一直在GPU上运行的。
比如:
for(int i=0;i<MAX;i++)
cublasSgemm(handle,……);
这样的写法,虽然看上去没有内核发射,像是CPU程序一样,实际上它里面封装了GPU内核发射程序。你这样写,它实际上就是完全在GPU上运行的。

是这样的,直接用cublasSgemm()算出的结果,跟CPU是不一样的,比如说,C=A*B,所以,我自己写了一个利用cublas库进行矩阵相乘的函数,这样,输出的结果就跟CPU的串行结果一致了。我并不是说矩阵相乘在CPU端运行,我是说在CPU端“调用”,不能再__global__里面调用,这样的话,岂不是需要在CPU与GPU间反复传递数据吗?(很有可能是我这样用是很笨的方法,如果有别的方法能达到目的也行,欢迎提建议~)我写的矩阵相乘如下:

void matMulmat(double *A,double *B,double *C,int M,int N,int K,const double alpha,const double beta)   //矩阵相乘的CUBLAS库中的cublasDgemm()函数调用
{
	int lda=N;
   int ldb=K;
	int ldc=N;
	int m=N;
	int n=M;
	int k=K;
	cublasOperation_t transa,transb;
	transa=CUBLAS_OP_N;
	transb=CUBLAS_OP_N;
	size_t size_A=M*K*sizeof(double);
	size_t size_B=K*N*sizeof(double);
	size_t size_C=M*N*sizeof(double);

	cublasStatus_t stat;
	cudaError cudaStat;
	cublasHandle_t handle;

	stat=cublasCreate(&handle);
	if(stat!=CUBLAS_STATUS_SUCCESS)
	{
		printf("CUBLAS initialization failed\n");
	}
	double *dev_A,*dev_B,*dev_C;
	cudaStat=cudaMalloc((void**)&dev_A,size_B);
	if(cudaStat!=cudaSuccess)
	{
		printf("Matrix A on device memory allocation failure!\n");
	}
	cudaStat=cudaMalloc((void**)&dev_B,size_A);
	if(cudaStat!=cudaSuccess)
	{
		printf("Matrix B on device memory allocation failure!\n");
	}
	cudaStat=cudaMalloc((void**)&dev_C,size_C);
	if(cudaStat!=cudaSuccess)
	{
		printf("Matrix C on device memory allocation failure!\n");
	}
	cudaStat=cudaMemcpy(dev_A,B,size_B,cudaMemcpyHostToDevice);
	if(cudaStat!=cudaSuccess)
	{
		printf("Matrix from host(A) to device(dev_A) copy failure!\n");
	}
	cudaStat=cudaMemcpy(dev_B,A,size_A,cudaMemcpyHostToDevice);
	if(cudaStat!=cudaSuccess)
	{
		printf("Matrix from host(B) to device(dev_B) copy failure!\n");
	}

	cublasDgemm(handle,transa,transb,m,n,k,&alpha,dev_A,lda,dev_B,ldb,&beta,dev_C,ldc);
	if(stat!=CUBLAS_STATUS_SUCCESS)
	{
		printf("Function cublasDgemm() excute failure!\n");
		cudaFree(dev_A);
		cudaFree(dev_B);
		cudaFree(dev_C);
		cublasDestroy(handle);
	}

	cudaStat=cudaMemcpy(C,dev_C,size_C,cudaMemcpyDeviceToHost);
	if(cudaStat!=cudaSuccess)
	{
		printf("Matrix from device(dev_C) to host(C) copy failure!\n");
	}
	cudaFree(dev_A);
	cudaFree(dev_B);
	cudaFree(dev_C);
	cublasDestroy(handle);
}

“我自己写了一个利用cublas库进行矩阵相乘的函数,这样,输出的结果就跟CPU的串行结果一致了。
我并不是说矩阵相乘在CPU端运行,我是说在CPU端“调用”,不能再__global__里面调用,这样的话,岂不是需要在CPU与GPU间反复传递数据吗?”

楼主说这些您自己写的,那么是否每次都反复cudaMemcpy过来和过去不就是很清楚了吗?
既然是您自己写的东西,您如果在自己的kernel后每次都复制回来,并在下一次启动后并复制后去,那么自然您是知道的。您不需要反问我们。

反之,如果您自己写的那个kernel, 不需要反复复制结果回来又过去,您为何不简单的去掉呢?

我看不懂您的疑问所在。

LZ你看下这个主题http://cudazone.nvidia.cn/forum/forum.php?mod=viewthread&tid=6507的最后一楼,就知道怎么让cublas的矩阵相乘结果和CPU矩阵相乘结果对上了。

看来sdk里cublasMatrixMul的注释都没人看啊……

好的。学习太马虎了,O(∩_∩)O谢谢~

好吧~还是谢谢你~

LZ您好,根据您5#的代码,您把malloc,copy,free神马的操作都包裹在里面了,请您仔细考虑您需要的行为和逻辑,看是否需要真的这么写,以及这是否是您的问题的来源。

祝您好运~

好的。我再想想,好多东西我运用不灵活~

恕我直言,这不是灵活不灵活的问题,而是你有没有理解的问题。

你自己把copy(以及费时的malloc,free)都写到你的函数里面,然后抱怨copy太慢,效率低下。您在书写这个函数的时候,有搞清楚你需要的行为和你写出的行为一致么?

别人告诉你无需每次都copy,你有反思您的函数写法么?