2016-07-28 102 views
1

我已经使用OpenCL成功实现了数字下变换器。在实现插值部分时,我只能设置146的最大因子。任何一个都会导致程序崩溃并引发错误代码CL_INVALID_MEM_OBJECT -38使用太多内存的OpenCL程序

对于那些不知道的人来说,插值是一种在已知数据点范围内构建新数据点的方法。 DDC或数字下变频器用于在尝试通过重构滤波器重建数据点时增加或减少采样率。

请注意,我正在使用的文件是1.75Mb的wav文件作为输入。它的采样频率为44100,我的目标是以48000采样(蓝光质量)。这导致160/147的插值/抽取因子。但是,超过146的任何插值因素会导致驱动程序和程序崩溃,并且如上所示抛出-38的错误。

我认为问题在于我创建了cl_mem缓冲区。我大概有7个,这里是他们如何初始化和使用。假设P为3且Q是2,而项数是918222个样品:

input = clCreateBuffer(
    context, 
    CL_MEM_READ_ONLY, 
    num_items * sizeof(float), 
    NULL, 
    &status); 

output = clCreateBuffer(
    context, 
    CL_MEM_WRITE_ONLY, 
    num_items * P * sizeof(float), 
    NULL, 
    &status); 

//Lowpass kernel parameters 
inputForLowpass = clCreateBuffer(
    context, 
    CL_MEM_READ_ONLY, 
    num_items * P * sizeof(float), 
    NULL, 
    &status); 

outputFromLowpass = clCreateBuffer(
    context, 
    CL_MEM_READ_ONLY, 
    num_items * P * sizeof(float), 
    NULL, 
    &status); 

//Decimate kernel parameters 
inputForDecimate = clCreateBuffer(
    context, 
    CL_MEM_READ_ONLY, 
    num_items * P * sizeof(float), 
    NULL, 
    &status); 

outputFromDecimate = clCreateBuffer(
    context, 
    CL_MEM_READ_ONLY, 
    (int)(num_items * (P*1.0/Q) * sizeof(float)), 
    NULL, 
    &status); 

//numOfCoefficients for number of taps 
coeff = clCreateBuffer(
    context, 
    CL_MEM_READ_ONLY, 
    numOfCoefficients * sizeof(float), 
    NULL, 
    &status); 

我用在Visual Studio中存储器调试器来找到程序使用602Mb(为160的内插因子之前它崩溃它用于围绕120MB。为3的因素,仍然很多!)我怎么能把这个下降?我是否以不正确的方式使用缓冲区?

最重要的是,我有三个主机代码中的其他内存分配。 'Array'只是保存wav文件中的值,而OutputData和OutputData2分别存储来自过滤输入和抽取输入的值。

Array = (float*)malloc(num_items * sizeof(float)); 
OutputData = (float*)malloc(num_items * P * sizeof(float)); 
OutputData2 = (float*)malloc((int)(num_items * (P*1.0/Q) * sizeof(float))); 

以下是Visual Studio中P = 3时的内存使用情况(数组增加3的大小)。

enter image description here

这里就是我得到的-38码writeBuffers之一。

status = clEnqueueWriteBuffer(
    cmdQueue, 
    inputForLowpass, 
    CL_FALSE, 
    0, 
    num_items * P * sizeof(float), 
    OutputData, 
    0, 
    NULL, 
    NULL); 
printf("Input enqueueWriteBuffer for Lowpass Kernel status: %i \n", status); 

这里是低通内核:

__kernel void lowpass(__global float *Array, __global float *coefficients, __global float *Output, __const int numOfCoefficients) { 

    int globalId = get_global_id(0); 
    float sum=0.0f; 
    int min_i= max((numOfCoefficients-1),globalId)-(numOfCoefficients-1); 
    int max_i= min_i+numOfCoefficients; 
    for (int i=min_i; i< max_i; i++) 
    { 
     sum +=Array[i]*coefficients[globalId-i];  
    } 
    //sum = min(., (0.999969482421875)); 
    //sum = max(sum, -1.0f); 
    Output[globalId]=sum; 

}

EDIT发生 错误,因为缓冲区大小我分配有超过所使用的存储器的512Mb。这是我可以拥有的最大缓冲区大小。为了解决这个问题,我必须在我的代码中实现某种内存管理系统。也许一次使用8Mb缓冲区。

+0

你能告诉我们你写入这些缓冲区的位置以及你调用内核的地方吗? (并且清理代码也可能是个好主意)'CL_INVALID_MEM_OBJECT'我认为不会被'clCreateBuffer'抛出。 – JavaProphet

+0

@JavaProphet我已经添加了writeBuffer以及内核。它也为decimate内核抛出相同的错误。我会尝试添加发生错误时输出的日志消息。 – VedhaR

回答

0

你的记忆对象没有明确的任何支持,这可能是你的问题。我建议把一个标志添加从

https://www.khronos.org/registry/cl/sdk/1.1/docs/man/xhtml/clCreateBuffer.html

CL_MEM_USE_HOST_PTRCL_MEM_COPY_HOST_PTR,或CL_MEM_ALLOC_HOST_PTR,然后指定主机指针。如果使用CL_MEM_USE_HOST_PTR,那么如果主机内存中的缓冲区不会再次分配给主机,那么如果它只是内存使用情况,可能会帮助您解决问题。

+0

所以我试着用'CL_MEM_COPY_HOST_PTR'来处理你的方法,看起来性能很慢。我首先尝试了它的输入缓冲区,并注意到Interpolate内核跳了13ms。然后,当我尝试输出缓冲区相同,程序崩溃。内插内核只是一个简单的内核,它在给定输入数组的每个'n'位置添加一个元素。 – VedhaR

+0

@VedhaR我不推荐'CL_MEM_COPY_HOST_PTR',但是'CL_MEM_USE_HOST_PTR'。 – JavaProphet

+0

对不起,这就是我的意思,我用'CL_MEM_USE_HOST_PTR',我只是把它错误地复制到这里的框中 – VedhaR