2014-02-07 25 views
2

我对OpenCl非常陌生。opencl给双数据类型提供了错误的结果?

问题:我在主机中初始化一个值为-1的10个元素的数组。我将同一个数组作为输入传递给设备,并递增每个元素,然后通过Buffer接收数组作为输出。然后再次发送相同的输出数组作为输入到主机并接收增量输出缓冲区。这是循环完成的。

问题:当我将数组的数据类型设置为float/int时,程序工作正常。但是当我将数据类型设置为数组的双精度时,它不会给我所需的结果。 请建议我失踪的地方?任何帮助/建议/关键字将是一个很大的帮助。提前致谢。对于上面的代码

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


#define MEM_SIZE (10) 
#define MAX_SOURCE_SIZE (0x100000) 


int main() { 
    float input[MEM_SIZE], output[MEM_SIZE]; 
    int go, i; 
    for (i = 0; i < MEM_SIZE; i++) { 
     input[i] = -1.0; 
     output[i] = -1.0; 
    } 
    FILE *fp; 
    cl_device_id device_id = NULL; 
    cl_context context = NULL; 
    cl_command_queue command_queue = NULL; 
    cl_program program = NULL; 
    cl_kernel kernel = NULL; 
    cl_platform_id platform_id = NULL; 
    cl_uint ret_num_devices; 
    cl_uint ret_num_platforms; 
    cl_int ret; 
    size_t source_size; 
    char *source_str; 
    fp = fopen("calc_float.cl", "r"); 
    if (!fp) { 
     fprintf(stderr, "Failed to load kernel.\n"); 
     exit(1); 
    } 
    source_str = (char*)malloc(MAX_SOURCE_SIZE); 
    source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp); 
    fclose(fp); 


    /*Initialization*/ 
    /* Get Platform and Device Info */ 
    ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms); 
    ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices); 

    /* Create OpenCL context */ 
    context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret); 

    /* Create Command Queue */ 
    command_queue = clCreateCommandQueue(context, device_id, 0, &ret); 

    /*Initialization complete*/ 

    cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, MEM_SIZE * sizeof(float),(void *) input, NULL); 
    cl_mem outputBuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY , MEM_SIZE * sizeof(float), NULL, NULL); 


    /* Create Kernel Program from the source */ 
    program = clCreateProgramWithSource(context, 1, (const char **)&source_str,(const size_t *)&source_size, &ret); 

    /* Build Kernel Program */ 
    ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); 

    /* Create OpenCL Kernel */ 
    kernel = clCreateKernel(program, "calc", &ret); 

    /* Set OpenCL Kernel Parameters */ 
    ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&inputBuffer); 
    ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&outputBuffer); 

    /* Execute OpenCL Kernel */ 
    ret = clEnqueueTask(command_queue, kernel, 0, NULL,NULL); 
    double x = 10, io; 
    size_t global_work_size[1] = {MEM_SIZE}; 
    for (io = 0; io < x; io++) { 
     inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, MEM_SIZE * sizeof(float),(void *) output, NULL); 
     ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&inputBuffer); 
     ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, NULL); 

     ret = clEnqueueReadBuffer(command_queue, outputBuffer, CL_TRUE, 0, MEM_SIZE * sizeof(float), output, 0, NULL, NULL); 
     for (go = 0; go < MEM_SIZE; go++) { 
      printf("output[%d] = %f\n",io, go, output[go]); 
     } 
     printf("\n\n"); 

    } 


    /* Finalization */ 
    ret = clFlush(command_queue); 
    ret = clFinish(command_queue); 
    ret = clReleaseKernel(kernel); 
    ret = clReleaseProgram(program); 
    ret = clReleaseMemObject(inputBuffer); 
    ret = clReleaseMemObject(outputBuffer); 
    ret = clReleaseCommandQueue(command_queue); 
    ret = clReleaseContext(context); 

    return 1; 
} 

calc_float.cl文件:

__kernel void calc(__global float* in, __global float* out) 
{ 
    int i; 
    for (i = 0; i < 10; i++) { 
     out[i] = in[i] + 1; 
    } 
} 

代码阵列的双数据类型:

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

#define MEM_SIZE (10) 
#define MAX_SOURCE_SIZE (0x100000) 


