【问题标题】:How to create OpenCL command queue?如何创建 OpenCL 命令队列?
【发布时间】:2018-01-18 18:54:51
【问题描述】:

我正在尝试学习 OpenCL,但我什至无法制作一个简单的内核来工作。

下面的代码来自《OpenCL Programming by Example》一书,我修改,修改,修改......仍然不知道是什么问题。

每次我在我的 PC(AMD Athlon 5350 APU 和 Radeon R3)中执行程序时,它都会将结果打印为“0.0000”。 如果我在我的另一台机器上运行相同的可执行文件(它是这个 HD 的克隆,所以一切都是一样的)与 NVIDIA 1080 TI,程序输出“3.000”作为结果。

我注意到编译器输出中有一个警告,因此我将过时的 clCreateCommandQueue 调用更改为 clCreateCommandQueueWithProperties()。

现在...它只是段错误(通过 printf() 测试,我知道它在 clCreateCommandQueueWithProperties 期间/之后会出现段错误)。

在配备 NVIDIA GPU 的系统上,它可以正常工作。

我错过了什么?

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <malloc.h>

#include <CL/cl.h>

#define VECTOR_NS 4096
#define VECTOR_SIZE (VECTOR_NS*sizeof(float))

static const char* saxpy_kernel =
    "__kernel void saxpy_kernel(__global float *A, __global float *B, __global float *C)\n"
    "{\n"
        "int index = get_global_id(0);\n"
        "C[0] = 3;\n"
    "}\n"
    ;

int main(void)
{
    int i;
    float total;
    float* A;
    float* B;
    float* C;
    float* Cmapped;
    cl_mem Acl;
    cl_mem Bcl;
    cl_mem Ccl;
    cl_context context;
    cl_platform_id* platforms;
    cl_uint num_platforms;
    cl_uint num_devices;
    cl_command_queue queue;
    cl_kernel kernel;
    cl_int clStatus;

    // Get platform and device information
    platforms = NULL;
    //Set up the Platform
    clStatus = clGetPlatformIDs(0, NULL, &num_platforms);
    platforms = (cl_platform_id *)malloc(sizeof(cl_platform_id)*num_platforms);
    clStatus = clGetPlatformIDs(num_platforms, platforms, NULL);
    //Get the devices list and choose the device you want to run on
    cl_device_id* device_list = NULL;

    clStatus = clGetDeviceIDs( platforms[0], CL_DEVICE_TYPE_GPU, 0, NULL, &num_devices);
    device_list = (cl_device_id *) malloc(sizeof(cl_device_id)*num_devices);

    clStatus = clGetDeviceIDs( platforms[0], CL_DEVICE_TYPE_GPU, num_devices, device_list, NULL);
    // Create one OpenCL context for each device in the platform
    context = clCreateContext( NULL, num_devices, device_list, NULL, NULL, &clStatus);

    /* Create the command queue */
    //queue = clCreateCommandQueue(context, device_list[0], 0, &clStatus);
    queue = clCreateCommandQueueWithProperties(context, device_list[0], NULL, &clStatus);

    if(clStatus != CL_SUCCESS){
        fprintf(stderr, "ERROR: failed to execute the kernel: %d.\n", clStatus);
        exit(1);
    }

    /* */
    if((A = aligned_alloc(sysconf(_SC_PAGESIZE), VECTOR_SIZE)) == NULL){
        fprintf(stderr, "ERROR: failed to allocate memory.\n");
        exit(1);
    }
    if((B = aligned_alloc(sysconf(_SC_PAGESIZE), VECTOR_SIZE)) == NULL){
        fprintf(stderr, "ERROR: failed to allocate memory.\n");
        exit(1);
    }
    if((C = aligned_alloc(sysconf(_SC_PAGESIZE), VECTOR_SIZE)) == NULL){
        fprintf(stderr, "ERROR: failed to allocate memory.\n");
        exit(1);
    }

    /* Initialize it */
    i = 0;
    do {
        A[i] = 1;
        B[i] = 2;
        C[i] = 0;
    } while(++i != VECTOR_NS);

    Acl = clCreateBuffer(context, CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, VECTOR_SIZE, A, &clStatus); // CL_MEM_READ_ONLY
    Bcl = clCreateBuffer(context, CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, VECTOR_SIZE, B, &clStatus); // CL_MEM_READ_ONLY
    Ccl = clCreateBuffer(context, CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, VECTOR_SIZE, C, &clStatus); // CL_MEM_WRITE_ONLY

    // Create a program from the kernel source
    // Build the program
    cl_program program = clCreateProgramWithSource(context, 1, (const char**)&saxpy_kernel, NULL, &clStatus);

    if(clStatus != CL_SUCCESS){
        fprintf(stderr, "ERROR: failed to compile the OpenCL code.\n");
        exit(1);
    }

    clStatus = clBuildProgram(program, 1, device_list, NULL, NULL, NULL);

    if(clStatus != CL_SUCCESS){
        fprintf(stderr, "ERROR: failed to compile the OpenCL code.\n");
        exit(1);
    }

    // Create the OpenCL kernel
    kernel = clCreateKernel(program, "saxpy_kernel", &clStatus);
    // Set the arguments of the kernel
    clSetKernelArg(kernel, 0, sizeof(cl_mem), (void*)&Acl);
    clSetKernelArg(kernel, 1, sizeof(cl_mem), (void*)&Bcl);
    clSetKernelArg(kernel, 2, sizeof(cl_mem), (void*)&Ccl);

    // Execute the OpenCL kernel on the list
    size_t global_size = VECTOR_NS; // Process the entire lists
    size_t local_size = 1;

    // Process one item at a time
    clStatus = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global_size, &local_size, 0, NULL, NULL);

    if(clStatus != CL_SUCCESS){
        fprintf(stderr, "ERROR: failed to execute the kernel: %d.\n", clStatus);
        exit(1);
    }

    //* Clean up and wait for all the comands to complete. */
    clFlush(queue);

    /* Display the result to the screen */
    Cmapped = (float*) clEnqueueMapBuffer(queue, Ccl, CL_TRUE, CL_MAP_READ, 0, VECTOR_SIZE, 0, NULL, NULL, &clStatus); // CL_MEM_USE_HOST_PTR

    if(clStatus != CL_SUCCESS){
        fprintf(stderr, "ERROR: failed to execute the kernel: %d.\n", clStatus);
        exit(1);
    }

    total = 0;
    for(i = 0; i < VECTOR_NS; i++)
        total += C[i];

    printf("TOTAL: %f\n", total);

    /* Clean up and wait for all the comands to complete. */
    clFlush(queue);
    clFinish(queue);

    /* Finally release all OpenCL allocated objects and host buffers. */
    clReleaseKernel(kernel);
    clReleaseProgram(program);
    clReleaseMemObject(Acl);
    clReleaseMemObject(Bcl);
    clReleaseMemObject(Ccl);
    clReleaseCommandQueue(queue);
    clReleaseContext(context);

    free(platforms);
    free(device_list);

    return 0;
}

