我的OpenCL内核出了问题。我正在努力做Runge-Kutta 4整合。我已经在OpenGL计算着色器中实现了它,它可以工作,现在我想在OpenCL中实现它。
我认为我的问题与不知道如何在我的所有函数调用中正确共享全局数组的单个实例有关,因为现在我必须将指针发送到数组作为每个函数的参数调用,在我看来,这实际上在这些函数中创建了一个本地副本,因为我当前的实现适用于小数据集但不适用于大数据集(它们抛出CL_OUT_OF_RESOURCES)。
在我的计算着色器中,我声明了所有的全局数组:
layout(std430, binding=0) buffer pblock { coherent volatile restrict vec4 mcPosition[]; };
layout(std430, binding=1) buffer vblock { coherent volatile restrict vec4 mcVelocity[]; };
我可以在我的功能中使用它们:
vec4 calculateAcceleration(int numPoints, int step, ...) {...}
void rk4Step(int numPoints, int index, float timeStepToUse, ...) {...}
void calculateError(int index) {...}
但是在OpenCL实现中,我知道如何做的唯一方法是这样的(非常简洁的例子):
void rk4Step(
const __constant int* numPoints,
const int index,
const float timeStepToUse,
const bool calculateHalfTimeStep,
const __constant float* squaredSofteningFactor,
const __constant float* gravitationalConstant,
__global float4* kvel,
__global float4* dydx,
__global float4* kpos,
__global float4* mcPositionHalf,
__global float4* mcVelocityHalf,
__global float4* mcPositionFull,
__global float4* mcVelocityFull
)
{
...
// Actual time step
if(!calculateHalfTimeStep)
{
mcVelocityFull[index] += (kvel[index] + (2.0f*kvel[index+numPoints[0]]) + (2.0f*kvel[index+numPoints[0]*2]) + kvel[index+numPoints[0]*3]) * (1.0f/6.0f);
mcPositionFull[index] += (kpos[index] + (2.0f*kpos[index+numPoints[0]]) + (2.0f*kpos[index+numPoints[0]*2]) + kpos[index+numPoints[0]*3]) * (timeStepToUse/6.0f);
}
else
{
mcVelocityHalf[index] += (kvel[index] + (2.0f*kvel[index+numPoints[0]]) + (2.0f*kvel[index+numPoints[0]*2]) + kvel[index+numPoints[0]*3]) * (1.0f/6.0f);
mcPositionHalf[index] += (kpos[index] + (2.0f*kpos[index+numPoints[0]]) + (2.0f*kpos[index+numPoints[0]*2]) + kpos[index+numPoints[0]*3]) * (timeStepToUse/6.0f);
}
}
void calculateError(const int index, __global float4* scale)
{
float partialError = 0.0f;
partialError = fmax(partialError, fabs(deltaPos[index].x / scale[index].x));
}
// Adaptive step 4th order Runge-Kutta
__kernel
void main( const __constant float* timeStep, const __constant float* accuracy, const __constant int* maxSteps,
__global float4* mcPosition, __global float4* mcVelocity, __global float4* scale)
{
// Scaling used to monitor accuracy
scale[index] = calculateAcceleration(bi, index, numPoints, 1, false,
squaredSofteningFactor, gravitationalConstant,
mcPositionHalf, mcPositionFull, kvel);
scale[index] = fabs(mcVelocity[index]) + fabs(scale[index] * timeStep[0]);
for(int step=1; step<=maxSteps[0]; ++step)
{
// Take two half steps
rk4Step(numPoints, index, timeStep[0], true,
squaredSofteningFactor, gravitationalConstant,
mcPosition, mcVelocity);
rk4Step(numPoints, index, timeStep[0], true,
squaredSofteningFactor, gravitationalConstant,
mcPosition, mcVelocity);
// Take one full step
timeStep[0] *= 2.0f;
rk4Step(numPoints, index, timeStep[0], false,
squaredSofteningFactor, gravitationalConstant,
mcPosition, mcVelocity);
// Evaluate accuracy
calculateError(index, accuracy, scale, deltaPos);
}
}
您可以注意到,不同之处在于,在计算着色器版本中,我可以在文件顶部声明共享的全局数组,并在我的任何一个函数中使用它们。
但是在OpenCL内核版本中,我必须将这些数组作为每个函数调用的参数传递,对于大型数据集,这会给我一个CL_OUT_OF_RESOURCES错误。
我认为我的问题与以下事实有关:即使我声明数组是全局的,每个函数调用都会尝试制作数组的本地副本,但也许我错了。我通过阅读文档来假设这一点,这个问题指出了同样的事情:
所以我的问题是: 如何在用户定义的函数和我的OpenCL内核之间真正共享全局数组?
答案 0 :(得分:1)
您提到的数组作为指针传递,没有理由期望整个数组的本地副本,还有__constant参数可以停止写入,并且副本也是__constant是只读的。无本地拷贝的主要原因可能是没有堆栈的gpu-opencl实现。人们编写假堆栈来实现虚假递归,但即使这样也不能大于主机代码中定义的大小。
你什么时候得到“CL_OUT_OF_RESOURCES”?更改__constant缓冲区大小或__global大小后?通常__constant每个GPU只有50-100 kB,而__global可以大到每个缓冲区每个gpu的1/4视频内存。偶数个__常量参数是有限的。您可以将多个常量数组连接成单个常量数组以消除它。查询常量和全局的常量内存限制。使用CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE从clGetDeviceInfo开始。
其他情况:
堆碎片---&gt;没有大阵容。只有较小的可以分配为缓冲区。您是否正在发送使用所有vram(或常量vram)的并发内核?
本地工作组的大小比设备大(例如:amd在gpu上有256,nvidia有1024)(至少它是全局大小的分隔符)
标量寄存器太多,每个线程或每个smx / cu的矢量寄存器太多。
测试:
帮助: