在OpenCL中获得Parallel Floyd Warshall算法的错误输出

时间:2014-12-04 07:46:45

标签: c parallel-processing opencl gpu floyd-warshall

#include <stdio.h>
#include <stdlib.h>
#include <iostream>

/*#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else*/
#include <CL/cl.h>
//#endif

#define DATA_SIZE 16

using namespace std;

const char *ProgramSource =
"__kernel void floydWarshallPass(__global uint * pathDistanceBuffer,const unsigned int numNodes, __global uint * result, const unsigned int pass)\n"\
"{\n"\
    "int xValue = get_global_id(0);\n"\
    "int yValue = get_global_id(1);\n"\
    "int k = pass;\n"\
    "int oldWeight = pathDistanceBuffer[yValue * 4 + xValue];\n"\
    "int tempWeight = (pathDistanceBuffer[yValue * 4 + k] + pathDistanceBuffer[k * 4 + xValue]);\n"\
    "if (tempWeight < oldWeight)\n"\
    "{\n"\
        "pathDistanceBuffer[yValue * 4 + xValue] = tempWeight;\n"\
        "result[yValue * 4 + xValue] = tempWeight;\n"\
    "}\n"\
"}\n"\
"\n";


int main(void)
{
cl_context context;
cl_context_properties properties[3];
cl_kernel kernel;
cl_command_queue command_queue;
cl_program program;
cl_int err;
cl_uint num_of_platforms=0;
cl_platform_id platform_id;
cl_device_id device_id;
cl_uint num_of_devices=0;  
cl_mem inputA, inputB, output;
cl_int numNodes;
size_t global;

float inputDataA[16] = {0,2,3,4,5,0,7,8,9,10,0,12,13,14,15,0};
float results[16]={0};

int i,j;
numNodes = 16;



if(clGetPlatformIDs(1, &platform_id, &num_of_platforms) != CL_SUCCESS)
{
    printf("Unable to get platform id\n");
    return 1;
}


// try to get a supported GPU device
if (clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_CPU, 1, &device_id, &num_of_devices) != CL_SUCCESS)
{
printf("Unable to get device_id\n");
return 1;
}

// context properties list - must be terminated with 0
properties[0]= CL_CONTEXT_PLATFORM;
properties[1]= (cl_context_properties) platform_id;
properties[2]= 0;

// create a context with the GPU device
context = clCreateContext(properties,1,&device_id,NULL,NULL,&err);

// create command queue using the context and device
command_queue = clCreateCommandQueue(context, device_id, 0, &err);

// create a program from the kernel source code
program = clCreateProgramWithSource(context,1,(const char **) &ProgramSource, NULL, &err);

// compile the program
if (clBuildProgram(program, 0, NULL, NULL, NULL, NULL) != CL_SUCCESS)
{
printf("Error building program\n");
return 1;
}

// specify which kernel from the program to execute
kernel = clCreateKernel(program, "floydWarshallPass", &err);

// create buffers for the input and ouput

inputA = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * DATA_SIZE, NULL, NULL);
output = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * DATA_SIZE, NULL, NULL);

// load data into the input buffer
clEnqueueWriteBuffer(command_queue, inputA, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputDataA, 0, NULL, NULL);
clEnqueueWriteBuffer(command_queue, output, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputDataA, 0, NULL, NULL);

// set the argument list for the kernel command
clSetKernelArg(kernel, 0, sizeof(cl_mem), &inputA);
clSetKernelArg(kernel, 1, sizeof(cl_int), (void *)&numNodes);
clSetKernelArg(kernel, 2, sizeof(cl_mem), &output);

global=DATA_SIZE;

// enqueue the kernel command for execution
for(cl_uint sh=0; sh<16; sh++)
{
clSetKernelArg(kernel, 3, sizeof(cl_uint), (void *)&sh);
clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global, NULL, 0, NULL, NULL);
//clEnqueueReadBuffer(command_queue, output, CL_TRUE, 0, sizeof(float)*DATA_SIZE, results, 0, NULL, NULL);

//clEnqueueWriteBuffer(command_queue, inputA, CL_TRUE, 0, sizeof(float) * DATA_SIZE, results, 0, NULL, NULL);
//clEnqueueWriteBuffer(command_queue, output, CL_TRUE, 0, sizeof(float) * DATA_SIZE, results, 0, NULL, NULL);
//clSetKernelArg(kernel, 0, sizeof(cl_mem), &inputA);
//clSetKernelArg(kernel, 1, sizeof(cl_int), (void *)&numNodes);
//clSetKernelArg(kernel, 2, sizeof(cl_mem), &output);
clFinish(command_queue);

}
clFinish(command_queue);
// copy the results from out of the output buffer
clEnqueueReadBuffer(command_queue, output, CL_TRUE, 0, sizeof(float) *DATA_SIZE, results, 0, NULL, NULL);

// print the results
printf("output: ");

for(i=0;i<16; i++)
{
printf("%f ",results[i]);
}

// cleanup - release OpenCL resources
clReleaseMemObject(inputA);
//clReleaseMemObject(inputB);
clReleaseMemObject(output);
clReleaseProgram(program);
clReleaseKernel(kernel);
clReleaseCommandQueue(command_queue);
clReleaseContext(context);

return 0;

}

我为每个节点输出 -0.00000

P.S我在CL_DEVICE_TYPE_CPU上运行我的代码,因为在GPU上它提供了无法获取设备ID的错误。

请就如何获得正确的输出提供一些指导。

1 个答案:

答案 0 :(得分:0)

我认为你的问题有点过于宽泛,你应该稍微缩小你的代码范围。我会尝试帮助您解决我在代码中发现的一些错误,但我没有调试或编译它,所以我在这里描述的问题只是让您开始查看的内容。

  • 为什么要在内核中使用参数1调用get_global_id? 回到clEnqueueNDRangeKernel,你指定了你的 工作项维度只有一个,因此您的get_global_id正在查询 对于不存在的维度。如果你想翻译一个 维度坐标分为两个坐标,你应该使用一个 转型如下:
int id = get_global_id(0);
int x = id % size->width;
int y = id / size->height;
  • 使用sizeof(float)来衡量数据类型的大小时要注意:它们在OpenCL实现中的大小可能不同。请改用sizeof(cl_float)

  • 也许您没有获得任何GPU,因为您没有在计算机上安装正确的驱动程序。转到GPU供应商网站,查找OpenCL的运行时驱动程序。

查看OpenCL规范中的那些页面