这里的代码是一个cuda代码,用于使用Dijkstra算法找到最短的对路径。
我的代码逻辑在c程序中完美运行,而不是在Cuda中。我使用1个具有N个线程的块,N是用户输入的。
首先怀疑,除了共享变量temp之外,每个线程都有自己的变量副本。正确吗?
当我打印结果时,我将所有值存储在数组d中并打印其值为零的值。只有在s = threadIdx.x之后控制流不进入循环时才可以这样做。
请帮助,自上次24小时以来一直在调试。
给定输入是:
顶点数:4
输入边缘的来源,目的地和成本\ n输入-1结束 输入\ n边缘从零开始:0 1 1
输入边缘的来源,目的地和成本\ n输入-1结束 输入\ n边从零开始:0 2 5
输入边缘的来源,目的地和成本\ n输入-1结束 输入\ n边缘从零开始:0 3 2
输入边缘的来源,目的地和成本\ n输入-1结束 输入\ n边缘从零开始:1 3 4
输入边缘的来源,目的地和成本\ n输入-1结束 输入\ n边缘从零开始:2 3 7
输入边缘的来源,目的地和成本\ n输入-1结束 输入\ n边从零开始:-1 -1 -1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<sys/time.h>
#define nano 1000000L
__global__ void dijkstras(int *a, int *b, int *n)
{
int i;
int d[10],p[10],v[10];
// d stores distnce/cost of each path
// p stores path taken
// v stores the nodes already travelled to
int k,u,s;
int check =0;
// shared memory on cuda device
__shared__ int temp[20];
for(i=0; i < (*n)*(*n); i++)
{
temp[i] = a[i];
}
check = check + 1;
__syncthreads();
// were passing int s -- node from which distances are calculated
s = threadIdx.x;
for(i=0; i<(*n); i++)
{
d[i]=temp[s*(*n)+i];
if(d[i]!=9999)
p[i]=1;
else
p[i]=0;
v[i]=0;
}
p[s]=0;
v[s]=1;
for(i=0; i<((*n)-1); i++)
{
// findmin starts here
int i1,j1,min=0;
for(i1=0;i1<(*n);i1++)
{
if(v[i1]==0)
{
min=i1;
break;
}
}
for(j1=min+1;j1<(*n);j1++)
{
if((v[j1]==0) && (d[j1]<d[min]))
min=j1;
}
k = min;
// findmin ends here
v[k]=1;
for(u=0; u<(*n); u++)
{
if((v[u]==0) && (temp[k*(*n)+u]!=9999))
{
if(d[u]>d[k]+temp[k*(*n)+u])
{
d[u]=d[k]+temp[k*(*n)+u];
p[u]=k;
}
}
}
//storing output
int count = 0;
for(i = (s*(*n)); i< (s+1) * (*n); i++)
{
b[i] = d[count];
count++;
}
}
*n = check;
}
main()
{
int *a, *b, *n;
int *d_a, *d_b, *d_n;
int i,j,c;
int check = 0;
printf("enter the number of vertices.... : ");
n = (int*)malloc(sizeof(int));
scanf("%d",n);
int size = (*n) * (*n) * sizeof(int);
//allocating device memory
cudaMalloc((void **)&d_a, size);
cudaMalloc((void **)&d_b, size);
cudaMalloc((void **)&d_n, sizeof(int));
a = (int*)malloc(size);
b = (int*)malloc(size);
check = check +1;
for(i=0; i<(*n); i++)
for(j=0; j<=i; j++)
if(i==j)
a[(i*(*n) + j)]=0;
else
a[(i*(*n) + j)]=a[(j*(*n) + i)]=9999;
printf("\nInitial matrix is\n");
for(i=0;i<(*n);i++)
{
for(j=0;j<(*n);j++)
{
printf("%d ",a[i*(*n)+j]);
}
printf("\n");
}
while(1)
{
printf("\n enter the source,destination and cost of the edge\n Enter -1 to end Input\n Edges start from Zero : \n");
scanf("%d %d %d",&i,&j,&c);
if(i==-1)
break;
a[(i*(*n) + j)]=a[(j*(*n) + i)]=c;
}
printf("\nInput matrix is\n");
for(i=0;i<(*n);i++)
{
for(j=0;j<(*n);j++)
{
printf("%d ",a[i*(*n)+j]);
}
printf("\n");
}
check = check +1;
// copying input matrix to device
cudaMemcpy(d_a, a, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_n, n, sizeof(int), cudaMemcpyHostToDevice);
check++;
struct timeval start,stop;
double time;
int N = *n;
gettimeofday(&start,NULL);
dijkstras<<<1,N>>>(d_a, d_b, d_n);
gettimeofday(&stop,NULL);
time=(double)(stop.tv_sec-start.tv_sec)+(double)(stop.tv_usec-start.tv_usec)/(double)nano;
printf("\n TIME TAKEN: %lf\n",time);
check++;
// copying result from device to host
cudaMemcpy(b, d_b, size, cudaMemcpyDeviceToHost);
cudaMemcpy(n, d_n, sizeof(int), cudaMemcpyDeviceToHost);
check++;
// printing result
printf("the shortest paths are....");
for(i=0; i<(N); i++)
{
for(j=0; j<(N); j++)
{
if(i != j)
printf("\n the cost of the path from %d to %d = %d\n",i,j,b[i*(N) + j]);
}
printf("\n\n");
}
printf("your debug value of check in main is %d\n",check); //5
printf("your debug value of check in device is %d\n",*n); // 1+ 7+ 10
free(a); free(b);free(n);
cudaFree(d_a); cudaFree(d_b);cudaFree(d_n);
}
答案 0 :(得分:1)
此问题的根本原因是提供未初始化的设备变量作为内核参数。在这个内核调用中:
dijkstras<<<1,N>>>(d_a, d_b, d_n);
d_n
已分配内存,但从未分配值,导致内核中的未定义行为。
我认为,由于内核本身的设计决策很糟糕,原始海报难以检测到这一点。在这个原型中:
__global__ void dijkstras(int *a, int *b, int *n)
n
被用作输入和输出,具有两个完全不同的含义,这使得通过调用检测问题变得更加困难。如果原型是:
__global__ void dijkstras(int *a, int *b, int n, *int check)
然后n
和check
的角色会更加清晰,在调试内核时出错并在调试时丢失它的可能性会降低。