iOS - 使用 Accelerate.framework 对向量进行按位异或
Posted
技术标签:
【中文标题】iOS - 使用 Accelerate.framework 对向量进行按位异或【英文标题】:iOS - bitwise XOR on a vector using Accelerate.framework 【发布时间】:2014-01-04 15:14:54 【问题描述】:我正在尝试在预定值和数组的每个元素之间执行bitwise XOR
。
这显然可以在这样的循环中完成(在伪代码中):
int scalar = 123;
for(int i = 0; i < VECTOR_LENGTH; i++)
int x_or = scalar ^ a[i];
但我开始通过使用Accelerate.framework
了解性能增强。
我正在查看Accelerate.framework
的文档,但我还没有看到基于bitwise XOR
的元素。 有人知道这是否可行吗?
【问题讨论】:
【参考方案1】:Accelerate 不会执行相关操作。但是,您可以很容易地编写自己的矢量代码来做到这一点。曾经不错的方法是使用 clang 矢量扩展:
#include <stddef.h>
typedef int vint8 __attribute__((ext_vector_type(8),aligned(4)));
typedef int vint4 __attribute__((ext_vector_type(4),aligned(4)));
typedef int vint2 __attribute__((ext_vector_type(2),aligned(4)));
int vector_xor(int *x, size_t n)
vint8 xor8 = 0;
while (n >= 8)
xor8 ^= *(vint8 *)x;
x += 8;
n -= 8;
vint4 xor4 = xor8.lo ^ xor8.hi;
vint2 xor2 = xor4.lo ^ xor4.hi;
int xor = xor2.lo ^ xor2.hi;
while (n > 0)
xor ^= *x++;
n -= 1;
return xor ^ 123;
这非常好,因为 (a) 它不需要使用内在函数,并且 (b) 它不会将您绑定到任何特定架构。它为您编译的任何架构生成相当不错的代码。另一方面,它将您与clang
联系在一起,而如果您使用内在函数,您的代码也可以与其他编译器一起使用。
【讨论】:
这看起来是一种非常体面的方法。我的向量将介于 1000 到 10000 个元素之间。但是,我在实施它时遇到了麻烦;我在 Xcode 中遇到了错误(见截图:postimg.org/image/a858c4fbx)。有什么想法是什么意思? 看起来您在标题中定义了其他名为xor
的内容,导致名称冲突。【参考方案2】:
Stephen 的回答很有用,但是当您查看 Accelerate 时,请记住它不是一个神奇的“快速”库。除非 VECTOR_LENGTH 非常大(比如 10,000 —— 编辑:Stephen 不同意这种规模,并且往往比我更了解这个主题;请参阅 cmets),函数调用的成本通常会压倒您获得的任何好处。请记住,归根结底,Accelerate 只是代码。很多时候,像您这样的简单手写循环(尤其是具有良好编译器优化的)在 xor 等简单操作上会同样好或更好。
但在很多情况下,您需要让编译器帮助您。 Clang 知道如何自动进行各种有用的向量优化(就像在斯蒂芬的回答中一样)。但在大多数情况下,默认的优化设置是 -Os(Fastest,Smallest)。这就是说“clang,您可以进行任何您想要的优化,但如果它使生成的二进制文件更大,则不会。”你可能会注意到斯蒂芬的例子比你的大一点。这意味着编译器通常被禁止应用它知道该怎么做的自动向量优化。
但是,如果您切换到 -Ofast,那么即使它会增加二进制大小(在现代硬件,甚至移动硬件上,这通常是一个非常好的折衷方案),您也会允许 clang 提高性能。在“构建设置”面板中,这称为“优化级别:最快、激进的优化”。在几乎所有情况下,这都是 ios 和 OS X 应用程序的正确设置。 (由于历史原因,它目前不是默认值;我希望 Apple 将来会使其成为默认值。)
如需更多关于 Accelerate(它是一个很棒的库)的限制的讨论,您可能对 "Introduction to Fast Bézier (and Trying the Accelerate.framework)" 感兴趣。我还强烈推荐"What's New in the LLVM Compiler"(WWDCS 2013 的第 402 节),我发现它比 Accelerate 的介绍更有用。如果你不碍事,Clang 可以做一些非常惊人的优化。
【讨论】:
如果有问题的函数是在 Accelerate 中实现的,它会击败标量循环的实际阈值将是大约 32 - 64 个元素,而不是数万个 - 函数调用对于这种类型的操作,开销通常可以忽略不计,除非缓冲区真的很小。否则,很好的建议。 我发现(当我与他们讨论时,Apple 的 Accelerate 团队也证实了)像矩阵乘法这样的事情需要在一条腿上至少有 1000 的大小才能击败一个微不足道的循环。点积也类似。您是否发现其他 Accelerate 函数的值要小得多?许多 Accelerate 函数包括步幅选项和错误检查,这会在小向量上引入大量开销。但我只在 Accelerate 中测试了相对少量的函数,所以我想了解更多关于哪些函数可能优于标准编译器优化循环的详细信息。 我是 Accelerate 的负责人之一。通常,您的缓冲区需要在“每个维度上几十个”以摊销函数调用并击败标量代码。矩阵乘法有一些极端情况(一个非常高的纵横比矩阵;如果我没记错的话,这就是你所处理的)阈值更高(尽管我们在 OSX 10.9/iOS 7.0 中对它们进行了一些改进) , 也有一些极端情况和较少使用的函数没有像常见情况那样优化,但总的来说阈值远低于 1000。 当然,当您遇到性能出乎意料的低性能函数时,请告诉我们 =) 你没记错。我是那个出现问“Accelerate ever 更快吗?”的混蛋。我带着更好的理解离开了。谢谢你。以上是关于iOS - 使用 Accelerate.framework 对向量进行按位异或的主要内容,如果未能解决你的问题,请参考以下文章
使用 SmartFace.io 录制音频(Android - Ios)