Access/synchronization 到本地内存
Access/synchronization to local memory
我对 GPGPU 编程还很陌生。我正在尝试实现需要大量同步的算法,因此它只使用一个工作组(全局和局部大小具有相同的值)
我有一个休闲问题:我的程序在问题大小超过 32 之前一直运行正常。
__kernel void assort(
__global float *array,
__local float *currentOutput,
__local float *stimulations,
__local int *noOfValuesAdded,
__local float *addedValue,
__local float *positionToInsert,
__local int *activatedIdx,
__local float *range,
int size,
__global float *stimulationsOut
)
{
int id = get_local_id(0);
if (id == 0) {...}
barrier(CLK_LOCAL_MEM_FENCE);
for (int i = 2; i < size; i++)
{
int maxIdx;
if (id == 0)
{
addedValue[0] = array[i];
{...}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (id < noOfValuesAdded[0]){...}
else
barrier(CLK_LOCAL_MEM_FENCE);
barrier(CLK_LOCAL_MEM_FENCE);
if (activatedIdx[0] == -2) {...}
else {...}
barrier(CLK_LOCAL_MEM_FENCE);
if (positionToInsert[0] != -1.0f) {...}
barrier(CLK_LOCAL_MEM_FENCE);
stimulationsOut[id] = addedValue[0];
return;
}
经过一些调查尝试,我意识到(通过检查 stimulationsOut),addedValue[0] 与内核的第 33 个实例有不同的值,然后是第 65 个实例的另一个值(所以它像 [123 123 123 ... 123(第 33 个元素)66 ... 66 66 66 66 66 ..(第 65 个元素)127 ... .. 127 ...])
__global float *array 是 READ_ONLY 并且我不会在 for 循环中更改 first 旁边的 addedValue[0] 。是什么导致了这个问题?
我的 GPU 规格:[https://devtalk.nvidia.com/default/topic/521502/gt650m-a-kepler-part-/]
注释掉两个if的body问题后没有再出现:
/*if (activatedIdx[0] == -2)
{
if (noOfValuesAdded[0] == 2)
{
positionToInsert[0] = 0.99f;
}
else if (id != 0 && id != maxIdx
&& stimulations[id] >= stimulations[(id - 1)]
&& stimulations[id] >= stimulations[(id + 1)])
{
if ((1.0f - (fabs((currentOutput[(id - 1)] - currentOutput[id])) / range[0])) < stimulations[(id - 1)])
positionToInsert[0] = (float)id - 0.01f;
else
positionToInsert[0] = (float)id + 0.99f;
}
}*/
和
if (positionToInsert[0] != -1.0f)
{
float temp = 0.0f;
/*if ((float)id>positionToInsert[0])
{
temp = currentOutput[id];
barrier(CLK_LOCAL_MEM_FENCE);
currentOutput[id + 1] = temp;
}
else
{
barrier(CLK_LOCAL_MEM_FENCE);
}*/
barrier(CLK_LOCAL_MEM_FENCE);
if (id == round(positionToInsert[0]))
{
currentOutput[id] = addedValue[0];
noOfValuesAdded[0] = noOfValuesAdded[0] + 1;
}
}
更新:
修复障碍后,算法正常工作,直到大小超过 768(这奇怪地是我的 gpu 核心数量的 2 倍)。我原以为它最多可以处理 1024 个元素,这是最大工作组大小。我错过了什么吗?
warp 中的所有工作项都以锁步方式执行相同的指令。 Nvidia 上的 Warp 大小是 32 个工作项。如果内核最多可正确运行 32 个工作项,则表明障碍存在问题。
barrier 的文档说:
All work-items in a work-group executing the kernel on a processor
must execute this function before any are allowed to continue
execution beyond the barrier.
我可以看出这是您内核中的问题。例如这里:
if ((float)id>positionToInsert[0])
{
temp = currentOutput[id];
barrier(CLK_LOCAL_MEM_FENCE); // <---- some work items may meet here
currentOutput[id + 1] = temp;
}
else
{
barrier(CLK_LOCAL_MEM_FENCE); // <---- other work items may meet here
}
您可以通过以下方式解决此问题:
if ((float)id>positionToInsert[0])
temp = currentOutput[id];
barrier(CLK_LOCAL_MEM_FENCE); // <---- here all work items meet at the same barrier
if ((float)id>positionToInsert[0])
currentOutput[id + 1] = temp;
修复障碍后,算法可以正常工作,直到大小超过 768(这奇怪地是我的 GPU 核心数量的 2 倍)。我原以为它最多可以处理 1024 个元素,这是最大工作组大小。我错过了什么吗?
我对 GPGPU 编程还很陌生。我正在尝试实现需要大量同步的算法,因此它只使用一个工作组(全局和局部大小具有相同的值)
我有一个休闲问题:我的程序在问题大小超过 32 之前一直运行正常。
__kernel void assort(
__global float *array,
__local float *currentOutput,
__local float *stimulations,
__local int *noOfValuesAdded,
__local float *addedValue,
__local float *positionToInsert,
__local int *activatedIdx,
__local float *range,
int size,
__global float *stimulationsOut
)
{
int id = get_local_id(0);
if (id == 0) {...}
barrier(CLK_LOCAL_MEM_FENCE);
for (int i = 2; i < size; i++)
{
int maxIdx;
if (id == 0)
{
addedValue[0] = array[i];
{...}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (id < noOfValuesAdded[0]){...}
else
barrier(CLK_LOCAL_MEM_FENCE);
barrier(CLK_LOCAL_MEM_FENCE);
if (activatedIdx[0] == -2) {...}
else {...}
barrier(CLK_LOCAL_MEM_FENCE);
if (positionToInsert[0] != -1.0f) {...}
barrier(CLK_LOCAL_MEM_FENCE);
stimulationsOut[id] = addedValue[0];
return;
}
经过一些调查尝试,我意识到(通过检查 stimulationsOut),addedValue[0] 与内核的第 33 个实例有不同的值,然后是第 65 个实例的另一个值(所以它像 [123 123 123 ... 123(第 33 个元素)66 ... 66 66 66 66 66 ..(第 65 个元素)127 ... .. 127 ...])
__global float *array 是 READ_ONLY 并且我不会在 for 循环中更改 first 旁边的 addedValue[0] 。是什么导致了这个问题?
我的 GPU 规格:[https://devtalk.nvidia.com/default/topic/521502/gt650m-a-kepler-part-/]
注释掉两个if的body问题后没有再出现:
/*if (activatedIdx[0] == -2)
{
if (noOfValuesAdded[0] == 2)
{
positionToInsert[0] = 0.99f;
}
else if (id != 0 && id != maxIdx
&& stimulations[id] >= stimulations[(id - 1)]
&& stimulations[id] >= stimulations[(id + 1)])
{
if ((1.0f - (fabs((currentOutput[(id - 1)] - currentOutput[id])) / range[0])) < stimulations[(id - 1)])
positionToInsert[0] = (float)id - 0.01f;
else
positionToInsert[0] = (float)id + 0.99f;
}
}*/
和
if (positionToInsert[0] != -1.0f)
{
float temp = 0.0f;
/*if ((float)id>positionToInsert[0])
{
temp = currentOutput[id];
barrier(CLK_LOCAL_MEM_FENCE);
currentOutput[id + 1] = temp;
}
else
{
barrier(CLK_LOCAL_MEM_FENCE);
}*/
barrier(CLK_LOCAL_MEM_FENCE);
if (id == round(positionToInsert[0]))
{
currentOutput[id] = addedValue[0];
noOfValuesAdded[0] = noOfValuesAdded[0] + 1;
}
}
更新: 修复障碍后,算法正常工作,直到大小超过 768(这奇怪地是我的 gpu 核心数量的 2 倍)。我原以为它最多可以处理 1024 个元素,这是最大工作组大小。我错过了什么吗?
warp 中的所有工作项都以锁步方式执行相同的指令。 Nvidia 上的 Warp 大小是 32 个工作项。如果内核最多可正确运行 32 个工作项,则表明障碍存在问题。
barrier 的文档说:
All work-items in a work-group executing the kernel on a processor must execute this function before any are allowed to continue execution beyond the barrier.
我可以看出这是您内核中的问题。例如这里:
if ((float)id>positionToInsert[0])
{
temp = currentOutput[id];
barrier(CLK_LOCAL_MEM_FENCE); // <---- some work items may meet here
currentOutput[id + 1] = temp;
}
else
{
barrier(CLK_LOCAL_MEM_FENCE); // <---- other work items may meet here
}
您可以通过以下方式解决此问题:
if ((float)id>positionToInsert[0])
temp = currentOutput[id];
barrier(CLK_LOCAL_MEM_FENCE); // <---- here all work items meet at the same barrier
if ((float)id>positionToInsert[0])
currentOutput[id + 1] = temp;
修复障碍后,算法可以正常工作,直到大小超过 768(这奇怪地是我的 GPU 核心数量的 2 倍)。我原以为它最多可以处理 1024 个元素,这是最大工作组大小。我错过了什么吗?