【问题标题】:OpenCL - How can my array be too big to cause a stack overflow?OpenCL - 我的数组怎么会太大而导致堆栈溢出?
【发布时间】:2015-03-31 12:40:26
【问题描述】:

我是 OpenCL 新手,我正在使用 C++ 包装器对其进行编程。我有一张较旧的 AMD 卡 (Radeon HD 5770),这可能是问题的原因,但我想暂时排除这个问题。

我正在尝试“处理”一个“图像”,为此我将 400 x 400 像素^2 伪造为一维整数数组。所以,我的缓冲区大小应该是 4 * 400 * 400 - 大约 640kb。我认为这一点也不大。

我认为相关的一些统计数据:

  • 每个工作组的最大工作项:256
  • 每个工作组的最大工作项尺寸:(256, 256, 256) 我认为其中 x * y * z
  • 最大内存分配大小:536,870,912(看起来像 1/2 GB)
  • 催化剂 14.12
  • AMD SDK 3.0.0(测试版)
  • 使用 Visual Studio Community 2013

一些代码:

#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <streambuf>
#include <string>

#include <CL/cl.hpp>

using namespace System;
using namespace std;
#define IMG_WIDTH 400
#define IMG_HEIGHT 400

int main(array<System::String ^> ^args)
{
    vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);

    cl::Platform default_platform = all_platforms[0];

    vector<cl::Device> all_devices;
    default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
    cl::Device default_device = all_devices[0];     

    cl::Context context({ default_device });

    std::ifstream file("kernels.cl");
    std::string kcode(std::istreambuf_iterator<char>(file),
                      (std::istreambuf_iterator<char>()));

    cl::Program::Sources sources(1,
         std::make_pair(kcode.c_str(), kcode.length() + 1));

    cl::Program program(context, sources);

    if (program.build({ default_device }) != CL_SUCCESS){
        cout << "Error building " << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device) << endl;
    exit(1);
    }

    int h_C[IMG_WIDTH * IMG_HEIGHT]; // initialize the array.
    cl::Buffer d_C(context, CL_MEM_READ_WRITE, sizeof(int) * IMG_WIDTH * IMG_HEIGHT); // create the device memory for this array.

    cl::CommandQueue queue(context, default_device, CL_QUEUE_PROFILING_ENABLE);

    cl::Kernel kernel_to_run(program, "get_row");   
    kernel_to_run.setArg(0, d_C);
    kernel_to_run.setArg(1, IMG_WIDTH);
    kernel_to_run.setArg(2, IMG_HEIGHT);

    cl::Event evt;
    queue.enqueueNDRangeKernel(kernel_to_run, cl::NullRange, cl::NDRange(IMG_WIDTH, IMG_HEIGHT), cl::NDRange(10, 10), NULL, &evt);
    queue.finish();

    /* I think the problem is here. If I comment it out, the program
       will run fine, but I need the device information back to the
       host, though!
    */
    queue.enqueueReadBuffer(d_C, CL_TRUE, 0, sizeof(int) * IMG_WIDTH * IMG_HEIGHT, h_C);

    unsigned long elapsed = (unsigned long)(evt.getProfilingInfo<CL_PROFILING_COMMAND_END>() -
    evt.getProfilingInfo<CL_PROFILING_COMMAND_START>());
std::cout << " result: " << elapsed / (float)10e6 << " ms";

    queue.flush();
    queue.finish();
    delete &d_C;
}

内核,它只存储每个“像素”所属的全局行:

#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable
__kernel void get_row(__global int *out, int width, int height){

    int r = get_global_id(1);
    int c = get_global_id(0);

    if ((r >= height) || (c >= width))
        return; 

    int gIdx = r * width + c;

    out[gIdx] = r;

}

我做错了什么?对于 400 x 400,程序给我一个错误“进程因堆栈溢出异常而终止”

  • 我的“图像”尺寸对于总工作项大小来说是否太大(仅 400 x 400)?
  • 我选择了 100 (10 x 10) 的工作组大小,所以,我想我将有 1600 个工作组和 400 x 400。我认为工作组的数量没有限制,即使对于旧设备,还是有?
  • 可能我的主机代码顺序不正确。

对此的任何帮助表示赞赏。如果可能的话,我不想买新的显卡。我不想将我的图像分割成更小的矩形,然后将它们分成工作组。

我在 CUDA(在另一台机器上)中执行与上述相同的操作,图像大于 400 x 400 没有问题。

【问题讨论】:

    标签: c++ opencl gpu gpgpu


    【解决方案1】:

    您的变量h_C 消耗了大量的堆栈内存。堆栈内存非常有限。而不是使用堆栈变量,例如,

    int h_C[IMG_WIDTH * IMG_HEIGHT];
    

    使用 std::vector 之类的东西动态分配它:

    std::vector<int> h_C;
    h_C.resize(IMG_WIDTH * IMG_HEIGHT);
    ...
    queue.enqueueReadBuffer(d_C, CL_TRUE, 0, sizeof(int) * IMG_WIDTH * IMG_HEIGHT, h_C.data());
    

    【讨论】:

      猜你喜欢
      • 2014-09-06
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 2011-10-22
      • 2010-09-11
      • 1970-01-01
      • 2016-02-09
      相关资源
      最近更新 更多