什么可能导致OpenCL在cl :: Program.build上崩溃?

时间:2013-07-22 17:41:25

标签: opencl

当我尝试cl :: Program.build()时,这个程序崩溃,但我不知道为什么。它在这段代码的最后一行崩溃了:

#define __NO_STD_VECTOR 
#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hPP>
#include <iostream>
#include <fstream>
#include <string>
#include <CL/cl.h>

using namespace std;
using namespace cl;
int _tmain(int argc, _TCHAR* argv[])
{
    int tmpSize = 1024;
    float **my2D = new float*[tmpSize];
    for(int i = 0; i < tmpSize; i++)
    {
        my2D[i] = new float[tmpSize];
        for(int i2 = 0; i2 < tmpSize; i2++)
        {
            my2D[i][i2] = 5;
        }
    }
    cl::vector <Platform> platforms;
    Platform::get(&platforms);

    cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[1]()), 0};
    Context context(CL_DEVICE_TYPE_ALL, cps);

    cl::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();

    CommandQueue queue = CommandQueue(context, devices[0], 0);

    int W = tmpSize; //i.width();
    int H = tmpSize; //i.height();

    Buffer d_ip = Buffer(context, CL_MEM_READ_ONLY, W*H*sizeof(float));
    Buffer d_op = Buffer(context, CL_MEM_WRITE_ONLY, W*H*sizeof(float));

    queue.enqueueWriteBuffer(d_ip, CL_TRUE, 0, W*H*sizeof(float), my2D);

    std::ifstream sourceFileName("c:\\users\\me\\desktop\\img_rotate_kernel.cl");
    std::string sourceFile(istreambuf_iterator<char>(sourceFileName), (istreambuf_iterator<char>()));

    Program::Sources rotn_source(1,std::make_pair(sourceFile.c_str(), sourceFile.length() + 1));
    Program rotn_program(context, rotn_source);
    rotn_program.build(devices); // <----- CRASHES HERE
}

使用此内核

__kernel void img_rotate(__global float* dest_data, __global float* src_data, int W, int H, float sinTheta, float cosTheta)
    const int ix = get_global_id(0);
    const int iy = get_global_id(1);
    float x0 = W/2.0f;
    float y0 = W/2.0f;
    float xOff = ix-x0;
    float yOff = iy - y0;
    int xpos = (int)(xOff*cosTheta + yOff*sinTheta + x0);
    int ypos = (int)(yOff*cosTheta - yOff*sinTheta + y0);
    if(((int)xpos>=0) && ((int)xpos < W) && ((int)ypos>=0) && ((int)ypos<H))
    {
        dest_data[iy*W+ix] = src_data[ypos*W+xpos];
    }
}

这是崩溃时遇到的异常对话

enter image description here

1 个答案:

答案 0 :(得分:1)

来自OpenCL C++ wrapper spec

  

cl :: Program :: Program返回一个有效的程序对象,如果程序对象是,则将err设置为CL_SUCCESS   创建成功。否则,它将返回错误[...]

中返回的以下错误值之一

您的程序对象可能无法正确创建,请更改您的程序构造调用以使用此签名后的err参数

cl::Program::Program(const Context& context, const Sources& sources, cl_int * err = NULL)

在对程序对象执行任何其他操作之前,请确保err == CL_SUCCESS

大多数OpenCL调用允许您传递指向错误参数的指针。您应该这样做并在调用之后检查它(至少在调试版本中我猜),以减少未来的麻烦。


好的,所以我稍微修改了你的源代码。在这里,我会立即解释我的变化。

#define __NO_STD_VECTOR 
#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <CL/cl.h>

#define ARRAY_SIZE 128

using namespace std;
using namespace cl;

