我正在尝试构建基于 Halide 的图像处理算法,该算法在其中一个阶段需要 SGEMM 函数。
我发现 Halide 有两种矩阵乘法实现:
对于大小为 1024x1024 的矩阵:
首先,它们在 CPU (Intel i7) 和 Fermi GPU (GF 540M) 上运行得很好,CPU 时间接近 OpenBlas,Fermi GPU 时间接近 cuBlas(约 18ms),但此实现在 Maxwell 上比 cuBlas 慢 10 倍GPU (TitanX) - 5 毫秒与 0.4 毫秒。第二个实现 (cuda_mat_mul) 比 Fermi 上的 cuBlas 慢 3 倍 - 大约 57 毫秒 vs 18 毫秒,在 Maxwell GPU 上比 cuBlas 慢 2 倍 - 1 毫秒 vs 0.4 毫秒
正如我所见 - Halide 可以为 Fermi GPU 生成最佳代码,但无法在 Maxwell 上快速运行。据我所知,SGEMM 函数是许多具有正确调度的 FusedMultiplyAdd 函数,但我找不到任何可以使其在 Maxwell 上快速工作的最佳调度。
我能想象到的最快的 Halide 代码放置在 cuda_mat_mul 文件夹中,时间表是:
Func prod("prod");
RDom r(0, size);
prod(x, y) += A(x, r) * B(r, y);
Var xi, yi, xio, xii, yii, xo;
Func out = prod.in();
out.bound(x, 0, size)
.bound(y, 0, size)
.tile(x, y, xi, yi, 8*32, 8)
.split(xi, xio, xii, 32)
.reorder(xio, yi, xii, x, y)
.unroll(xio)
.unroll(yi)
.gpu_blocks(x, y).gpu_threads(xii);
prod.compute_at(out, xii)
.unroll(x)
.unroll(y)
.update()
.unroll(r.x, 2)
.reorder(y, x, r.x)
.unroll(x)
.unroll(y);
B.in()
.compute_at(prod, y)
.vectorize(B.in().args()[0])
;
Run Code Online (Sandbox Code Playgroud)
我也尝试过使用更大的矩阵(2048x2048) - 图片看起来相似:
基准测试代码来自 apps/cuda_mat_mul/runner.cpp,但将迭代计数从 10 更改为 100,以获得更精确的计时
如何更改时间表以使其与 TitanX 上的 cuBlas 性能接近?
更新:在 Ubuntu 16.4、LLVM 3.8、Halide 上进行测试 - 来自 git 的最新版本、Cuda 8
| 归档时间: |
|
| 查看次数: |
991 次 |
| 最近记录: |