带记忆合并的OpenCl矩阵转置

带记忆合并的OpenCl矩阵转置,opencl,gpu,coalescing,Opencl,Gpu,Coalescing,我目前正试图在OpenCl中转置一个带有内存合并的矩阵 我已经用一种“简单”的方式转换了矩阵,效果非常好。当我现在尝试使用内存合并做同样的事情时,我希望看到执行时间有一点改进,但是我的实现实际上比简单的实现慢(实现是正确的,只是效率不高)。我想我还没有完全理解如何确保水平相邻的工作项写在水平相邻的地址上 以下是我的coalised实现的内核: __kernel void MatrixTranspose(__global const float* Matrix, __global float*

我目前正试图在OpenCl中转置一个带有内存合并的矩阵

我已经用一种“简单”的方式转换了矩阵,效果非常好。当我现在尝试使用内存合并做同样的事情时,我希望看到执行时间有一点改进,但是我的实现实际上比简单的实现慢(实现是正确的,只是效率不高)。我想我还没有完全理解如何确保水平相邻的工作项写在水平相邻的地址上

以下是我的coalised实现的内核:

__kernel void MatrixTranspose(__global const float* Matrix, 
__global float* MatrixTransposed, uint Width, uint Height, __local float* block) {

    int2 GlobalID;
    GlobalID.x = get_global_id(0);
    GlobalID.y = get_global_id(1);

    int2 LocalID;
    LocalID.x = get_local_id(0);
    LocalID.y = get_local_id(1);

    block[LocalID.y*get_local_size(0) + LocalID.x] = Matrix[GlobalID.y*Width + GlobalID.x];

    barrier(CLK_LOCAL_MEM_FENCE);

    int2 groupId;
    groupId.x = get_group_id(0);
    groupId.y = get_group_id(1);
    int2 localSize;
    localSize.x = get_local_size(0);
    localSize.y = get_local_size(1);
    MatrixTransposed[Height*(LocalID.x + groupId.x*localSize.x) + Height - (LocalID.y + groupId.y*localSize.y) - 1] = block[LocalID.y*localSize.x + LocalID.x];
}

我希望有人能给我一个建议,谢谢:)

从原始矩阵中读取列,将它们作为行写入本地内存以避免内存库冲突,然后将本地内存中的行存储到转置矩阵中

在这种情况下,两个写入操作很容易合并(相邻的工作项写入相邻的内存单元)。然而,读取操作并不那么好


顺便问一下,你的设备是什么?如果向量操作很好,使用vload/vstore操作,可能会显著提高IO性能。

不幸的是,您将受到设备全局读写速度的限制。通常情况下,您可以转置矩阵进行一些计算,这有助于隐藏延迟。在您的示例中,您正在读取本地内存,等待屏障,并将黑色写入全局。这只会增加使用本地内存的额外步骤和复杂性

如果要隐藏全局内存延迟,则应该在数据位于本地内存时对其进行处理

如果您只想转置矩阵,只需从全局读取并直接写入全局中的目标位置即可。如果您仍然想尝试使用本地内存,可以查看异步工作组拷贝

现在我来回答

尝试使一个工作项负责多个浮动。如果读取带有工作项的4x4区域,则可以在专用内存中对其进行转置。这不仅可以跳过本地内存,还可以消除对屏障的需求,并将所需工作项的数量减少16倍

步骤:

  • 计算src和dest全局内存地址
  • 从全局加载四个float4值
  • 通过相应地交换其w、x、y、z值来转换4x4浮动
  • 在全局内存中的新位置存储4个float4值
  • 在单独的内核中处理矩阵的边缘区域,或在主机程序中处理非四维矩阵的边缘区域(或填充输入矩阵使其为4的倍数)

“不幸的是,您将受到设备的全局读写速度的限制。通常您会转置矩阵以进行一些计算”-这是正确的。大多数标准BLAS库甚至不显式转置矩阵,而是提供“标志”,指示是否应将矩阵解释为转置。然后,他们可能会使用一个完全不同的内核来读取这个矩阵,它不是按列主顺序,而是按行主顺序(反之亦然)。据我所知,在这个简单的实现中,每个工作项都会顺序写入全局内存,而在coalisced实现中,可以在一个步骤中执行几个写入操作。执行时间不应该还有一点提高吗?是的,但是如果顺序写入恰好相邻,那么内存将免费聚合。内存控制器将同时写入多个浮点(通常为4个,但取决于管道宽度)。同样的想法也适用于阅读:不管怎样,你要阅读4个值,这只是你想扔掉多少个值的问题——以后可能会重新阅读。