我在OpenCL中完成了一个Window Function内核。基本上,窗口函数只是将一组系数分别应用于另一组数字(维基百科更好地解释了它)。在大多数情况下,我能够将窗口系数浮点数填充到常量缓存中。
我期望Compute Prof的结果表明,托管内存传输的设备和设备的主机将占用超过95%的处理时间。对于我的几乎所有情况,它只占处理时间的80%。我正在编写和读取一个420万个浮动数组进出电路板并编写另一个浮点数组,通常保持在一百万以下。
内核中的任何内容看起来都很可疑吗?关于它是否应该在GPU上比在CPU上运行得更快的问题的任何意见(我仍然不是100%)。我有点惊讶于为什么我的gld_efficiency和gst_efficiency悬停在0.1和0.2之间。我在考虑G80全局内存的情况下制作了这个内核。我的全局内存整体吞吐量似乎还不错,只有40gbs。内核非常简单,发布在下面。
__kernel void window(__global float* inputArray, // first frame to ingest starts at 0. Sized to nFramesToIngest*framesize samples
__constant float* windowArray, // may already be partly filled
int windowSize, // size of window frame, in floats
int primitivesPerDataFrame, //amount of primitives in each frame of inputArray parameter
int nInFramesThisCall, //each thread solves a frame, so this integer represent how many threads this kernel launches
int isRealNumbers //0 for complex, non-zero for real
)
{
int gid = get_global_id(0) + get_global_size(0) * get_global_id(1);
if(gid < nInFramesThisCall) //make sure we don't execute unnecessary threads
{
if(isRealNumbers)
{
for(int i = 0; i < primitivesPerDataFrame; i++)
{
int inputArrayIndex = (gid*primitivesPerDataFrame)+i;
inputArray[inputArrayIndex] = inputArray[inputArrayIndex] * windowArray[i%windowSize];
}
}
else //complex
{
for(int i = 0; i < primitivesPerDataFrame; i++)
{
int inputArrayIndex = (gid*primitivesPerDataFrame)+i;
inputArray[inputArrayIndex] = inputArray[inputArrayIndex] * windowArray[i%windowSize/2];
}
}
}
}
答案 0 :(得分:1)
你使用了多少个线程(OpenCL术语是工作项)?至少需要几百个才能有效地加载大型GPU。
你说你想要使用合并的内存访问,但是使用像
这样的偏移量int inputArrayIndex = (gid*primitivesPerDataFrame)+i;
在大多数情况下,不会使这成为可能。 NVidia的G80在合并时有相当严格的限制,有关详细信息,请参阅“OpenCL最佳实践指南”。基本上,来自一个warp的工作项必须同时以某种方式访问64或128字节对齐块的元素,以使加载和存储发生合并。
或者举个例子:如果primitivesPerDataFrame
为16,则扭曲的加载和存储是在间隔16个元素的偏移处完成的,这使得任何有效的合并都不可能。