我使用CUDA 7.5运行并行BFS的以下算法。该函数接受一个边数组和一个顶点数组。边缘定义为
typedef struct Edge
{
int first;
int second;
}Edge;
对于除起始顶点之外的所有顶点,顶点数组初始化为-1。因此我们有类似
的内容 1 2 3 4 5 6.....1024
-1-1-1-1 0-1.....-1
在这种情况下,起始顶点为4 假设一个稀疏图形,边缘列表将以下列方式获得数据(数据将在边缘内容中,但我提供了整数表示)
1 2 3 4 5 .......2048
3 17 12 1 3........2010
9 34 20 9 17.......196
BFS应该与2048个线程平行运行,任何线程都有0作为第一个/第二个索引写入顶点数组1中的相关索引,并将bool修改为1.这是BFS代码。
__global__ void bfs(Edge* edges, int* vertices, int current_depth, int* modified){
int e = blockDim.x * blockIdx.x + threadIdx.x;
int vfirst = edges[e].first;
if (vfirst > 1023) {printf("oops %d:%d\n", e, vfirst); return;}
int dfirst = vertices[vfirst];
int vsecond = edges[e].second;
if (vsecond > 1023) {printf("oops %d:%d\n", e, vsecond); return;}
int dsecond = vertices[vsecond];
if((dfirst == current_depth) && (dsecond == -1)){
vertices[vsecond] = current_depth;
printf("e:%d depth:%d\n", e, current_depth);
__syncthreads();
*modified = 1;
printf("%d\n", *modified);
}else if((dsecond == current_depth) && (dfirst == -1)){
vertices[vfirst] = current_depth;
printf("e:%d depth:%d\n", e, current_depth);
__syncthreads();
*modified = 1;
printf("%d\n", *modified);
}
}
每次调用时,主代码会重复调用此BFS内核,以增加当前深度的值。这是调用代码的相关部分。
begin = clock();
do{
h_modified = 0;
//printf("Entered while loop\n");
err = cudaMemcpy(d_modified, &h_modified, sizeof(int), cudaMemcpyHostToDevice);
if (err != cudaSuccess)
{
fprintf(stderr, "Failed to copy h_done to device(error code %s)!\n", cudaGetErrorString(err));
exit(EXIT_FAILURE);
}
printf("CUDA kernel launching with %d blocks of %d threads\n", edgeBlocks, threadsPerBlock);
bfs<<<edgeBlocks, threadsPerBlock>>>(d_edges, d_vertices, current_depth, d_modified);
cudaThreadSynchronize();
err = cudaGetLastError();
if (err != cudaSuccess)
{
fprintf(stderr, "Failed to launch bfs kernel (error code %s)!\n", cudaGetErrorString(err));
exit(EXIT_FAILURE);
}
//printf("Second kernel launch finished\n");
err = cudaMemcpy(&h_modified, d_modified, sizeof(int), cudaMemcpyDeviceToHost);
printf("%d\n", h_modified);
if (err != cudaSuccess)
{
fprintf(stderr, "Failed to copy d_done to host(error code %s)!\n", cudaGetErrorString(err));
exit(EXIT_FAILURE);
}
printf("BFS run for level %d\n", current_depth);
current_depth++;
}while(h_modified != 0);
end = clock();
time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Time taken: %f\n", time_spent);
memcpy和mallocs都已正确检查。我的问题是,在第一次运行BFS时,修改后的变量永远不会被修改为1,因此函数永远不会被第二次调用。我已经彻底检查了我的逻辑,但似乎无法解决问题。这是我在CUDA的第一个完整项目,因此任何帮助将不胜感激。如果您想要一个完整的可验证示例,请使用链接
答案 0 :(得分:2)
我的问题是,在第一次运行BFS时,修改后的变量永远不会被修改为1,因此函数永远不会被第二次调用。
遇到的第一个问题是cuda-memcheck
所指示的越界访问。这是因为edges
数组错误地包含了1024的索引,这是无效的,因为vertices
数组的大小是1024.修复是修改edges
数组,以便不存在大于1023的值。
发现的另一个主要问题是current_depth
变量最初设置为1(在main.cu中)。这样可以防止if
内核中的bfs
条件得到满足。 if
条件:
if((dfirst == current_depth) &&...
取决于从匹配dfirst
值的vertices
数组中检索的值(current_depth
)。但由于vertices
数组的初始总体全部为0或-1(如问题描述中所述),因此在第一次内核启动时不可能满足if
条件。因此,modified
变量永远不会更改为1,因此不会发生其他内核启动。修复是在main.cu中将current_depth
初始设置为零。
此外,在main.cu中观察到以下代码行:
err = cudaMemcpy(&h_vertices, d_vertices, VERTEX_BYTES, cudaMemcpyDeviceToHost);
由于h_vertices
已经是一个指针,因此在这里获取它的地址是不正确的,因此符号在这里是不合适的。按原样使用该代码将是程序中堆栈损坏的一个方法。解决方法是删除&符号。