iOS的Metal计算流水线在搜索任务方面比CPU实现慢

12

我做了一个简单的实验,通过实现朴素字符搜索算法在CPU和GPU上(使用iOS8的Metal计算管道)搜索1,000,000行每行50个字符的简单数据(共5,000万个字符映射)。

CPU实现使用简单循环,Metal实现为每个内核提供1行进行处理(以下是源代码)。

令我惊讶的是,如果我只使用1个核心,那么平均而言,Metal实现比简单的线性CPU慢2-3倍;如果我使用2个核心(每个核心搜索一半数据库),则慢3-4倍!我尝试了不同的线程组(16、32、64、128、512),但仍然得到非常相似的结果。

iPhone 6:

CPU 1 core:  approx 0.12 sec
CPU 2 cores: approx 0.075 sec
GPU: approx 0.35 sec (relEase mode, validation disabled)

我可以看到Metal着色器使用超过90%的时间来访问内存(见下文)。

有什么优化的方法吗?

任何见解都将不胜感激,因为互联网上没有太多来源(除了标准的Apple编程指南),提供有关Metal框架特定的内存访问内部和权衡的详细信息。

METAL实现细节:

主机代码要点:https://gist.github.com/lukaszmargielewski/0a3b16d4661dd7d7e00d

内核(着色器)代码:https://gist.github.com/lukaszmargielewski/6b64d06d2d106d110126

GPU帧捕获分析结果:

enter image description here


11
不要粘贴代码截图,它们基本上没有用...请复制并粘贴实际的代码。 - Marc B
@MarcB 我用 Github Gist 替换了截图。希望这样可以(我在格式化那一大块代码时遇到了很大的麻烦)。 - Lukasz
我会尝试的第一件事是将searchPhrase移动到设备内存中。苹果公司建议不要为数组使用常量空间。如果有任何效果,请告诉我们。 - user652038
1
@Jessy:切换到设备空间没有改变任何东西。更重要的是:我失去了使用setBytes:设置着色器缓冲区的机会(苹果声称这样做更快,因为您不必创建<MTLBuffer>对象)。 - Lukasz
有趣。我猜相关的文档需要进行彻底改进。谎言! - user652038
显示剩余4条评论
2个回答

4
GPU着色器在内存中垂直跨越,而CPU则水平移动。当您阅读charTable时,请考虑每个线程以锁步方式执行时实际上同时触及的地址。如果您的charTable矩阵转置,则GPU可能会运行得更快。
此外,由于此代码以SIMD方式执行,因此每个GPU线程可能必须将循环运行到完整的搜索短语长度,而CPU将获得利用提前退出的机会。如果您删除早期退出并保持代码简单,则GPU代码实际上可能会运行得更快。这在很大程度上取决于搜索短语的长度和匹配的可能性。

0

我也猜一下,GPU并不适用于if/else条件语句,它无法预测分支(可能会同时执行两个分支),尝试以更线性的方式重写算法,避免使用条件语句或将其减少到最少。


性能分析工具清楚地显示(如附图所示),这不是瓶颈。超过90%的时间用于内存访问。 - Lukasz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接