我想要評估一個標量函數f(x),其中x是一個k維矢量(即f:R^k-> R)。在評估過程中,我必須執行許多矩陣運算:反演,乘法和尋找矩陣行列式和中等大小矩陣(大部分小於30x30)的軌跡。現在我想通過在GPU上使用不同的線程來同時在許多不同的xs上評估函數。這就是爲什麼我需要設備API。用cublas設備API計算矩陣行列式
我已經寫了下面的代碼來測試由cublas設備API cublasSgetrfBatched計算矩陣行列式,其中我首先找到矩陣的LU分解並計算U矩陣中所有對角線元素的乘積。我已經使用cublas返回的結果在GPU線程和CPU上完成了此操作。但是,GPU的結果沒有任何意義,而CPU的結果是正確的。我用cuda-memcheck,但沒有發現錯誤。有人可以幫助解決這個問題嗎?非常感謝。
cat test2.cu
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <cuda_runtime.h>
#include <cublas_v2.h>
__host__ __device__ unsigned int IDX(unsigned int i,unsigned int j,unsigned int ld){return j*ld+i;}
#define PERR(call) \
if (call) {\
fprintf(stderr, "%s:%d Error [%s] on "#call"\n", __FILE__, __LINE__,\
cudaGetErrorString(cudaGetLastError()));\
exit(1);\
}
#define ERRCHECK \
if (cudaPeekAtLastError()) { \
fprintf(stderr, "%s:%d Error [%s]\n", __FILE__, __LINE__,\
cudaGetErrorString(cudaGetLastError()));\
exit(1);\
}
__device__ float
det_kernel(float *a_copy,unsigned int *n,cublasHandle_t *hdl){
int *info = (int *)malloc(sizeof(int));info[0]=0;
int batch=1;int *p = (int *)malloc(*n*sizeof(int));
float **a = (float **)malloc(sizeof(float *));
*a = a_copy;
cublasStatus_t status=cublasSgetrfBatched(*hdl, *n, a, *n, p, info, batch);
unsigned int i1;
float res=1;
for(i1=0;i1<(*n);++i1)res*=a_copy[IDX(i1,i1,*n)];
return res;
}
__global__ void runtest(float *a_i,unsigned int n){
cublasHandle_t hdl;cublasCreate_v2(&hdl);
printf("det on GPU:%f\n",det_kernel(a_i,&n,&hdl));
cublasDestroy_v2(hdl);
}
int
main(int argc, char **argv)
{
float a[] = {
1, 2, 3,
0, 4, 5,
1, 0, 0};
cudaSetDevice(1);//GTX780Ti on my machine,0 for GTX1080
unsigned int n=3,nn=n*n;
printf("a is \n");
for (int i = 0; i < n; ++i){
for (int j = 0; j < n; j++) printf("%f, ",a[IDX(i,j,n)]);
printf("\n");}
float *a_d;
PERR(cudaMalloc((void **)&a_d, nn*sizeof(float)));
PERR(cudaMemcpy(a_d, a, nn*sizeof(float), cudaMemcpyHostToDevice));
runtest<<<1, 1>>>(a_d,n);
cudaDeviceSynchronize();
ERRCHECK;
PERR(cudaMemcpy(a, a_d, nn*sizeof(float), cudaMemcpyDeviceToHost));
float res=1;
for (int i = 0; i < n; ++i)res*=a[IDX(i,i,n)];
printf("det on CPU:%f\n",res);
}
nvcc -arch=sm_35 -rdc=true -o test test2.cu -lcublas_device -lcudadevrt
./test
a is
1.000000, 0.000000, 1.000000,
2.000000, 4.000000, 0.000000,
3.000000, 5.000000, 0.000000,
det on GPU:0.000000
det on CPU:-2.000000
非常感謝,羅伯特。您的建議有效並可以產生預期結果。我有另一個設備例程,首先使用cublasSgetrfBatched獲取LU分解,然後cublasSgetriBatched從LU輸出獲取逆。在他們之間,我需要使用cudaDeviceSynchronize()嗎?對於小矩陣(3乘3),結果似乎相同。 – Jack
另一個問題是關於釋放malloc在設備例程中創建的內存。如果我使用free()來釋放內存,那麼當代碼使用-lcublas_device編譯時(如果沒有它),cuda-memcheck會產生錯誤。你碰巧有什麼想法來解決這個問題嗎?如果我沒有釋放記憶,會有什麼後果?多謝。 – Jack
關於第一個問題,cuda [stream semantics](http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#streams)也適用於設備端操作。沒有指定流的設備端啓動應該啓動到默認流(每個線程!),這意味着一個設備cublas操作A跟一個由同一個線程發出的設備cublas操作B應該被串行化。 B應該在A完成之後纔開始。關於第二個問題,我需要確切知道你在做什麼'free()'操作。 –