iOS Metal 计算管道比搜索任务的 CPU 实现慢

Posted

技术标签:

【中文标题】iOS Metal 计算管道比搜索任务的 CPU 实现慢【英文标题】:iOS Metal compute pipeline slower than CPU implementation for search task 【发布时间】:2015-08-07 08:59:53 【问题描述】:

我做了一个简单的实验,通过实现简单的字符搜索算法在 CPU 和 GPU 上搜索 1.000.000 行,每行 50 个字符(50 百万字符映射)(使用 ios8 Metal 计算管道)。

CPU 实现使用简单循环,Metal 实现给每个内核 1 行来处理(源代码如下)。

令我惊讶的是,Metal 实现平均比简单的线性 CPU(如果我使用 1 个内核)慢 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)

我可以看到金属着色器花费了超过 90% 的内存访问(见下文)。

可以做些什么来优化它?

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

金属实施细节:

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

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

GPU 帧捕获分析结果:

【问题讨论】:

不要粘贴代码截图。它们基本上没用...剪切和粘贴实际代码。 @MarcB 我用 github gist 替换了屏幕截图。希望没问题(正确格式化那段代码有很大的麻烦)。 我尝试的第一件事是将 searchPhrase 移动到设备内存中。 Apple 表示不要为数组使用常量空间。让我们知道这是否有任何作用。 @Jessy :更改为设备空间没有任何改变。更重要的是:我失去了使用 setBytes 设置着色器缓冲区的机会:(Apple 声称它更快,因为您不必创建 对象)。 有趣。我想相关文件需要大修。谎言! 【参考方案1】:

GPU 着色器也在内存中垂直移动,而 CPU 则在水平方向移动。当您阅读 charTable 时,请考虑在着色器中以锁步方式执行的每个线程实际上或多或少同时接触的地址。如果您的 charTable 矩阵被转置,GPU 可能会运行得更快。

此外,由于此代码以 SIMD 方式执行,每个 GPU 线程可能必须将循环运行到完整的搜索短语长度,而 CPU 将利用早期输出。如果您删除早期输出并保持代码简单,GPU 代码实际上可能会运行得更快一些。很大程度上取决于搜索词组的长度和匹配的可能性。

【讨论】:

【参考方案2】:

我也会猜测一下,gpu 没有针对 if/else 进行优化,它不会预测分支(它可能会同时执行),尝试以更线性的方式重写算法,没有任何条件或减少它们最低限度。

【讨论】:

分析工具清楚地显示(在附加的屏幕截图中可见)这不是瓶颈。超过 90% 的时间都花在了内存访问上。

以上是关于iOS Metal 计算管道比搜索任务的 CPU 实现慢的主要内容,如果未能解决你的问题,请参考以下文章

在大纹理上渲染小纹理时,Metal 比 OpenGL 慢得多

METAL渲染是什么?

苹果的 Metal 工程

我如何与Metal沟通,以避免GPU和CPU之间的数据冲突

Java多进程管道通信

计算机的CPU怎么看?