我正在尝试学习如何使 GPU 优化 OpenCL 内核,我以使用本地内存中的方形图块进行矩阵乘法为例。然而在最好的情况下,我只得到了约 10 倍的加速(约 50 Gflops)与 numpy.dot() 相比(5 Gflops,它使用的是 BLAS)。
我发现研究在哪里他们的加速比>200x(>1000 Gflops).
ftp://ftp.u-aizu.ac.jp/u-aizu/doc/Tech-Report/2012/2012-002.pdf ftp://ftp.u-aizu.ac.jp/u-aizu/doc/Tech-Report/2012/2012-002.pdf我不知道我做错了什么,或者只是因为我的 GPU ( nvidia GTX 275 )。或者如果是因为一些 pyOpenCl 开销。但我还测量了将结果从 GPU 复制到 RAM 需要多长时间,它只是矩阵乘法时间的 10% 左右。
#define BLOCK_SIZE 22
__kernel void matrixMul(
__global float* Cij,
__global float* Aik,
__global float* Bkj,
__const int ni,
__const int nj,
__const int nk
){
// WARRNING : interchange of i and j dimension lower the performance >2x on my nV GT275 GPU
int gj = get_global_id(0); int gi = get_global_id(1);
int bj = get_group_id(0); int bi = get_group_id(1); // Block index
int tj = get_local_id(0); int ti = get_local_id(1); // Thread index
int oj = bi*BLOCK_SIZE; int oi = bj*BLOCK_SIZE;
float Csub =0;
__local float As [BLOCK_SIZE][BLOCK_SIZE];
__local float Bs [BLOCK_SIZE][BLOCK_SIZE];
for (int ok = 0; ok < nk; ok += BLOCK_SIZE ) {
As[ti][tj] = Aik[ nk*(gi ) + tj + ok ]; // A[i][k]
Bs[ti][tj] = Bkj[ nj*(ti+ok) + gj ]; // B[k][j]
barrier(CLK_LOCAL_MEM_FENCE);
for (int k = 0; k < BLOCK_SIZE; ++k) Csub += As[ti][k] * Bs[k][tj];
barrier(CLK_LOCAL_MEM_FENCE);
}
Cij[ nj * ( gi ) + gj ] = Csub;
}
注意 - 奇怪的 BLOCK_SIZE=22 是最大 BLOCK_SIZE,它适合最大 work_group_size,在我的 GPU 上为 512。在此代码中必须保持条件 BLOCK_SIZE^2
我还尝试了简单的matrixMul(不使用本地内存),但它甚至比numpy.dot()慢10倍。
我在这里复制了代码http://gpgpu-computing4.blogspot.cz/2009/10/matrix-multiplication-3-opencl.html http://gpgpu-computing4.blogspot.cz/2009/10/matrix-multiplication-3-opencl.html他们说即使是简单版本(没有本地内存)的运行速度也应该比 CPU 快 200 倍?我不明白这一点。
在我的例子中,性能的依赖性是:
N = 220 numpy 3.680 [Gflops] GPU 16.428 [Gflops] speedUp 4.464
N = 330 numpy 4.752 [Gflops] GPU 29.487 [Gflops] speedUp 6.205
N = 440 numpy 4.914 [Gflops] GPU 37.096 [Gflops] speedUp 7.548
N = 550 numpy 3.849 [Gflops] GPU 47.019 [Gflops] speedUp 12.217
N = 660 numpy 5.251 [Gflops] GPU 49.999 [Gflops] speedUp 9.522
N = 770 numpy 4.565 [Gflops] GPU 48.567 [Gflops] speedUp 10.638
N = 880 numpy 5.452 [Gflops] GPU 44.444 [Gflops] speedUp 8.152
N = 990 numpy 4.976 [Gflops] GPU 42.187 [Gflops] speedUp 8.478
N = 1100 numpy 5.324 [Gflops] GPU 83.187 [Gflops] speedUp 15.625
N = 1210 numpy 5.401 [Gflops] GPU 57.147 [Gflops] speedUp 10.581
N = 1320 numpy 5.450 [Gflops] GPU 48.936 [Gflops] speedUp 8.979
注意 - “Gflops”数字是按 N^3/次获得的,它确实包括将结果从 GPU 复制到主内存所需的时间,但这个时间仅占总时间的百分之几,特别是对于 N>1000
也许更形象的是以秒为单位的时间:
N = 220 numpy 0.003 [s] GPU 0.001 [s] load 0.001 [s] speedUp 5.000
N = 330 numpy 0.008 [s] GPU 0.001 [s] load 0.001 [s] speedUp 7.683
N = 440 numpy 0.017 [s] GPU 0.002 [s] load 0.001 [s] speedUp 7.565
N = 550 numpy 0.043 [s] GPU 0.004 [s] load 0.001 [s] speedUp 11.957
N = 660 numpy 0.055 [s] GPU 0.006 [s] load 0.002 [s] speedUp 9.298
N = 770 numpy 0.100 [s] GPU 0.009 [s] load 0.003 [s] speedUp 10.638
N = 880 numpy 0.125 [s] GPU 0.010 [s] load 0.000 [s] speedUp 12.097
N = 990 numpy 0.195 [s] GPU 0.015 [s] load 0.000 [s] speedUp 12.581
N = 1100 numpy 0.250 [s] GPU 0.031 [s] load 0.000 [s] speedUp 8.065
N = 1210 numpy 0.328 [s] GPU 0.031 [s] load 0.000 [s] speedUp 10.581
N = 1320 numpy 0.422 [s] GPU 0.047 [s] load 0.000 [s] speedUp 8.979
我在想也许可以使用以下方法来提高速度
async_work_group_copy 甚至 read_imageui 将块复制到本地内存。但我不明白为什么当我使用与那些说他们有 200 倍加速的人基本相同的代码时我有这么大的差异???