int main(int, char**)
{
    int err;

    float my2D[ARRAY_SIZE * ARRAY_SIZE] = { 0 };
    for(int i = 0; i < ARRAY_SIZE * ARRAY_SIZE; i++)
    {
        my2D[i] = 5;
    }

    cl::vector <Platform> platforms;
    err = Platform::get(&platforms);

    if(err != CL_SUCCESS) {
        std::cout << "Platform::get failed - " << err << std::endl;
        std::cin.get();
    }

    cl_context_properties cps[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0]()), 0 };
    Context context(CL_DEVICE_TYPE_ALL, cps, nullptr, nullptr, &err);

    if(err != CL_SUCCESS) {
        std::cout << "Context::Context failed - " << err << std::endl;
        std::cin.get();
    }

    cl::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>(&err);

    if(err != CL_SUCCESS) {
        std::cout << "Context::getInfo failed - " << err << std::endl;
        std::cin.get();
    }

    CommandQueue queue = CommandQueue(context, devices[0], 0, &err);

    if(err != CL_SUCCESS) {
        std::cout << "CommandQueue::CommandQueue failed - " << err << std::endl;
        std::cin.get();
    }

    int W = ARRAY_SIZE; //i.width();
    int H = ARRAY_SIZE; //i.height();

    Buffer d_ip = Buffer(context, CL_MEM_READ_ONLY, W*H*sizeof(float), nullptr, &err);

    if(err != CL_SUCCESS) {
        std::cout << "Buffer::Buffer 1 failed - " << err << std::endl;
        std::cin.get();
    }

    Buffer d_op = Buffer(context, CL_MEM_WRITE_ONLY, W*H*sizeof(float), nullptr, &err);

    if(err != CL_SUCCESS) {
        std::cout << "Buffer::Buffer 2 failed - " << err << std::endl;
        std::cin.get();
    }

    err = queue.enqueueWriteBuffer(d_ip, CL_TRUE, 0, W*H*sizeof(float), &my2D[0]);

    if(err != CL_SUCCESS) {
        std::cout << "Queue::enqueueWriteBuffer failed - " << err << std::endl;
        std::cin.get();
    }

    std::ifstream sourceFileName("so_question.cl");
    std::string sourceFile(std::istreambuf_iterator<char>(sourceFileName), (std::istreambuf_iterator<char>()));

    Program::Sources rotn_source(1,std::make_pair(sourceFile.c_str(), sourceFile.length() + 1));
    Program rotn_program(context, rotn_source, &err);

    if(err != CL_SUCCESS) {
        std::cout << "Program::Program failed - " << err << std::endl;
        std::cin.get();
    }

    err = rotn_program.build(devices);

    if(err != CL_SUCCESS) {
        std::cout << "Program::build failed - " << err << std::endl;
        std::cin.get();
    }
}

您会注意到我添加了更多错误检查。这让我发现在初始程序中Context::Context实际上的调用失败了。问题可能是platforms[1]不存在(向量中有1个元素)所以我将其切换为platforms[0]

修复后,我在queue.enqueueWriteBuffer();电话上收到了访问权限违规行为。问题是你的二维数组实际上是堆分配数组的数组。这是一个问题,因为OpenCL希望能够从连续的内存中读取数据,而在循环中使用new进行分配时并非如此。实际上无法保证您的阵列在内存中彼此相邻。

为了解决这一问题,我在堆栈上分配了一维数组(参见开头的循环)。然后呼叫变为

queue.enqueueWriteBuffer(d_ip, CL_TRUE, 0, W*H*sizeof(float), &my2D[0]);

但是,您可能无法使用1024 x 1024的float数组执行此操作,因为您将占用堆栈空间。如果你需要一个很大的数组,你可能希望new一个足够大的单维数组来包含你的数据并自己执行索引算法。这可以确保您将整个存储空间作为一个连续的块。

CL_BUILD_PROGRAM_FAILURE调用时代码现在出现err = rotn_program.build()错误,这意味着您的CL程序代码可能存在错误。由于这是一个完全不同的问题,我会让你想出这个。