优化矩阵乘法OpenCL - 目的:学习如何管理内存

时间:2014-10-20 14:15:37

标签: matrix opencl gpu

我是OpenCL的新手,并试图了解如何优化矩阵乘法以熟悉各种范例。这是当前的代码。 如果我正在混合矩阵A和B.我在私有内存中分配一行A(因为每个工作项使用它),并在本地内存中分配一列B(因为每个工作组使用它)。

1)代码目前不正确,遗憾的是我在如何使用本地工作ID来获取正确的代码方面苦苦挣扎,但我无法找到错误?我基于http://www.cs.bris.ac.uk/home/simonm/workshops/OpenCL_lecture3.pdf,但是(幻灯片27)似乎这是错误的,因为他们没有在内部循环中使用loc_size)

2)您对此代码有什么其他优化建议吗?

 __kernel void mmul(
  __global int* C,
 __global int* A, 
 __global int* B,
   const int rA, 
   const int rB,
   const int cC, 
   __local char* local_mem) 
{ 
   int k,ty; 
   int tx = get_global_id(0); 
   int loctx = get_local_id(0); 
   int loc_size = get_local_size(0);
   int value = 0 ;
   int tmp_array[1000]; 
   for(k=0;k<rB;k++) { 
     tmp_array[k] = A[tx * cA + k] ;
   } 
   for (ty=0 ; ty < cC ; ty++) { \n" \
     for (k = loctx ; k < rB ; k+=loc_size) { 
         local_mem[k] = B[ty + k * cC] ;
     }
      barrier(CLK_LOCAL_MEM_FENCE); 
       value = 0 ; 
       for(k=0;k<rB;k+=1) {
           int i = loctx + k*loc_size;
           value += tmp_array[k] * local_mem[i]; 
     } 
   C[ty + (tx * cC)] = value; 
 } 
} 

我将全局和本地工作项设置如下

const size_t globalWorkItems[1] = {result_row};
const size_t localWorkItems[1] = {(size_t)local_wi_size};

local_wi_size是result_row /计算单位数(使得result_row%计算单位== 0)

1 个答案:

答案 0 :(得分:2)

您的代码非常接近,但您认为对本地内存数组的索引实际上更简单。私有内存中有一行,本地内存中有一列,您需要计算这两个向量的点积。您只需将row[k]*col[k]k = 0相加N-1

for(k=0;k<rB;k+=1) {
    value += tmp_array[k] * local_mem[k]; 
}

实际上,在您使用的幻灯片上给出的示例解决方案中也存在第二个更微妙的错误。由于您在循环内部读取和写入本地内存,因此实​​际上需要两个障碍,以确保在迭代i上写入本地内存的工作项不会覆盖值正在执行迭代i-1的其他工作项读取的内容。

因此,内核的完整代码(经过测试和运行)应该如下所示:

__kernel void mmul(
  __global int* C,
  __global int* A,
  __global int* B,
     const int rA,
     const int rB,
     const int cC,
  __local char* local_mem)
{
  int k,ty;
  int tx = get_global_id(0);
  int loctx = get_local_id(0);
  int loc_size = get_local_size(0);
  int value = 0;
  int tmp_array[1000];
  for(k=0;k<rB;k++) {
    tmp_array[k] = A[tx * cA + k] ;
  }
  for (ty=0 ; ty < cC ; ty++) {

    for (k = loctx ; k < rB ; k+=loc_size) {
      local_mem[k] = B[ty + k * cC];
    }
    barrier(CLK_LOCAL_MEM_FENCE); // First barrier to ensure writes have finished

    value = 0;
    for(k=0;k<rB;k+=1) {
      value += tmp_array[k] * local_mem[k];
    }
    C[ty + (tx * cC)] = value;

    barrier(CLK_LOCAL_MEM_FENCE); // Second barrier to ensure reads have finished
  }
}

您可以在HandsOnOpenCL GitHub page上找到与您正在查看的幻灯片一起使用的全套练习和解决方案。还有来自同一教程here的更完整的幻灯片集,这些幻灯片继续显示更加优化的矩阵乘法示例,该示例使用阻塞方法来更好地利用时间和空间局部性。上述缺失的障碍错误已在示例解决方案代码中修复,但尚未在幻灯片中修复。