4

我的应用程序中有循环,在其中执行数学乘法和加法计算。

我知道一些事实:

  • android 设备支持 armv6 及更高版本的处理器
  • armv6 不支持 NEON 命令

如果我将开始使用汇编程序数学命令而不是 c 数学命令,我是否会提高 armv6 上应用程序的性能,包括及以上?

更新

我需要用数学运算更快地执行循环,这是使用汇编程序而不是 c 的正确方法。

更新

我有这个计算:

Ry0 = (b0a0 * buffer[index] + b1a0 * Rx1 + b2a0 * Rx2 - a1a0 * Ry1
                    - a2a0 * Ry2);

它是双二阶传递函数。

我可以用 asm 强制执行这个计算吗?

更新

  • 缓冲区大小为 192000
  • 变量是浮点类型
4

4 回答 4

12

编译器非常擅长他们的工作,所以除非你知道你的编译器正在产生什么,并且知道你可以做得更好,否则可能不会。

如果不确切知道您的代码做了什么,就不可能给出更好的答案。

编辑:总结这个讨论:提高性能的第一步不是开始编写汇编程序。第一步是找到最有效的算法。完成后,您可以查看汇编程序编码。

于 2012-12-21T20:22:50.857 回答
8

无限脉冲响应 (IIR) 函数很难以高性能实现,因为每个输出元素都密切依赖于前一个输出元素。这迫使从输出到输出的延迟。这种依赖链击败了常见的高性能技术(例如 SIMD、条带挖掘和超标量执行)。

最初在装配中工作并不是解决此问题的好方法。在某些时候,组装工作可能会有所帮助。但是,您有一个基本问题需要解决:在完成前一个输出、将其乘以一个系数并添加附加算术的结果之前,您无法产生新的输出。因此,使用此公式可以做的最好的事情是产生一个输出,就像处理器从头到尾执行乘法和加法一样频繁,即使假设其他工作可以并行完成。

在数学上可以重写 IIR,以便输出依赖于过去更远的其他输出和输入,而不是前一个输出。这使用了更多的算术,但提供了并行执行更多算术的可能性,从而获得更高的吞吐量。

在 iPhone 或其他 iOS 设备上,您可以简单地调用 Accelerate 框架中的 vDSP_deq22。Accelerate 是 Apple 库,因此在 Android 上不可用。但是,也许有人已经实现了类似的东西。

一种方法是测量每个输出占用多少处理器周期(计算多个,将时间除以输出数量,乘以处理器速度)到延迟,以周期为单位,从加法乘法(来自处理器模型的文档您正在使用)。如果所花费的时间与延迟相同,那么就不可能在该处理器上更快地执行此算术,您必须接受它或找到具有不同数学的替代解决方案。

于 2012-12-21T20:50:00.740 回答
3

通过查看编译器的功能,您可能能够获得一些额外的速度,但这应该是您做的最后一件事。首先好好看看你的算法和变量类型。

由于您的目标是 ARMv6,所以我要做的第一件事就是从浮点运算切换到定点运算。ARMv6 通常没有或非常慢的硬件浮点支持。ARMv7 通常更好,但对于 ARM,定点运算通常比浮点实现快很多。

于 2012-12-21T21:26:04.467 回答
1

Android 支持 ARMv5TE 和 ARMv7-A。阅读有关支持的 CPU ARCH 和 ABI 的 NDK 文档,请访问$NDK/docs/CPU-ARCH-ABIS.html

ARMv5TE 是默认的,不给你任何硬件浮点支持,你可以查看Android NDK页面了解更多。您应该将 ARMv7-A 支持添加到您的应用程序中,以获得硬件的最佳支持。

ARMv6 介于两者之间,如果你想针对这些设备,你必须做一些Android.mk诡计。

如今,如果您正在编写一个现代应用程序,您可能会针对具有 ARMv7-A 处理器类型(具有 VFPv3 和 NEON)的较新设备。如果你只想支持ARMv6,你应该使用 ARMv5TE 来覆盖这些。如果您想利用 ARMv6 提供的一些额外功能,那么您将完全失去对 ARMv5TE 的支持。

我用 NDK r8c 编译了您的简单代码行,它可以为我生成如下所示的二进制文件。最好的 ARM VFP 允许您的语句是multiply and accumulate指令,fmac编译器可以轻松发出这些指令。

00000000 <f>:
   0:   ee607aa2    fmuls   s15, s1, s5
   4:   ed9f7a05    flds    s14, [pc, #20]
   8:   ee407a07    fmacs   s15, s0, s14
   c:   ee417a03    fmacs   s15, s2, s6
  10:   ee417ae3    fnmacs  s15, s3, s7
  14:   eeb00a67    fcpys   s0, s15
  18:   ee020a44    fnmacs  s0, s4, s8
  1c:   e12fff1e    bx  lr

将您的语句分成几块以获得双重发布可能会更好,但您可以在 C 中执行此操作。

你不能仅仅使用汇编来创造奇迹,但是编译器也可以创造一个巨大的废话。GCC 和 ARM 不如 GCC 和 Intel。尤其是在矢量化、NEON 使用方面。如果您需要高性能的例程,检查编译器生成的内容总是好的。

于 2012-12-21T22:11:15.673 回答