【问题讨论】:

  • 如果您使用clEnqueueReadBuffer 而不是clEnqueueMapBuffer 是否有效?另外,我看到您正在写入 only c[0] ,然后汇总所有值。你认为你从 c[1] 到 c[VECTOR_NS-1] 得到什么值?可能是未初始化的内存。
  • 这个来源是我尝试学习 OpenCL 线程组、ID...以确认我是否理解它。由于没有任何工作,我在寻找问题的同时进行了编辑和编辑......最后现在内核只是执行“C [0] = 3”(其他所有内容都初始化为0)。这只是一个测试,没有做任何有用的事情。
  • 我没有尝试使用 clEnqueueReadBuffer(),因为我的整个目标是使用具有零拷贝 APU 的 16GB 计算机...我是 OpenCL 的新手,但我遵循了教程在arrayfire.com/zero-copy-on-integrated-gpus。本教程是关于 C++ 的,但我认为我已经完全适应了 C 版本的 API。
  • 我现在看到了初始化。我不知道为什么它不起作用。请检查从 clCreateBuffer 返回的 clStatus 值,以确保您使用 CL_MEM_USE_HOST_PTR 时一切正常(尽管可能不是这样,因为它会导致下游错误)。另一种方法是使用 CL_MEM_ALLOC_HOST_PTR,然后在 init 之前映射并在内核之前取消映射(然后再次映射以获得结果)。 clCreateCommandQueueWithProperties 在您的 AMD 上可能失败的原因是该驱动程序的版本不支持它。检查平台和设备版本(通过代码或使用 clInfo)。
  • 创建命令队列调用的驱动程序实现之一可能会尝试取消引用 nullptr(用于队列属性)。如果您定义属性,它会起作用吗?使用 cl_queue_properties properties[] = {0}; 为初学者尝试一个空列表;并替换你的 NULL。

标签: c opencl


【解决方案1】:

虽然您的代码在我的机器上按原样运行,但我认为这是一个可能导致您的问题的问题。来电

Cmapped = (float*)clEnqueueMapBuffer(queue, Ccl, CL_TRUE, CL_MAP_READ, 0, VECTOR_SIZE, 0, NULL, NULL, &clStatus);

更改了Cmapped,但您尝试从原始C 缓冲区中读取

total = 0;
for(i = 0; i < VECTOR_NS; i++)
    total += C[i];

这应该是这样的

total = 0;
for(i = 0; i < VECTOR_NS; i++)
    total += Cmapped[i];

但是,由于您使用 CL_MEM_USE_HOST_PTR 标志创建了缓冲区,如果您使用 clEnqueueReadBuffer 代替,如果您使用原始指针作为目标,您的 OpenCL 驱动程序也应该能够优化复制操作:

clEnqueueReadBuffer(queue, Ccl, CL_TRUE, 0, VECTOR_SIZE, C, 0, NULL, NULL);

如果数据没有被 OpenCL 实现缓存到设备内存,这应该是一个空操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    • 2012-10-06
    • 2011-05-31
    • 2020-09-18
    • 2015-08-07
    相关资源
    最近更新 更多