int main() { 
    double input[MEM_SIZE], output[MEM_SIZE]; 
    int go, i; 
    for (i = 0; i < MEM_SIZE; i++) { 
     input[i] = -1.0; 
     output[i] = -1.0; 
    } 
    FILE *fp; 
    cl_device_id device_id = NULL; 
    cl_context context = NULL; 
    cl_command_queue command_queue = NULL; 
    cl_program program = NULL; 
    cl_kernel kernel = NULL; 
    cl_platform_id platform_id = NULL; 
    cl_uint ret_num_devices; 
    cl_uint ret_num_platforms; 
    cl_int ret; 
    size_t source_size; 
    char *source_str; 
    fp = fopen("calc_double.cl", "r"); 
    if (!fp) { 
     fprintf(stderr, "Failed to load kernel.\n"); 
     exit(1); 
    } 
    source_str = (char*)malloc(MAX_SOURCE_SIZE); 
    source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp); 
    fclose(fp); 


    /*Initialization*/ 
    /* Get Platform and Device Info */ 
    ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms); 
    ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices); 

    /* Create OpenCL context */ 
    context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &ret); 

    /* Create Command Queue */ 
    command_queue = clCreateCommandQueue(context, device_id, 0, &ret); 

    /*Initialization complete*/ 

    cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, MEM_SIZE * sizeof(double),(void *) input, NULL); 
    cl_mem outputBuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY , MEM_SIZE * sizeof(double), NULL, NULL); 


    /* Create Kernel Program from the source */ 
    program = clCreateProgramWithSource(context, 1, (const char **)&source_str,(const size_t *)&source_size, &ret); 

    /* Build Kernel Program */ 
    ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL); 

    /* Create OpenCL Kernel */ 
    kernel = clCreateKernel(program, "calc", &ret); 

    /* Set OpenCL Kernel Parameters */ 
    ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&inputBuffer); 
    ret = clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&outputBuffer); 

    /* Execute OpenCL Kernel */ 
    ret = clEnqueueTask(command_queue, kernel, 0, NULL,NULL); 
    double x = 10, io; 
    size_t global_work_size[1] = {MEM_SIZE}; 
    for (io = 0; io < x; io++) { 
     inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR, MEM_SIZE * sizeof(double),(void *) output, NULL); 
     ret = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&inputBuffer); 
     ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, global_work_size, NULL, 0, NULL, NULL); 

     ret = clEnqueueReadBuffer(command_queue, outputBuffer, CL_TRUE, 0, MEM_SIZE * sizeof(double), output, 0, NULL, NULL); 
     for (go = 0; go < MEM_SIZE; go++) { 
      printf("output[%d] = %lf\n",io, go, output[go]); 
     } 
     printf("\n\n"); 

    } 


    /* Finalization */ 
    ret = clFlush(command_queue); 
    ret = clFinish(command_queue); 
    ret = clReleaseKernel(kernel); 
    ret = clReleaseProgram(program); 
    ret = clReleaseMemObject(inputBuffer); 
    ret = clReleaseMemObject(outputBuffer); 
    ret = clReleaseCommandQueue(command_queue); 
    ret = clReleaseContext(context); 

    return 1; 
} 

为阵列的浮点数据类型代码

calc_double.c对于上面的代码l文件:

__kernel void calc(__global double* in, __global double* out) 
{ 
    int i; 
    for (i = 0; i < 10; i++) { 
     out[i] = in[i] + 1; 
    } 
} 

程序编译:

gcc program.c -o doublesimulation -l OpenCL -I /usr/local/test/AMD-APP-SDK-v2.9-RC-lnx32/include/ -L /usr/local/test/AMD-APP-SDK-v2.9-RC-lnx32/lib/x86 

我也尝试添加下列检查,但它并没有帮助:

#ifdef cl_khr_fp64 
    #pragma OPENCL EXTENSION cl_khr_fp64 : enable 
#elif defined(cl_amd_fp64) 
    #pragma OPENCL EXTENSION cl_amd_fp64 : enable 
#else 
    #error "Double precision floating point not supported by OpenCL implementation." 
#endif 

操作系统:Centos5 32位与AMD显卡

+0

被clEnqueueReadBuffer成功执行?总是检查OpenCL API的错误,这些都是潜在的帮手。 – Meluha

回答

2

检查您的GPU是否支持双精度:

cl_uint native_double_width;  
clGetDeviceInfo(device_id, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &native_double_width, NULL); 

if(native_double_width == 0){ 
    printf("No double precision support.\n"); 
} 

如果天然双向量宽度等于0,双精度不支持(clGetDeviceInfo description

+0

完全同意,使用OpenCL女巫是一个与GPU的通信API,而不检查返回值是完全不安全的。正如使用套接字并丢弃返回值一样。 – DarkZeros

+0

使用此方法的一个小问题是CL_DEVICE_NATIVE_VECTOR_WIDTH_ *常量仅在标准的1.1版中添加,因此版本1.0的实现应该失败。检查双精度支持的正确方法(通常是任何扩展的存在)是检查为平台和设备返回的扩展。无可否认,这是一个小问题,因为我不知道任何当前的OpenCL实现都停留在版本1.0上,但我很迂腐。 – chippies

+0

感谢您的纠正。方法,它必须适用于每个OpenCL设备:检查cl_khr_fp64扩展名,并且不要被特定于供应商的扩展混淆,例如, G。 cl_amd_fp64。 –

相关问题