c - opencl 为 double 数据类型给出了错误的结果?

标签 c opencl

我是 OpenCl 的新手。

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

问题:当我将数组的数据类型设为 float/int 时,程序运行正常。但是当我将数据类型设为数组的两倍时,它并没有给我想要的结果。 请建议我在哪里失踪?任何帮助/建议/关键字都会有很大帮助。提前致谢。

float 据类型数组代码:

#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;
    }
}

double数据类型数组的代码:

#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.cl 文件:

__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 32bit AMD显卡

最佳答案

检查您的 GPU 是否支持 double :

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");
}

如果 native double vector 宽度等于 0,则不支持 double (clGetDeviceInfo description)

关于c - opencl 为 double 数据类型给出了错误的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21620008/

相关文章:

C - sysinfo() 返回错误值 i686

c - OpenCL。数组寻址/指针的奇怪错误

c - OpenCL clock_gettime 与内核分析 : strange results

c - 什么代码CPU比较贵: while(*p) or while(i--)?

c - Rust 链接属性的内部工作原理与 C 中的链接相比如何?

c - 向后字母表的算法是什么?

c - 如何在格式错误的输入中正确使用带循环的 sscanf?

c++ - 使用 OpenCL 2.0 C++ 绑定(bind)头文件的链接器错误

java - 错误: "UnsatisfedLinkError: com.aparapi.internal.jni.OPENCLJNI.getPlatforms()" JNI configuration

c++ - 为什么使用 OpenCL 在 GPU 上下载数据比上传数据慢很多?