OpenCL 在尝试读取内核输出时永远挂起

问题描述 投票:0回答:1

这是 OpenCL 主机在微不足道的内核中耗尽内存的后续结果,在应用更正并出现另一个错误后,我发现我的程序因未知原因挂在

EnqueueReadBuffer

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#define CL_TARGET_OPENCL_VERSION 210
#include "CL/cl.h"

char* program_src = "__kernel void SAXPY (__global float* x, __global float* y, float a)\n"
"{\n"
"const int i = get_global_id (0);\n"
"y [i] += a * x [i];\n"
"}\n";

int main() {
    cl_platform_id platform_ids[16];
    cl_uint platform_count;

    if (clGetPlatformIDs(16, &platform_ids, &platform_count) != CL_SUCCESS) {
        return EXIT_FAILURE;
    }
    printf("%i cl platform(s) found\n", platform_count);

    if (platform_count == 0) {
        return EXIT_FAILURE;
    }

    printf("choosing platform 0...\n");

    cl_device_id device_ids[16];
    cl_int device_count;
    if (clGetDeviceIDs(platform_ids[0], CL_DEVICE_TYPE_ALL, 16, &device_ids, &device_count) != CL_SUCCESS) {
        return EXIT_FAILURE;
    }
    printf("%i cl device(s) found on platform 0\n", device_count);

    if (device_count == 0) {
        return EXIT_FAILURE;
    }

    cl_device_id device = device_ids[0];

    printf("** running test **\n");

    cl_int cl_fehler;
    cl_context ctx = clCreateContext(NULL, 1, &device, NULL, NULL, &cl_fehler);
    if (ctx == NULL) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clCommandQueue\n");
    cl_fehler = CL_SUCCESS;
    cl_command_queue queue = clCreateCommandQueue(ctx, device, 0, &cl_fehler);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    // Replace 1 mit Zahlen von Gärate IDs
    printf("Am clCreateProgram\n");
    cl_fehler = CL_SUCCESS;
    cl_program program = clCreateProgramWithSource(ctx, 1, &program_src, NULL, &cl_fehler);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clBuildProgram\n");
    cl_fehler = clBuildProgram(program, 1, &device, NULL, NULL, NULL);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clCreateKernel\n");
    cl_fehler = CL_SUCCESS;
    cl_kernel kernel = clCreateKernel(program, "SAXPY", &cl_fehler);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clCreateBuffer\n");
    cl_fehler = CL_SUCCESS;
    cl_mem eingabe_buffer = clCreateBuffer(ctx, CL_MEM_READ_ONLY, sizeof(cl_float) * 10, NULL, &cl_fehler);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }
    
    printf("Am clCreateBuffer\n");
    cl_fehler = CL_SUCCESS;
    cl_mem ausgabe_buffer = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY, sizeof(cl_float) * 10, NULL, &cl_fehler);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    cl_float eingabe_data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    printf("Am clEnqueueWriteBuffer\n");
    cl_fehler = clEnqueueWriteBuffer(queue, eingabe_buffer, CL_TRUE, 0, sizeof(cl_float) * 10, &eingabe_data, 0, NULL, NULL); 
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clSetKernelArg\n");
    cl_fehler = clSetKernelArg(kernel, 0, sizeof(cl_mem), &eingabe_buffer);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clSetKernelArg\n");
    cl_fehler = clSetKernelArg(kernel, 1, sizeof(cl_mem), &ausgabe_buffer);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clSetKernelArg\n");
    cl_float f = 2.0;
    cl_fehler = clSetKernelArg(kernel, 2, sizeof(cl_float), &f);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clEnqueueNDRangeKernel\n");
    const size_t globalWorkSize[3] = { 10, 0, 0 };
    cl_fehler = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &globalWorkSize, NULL, 0, NULL, NULL);
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    printf("Am clEnqueueReadBuffer\n");
    cl_float ausgabe_data[3];
    cl_fehler = clEnqueueReadBuffer(queue, ausgabe_buffer, CL_TRUE, 0, sizeof(cl_float) * 10, &ausgabe_data, 0, NULL, NULL); 
    if (cl_fehler != CL_SUCCESS) {
        printf("Fehler: %i\n", cl_fehler);
        return EXIT_FAILURE;
    }

    // No point in share the rest of the code because the problem is being happening here
}
opencl opencl-c
1个回答
0
投票

我至少可以发现 3 个问题:

1.缓冲区大小

cl_float ausgabe_data[3];
---------------------^^^

clEnqueueReadBuffer(queue, ausgabe_buffer, CL_TRUE, 0, sizeof(cl_float) * 10, &ausgabe_data, 0, NULL, NULL);
-------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^

这是尝试将 10 个浮点数读入可容纳 3 个浮点数的缓冲区中。

2.指针语法

可能不会导致问题,具体取决于您的C编译器,但据我所知,它并不严格正确。当将指针传递到复制目的地时,您有:

…, &ausgabe_data, …

它获取数组本身的地址,而不是数组中数据项的地址。在“大多数”情况下,这些应该是相同的,但最好坚持安全的方法。删除与符号 (&) 以利用数组自动降级为指向其第 0 个元素的指针的事实,或者显式指定开始写入的数组项 (

&ausgabe_data[0]
)。
请注意,使用 

clEnqueueWriteBuffer()

调用

&eingabe_data
也存在同样的问题。
3.缓冲液的使用。

内核代码使用:

y [i] += …
因此,它
从 y 读取,将该值添加到另一个值,然后将其写回

。然而,y的缓冲区被创建为只写,并且其内容从未初始化:


cl_mem ausgabe_buffer = clCreateBuffer(ctx, CL_MEM_WRITE_ONLY, ---------------------------------------------------^^^^^^^^^^
要么使缓冲区可读写,并使用合理的初始数据(全为零?)对其进行初始化,要么将内核代码更改为纯赋值。 (
y [i] = …

)

    

© www.soinside.com 2019 - 2024. All rights reserved.