18

我已经编写了几个复制函数来寻找 PowerPC 上的良好内存策略。将 Altivec 或 fp 寄存器与高速缓存提示 (dcb*) 结合使用,可将大数据的简单字节复制循环的性能提高一倍。最初对此感到满意,我扔了一个普通的 memcpy 来看看它的比较……比我最好的快 10 倍!我无意重写 memcpy,但我确实希望从中学习并加速几个简单的图像过滤器,这些过滤器大部分时间都在将像素移入和移出内存。

Shark 分析表明,它们的内部循环使用 dcbt 进行预取,先读取 4 次向量,然后写入 4 次向量。在将我最好的函数调整为每次迭代也可以传输 64 个字节之后,memcpy 的性能优势仍然令人尴尬。我正在使用 dcbz 来释放带宽,Apple 什么都不使用,但是这两种代码在商店中往往会犹豫不决。

预取
  未来
  dcbt 遥远的未来
加载东西
  lvx 图片
  lvx 图片 + 16
  lvx 图片 + 32
  lvx 图片 + 48
  图片 += 64
准备储存
  dcbz 过滤
  dcbz 过滤 + 32
存储东西
  stvxl 过滤
  stvxl 过滤 + 16
  stvxl 过滤 + 32
  stvxl 过滤 + 48
  过滤 += 64
重复

有没有人对为什么非常相似的代码有如此巨大的性能差距有一些想法?我很想在 memcpy 使用的任何秘密酱汁中腌制真实的图像过滤器!

附加信息:所有数据都是矢量对齐的。我正在制作图像的过滤副本,而不是替换原始图像。该代码在 PowerPC G4、G5 和 Cell PPU 上运行。Cell SPU 版本已经非常快了。

4

5 回答 5

7

Shark 分析表明,它们的内部循环使用 dcbt 进行预取,先读取 4 次向量,然后写入 4 次向量。在调整了我最好的函数之后,每次迭代也可以传输 64 个字节

我可能会说显而易见的,但是由于您在问题中根本没有提到以下内容,因此可能值得指出:

我敢打赌,Apple 选择读取 4 个向量,然后写入 4 个向量,这与G5 的管道及其对“调度组”中乱序指令执行的管理有很大关系,就像它与神奇的 64 字节完美指令一样线大小。您注意到 Nick Bastin 链接的 bcopy.s 中的换行了吗?这意味着开发人员考虑了 G5 将如何使用指令流。如果你想重现相同的性能,一次读取 64 个字节的数据是不够的,你必须确保你的指令组被很好地填充(基本上,我记得指令最多可以由五个独立的指令分组,与前四个是非跳转指令,第五个只允许跳转,细节比较复杂)。

编辑:您可能还对同一页面上的以下段落感兴趣:

dcbz 指令仍然按照 G4 和 G3 将对齐的 32 字节内存段归零。但是,由于这不是 G5 上的完整高速缓存行,因此它不会具有您可能希望的性能优势。G5 新引入了一条 dcbzl 指令,可将完整的 128 字节高速缓存行归零。

于 2010-01-02T02:49:33.360 回答
2

我不知道你在做什么,因为我看不到你的代码,但苹果的秘诀就在这里

于 2010-01-02T02:14:26.163 回答
0

也许是因为 CPU 缓存。尝试运行CacheGrind

Cachegrind 是一个缓存分析器。它对 CPU 中的 I1、D1 和 L2 缓存执行详细模拟,因此可以准确地查明代码中缓存未命中的来源。它通过每个函数、每个模块和整个程序的摘要来识别每行源代码执行的缓存未命中、内存引用和指令的数量。它对用任何语言编写的程序都很有用。Cachegrind 运行程序的速度比正常速度慢 20--100 倍。

于 2010-01-02T02:08:18.187 回答
0

正如另一个答案中提到的,Apple 在 G5 上定义的“dcbz”仅在 32 字节上运行,因此在具有 128 字节缓存线的 G5 上使用此指令将失去性能。您需要使用“dcbzl”来防止从内存中获取目标缓存线(并有效地将有用的读取内存带宽减少一半)。

于 2010-01-13T19:51:19.200 回答
0

仍然不是答案,但您是否确认 memcpy 实际上正在移动数据?也许它只是重新映射了写时复制。您仍然会在 Shark 中看到内部 memcpy 循环,因为第一页和最后一页的一部分被真正复制。

于 2010-01-02T06:56:41.350 回答