Dijkstra算法的CUDA并行程序流程

时间:2015-05-17 14:36:51

标签: c++ cuda

这里的代码是一个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);
}

Output of this code

1 个答案:

答案 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)

然后ncheck的角色会更加清晰,在调试内核时出错并在调试时丢失它的可能性会降低。