【问题标题】:Does float VS int performance on x86 and ARM differ so much?x86 和 ARM 上的 float VS int 性能差异很大吗?
【发布时间】:2012-09-03 08:51:15
【问题描述】:

我想知道智能手机上的 ARM 浮点性能与 x86 相比如何。为此,我编写了以下代码:

#include "Linderdaum.h"
sEnvironment* Env = NULL;

volatile float af = 1.0f;
volatile float bf = 1.0f;
volatile int a = 1;
volatile int b = 1;

APPLICATION_ENTRY_POINT
{
    Env = new sEnvironment();

    Env->DeployDefaultEnvironment( "", "CommonMedia" );

    double Start = Env->GetSeconds();

    float Sum1 = 0.0f;

    for ( int i = 0; i != 200000000; i++ )    {        Sum1 += af + bf;    }

    double End = Env->GetSeconds();

    Env->Logger->Log( L_DEBUG, LStr::ToStr( Sum1, 4 ) );
    Env->Logger->Log( L_DEBUG, "Float: " + LStr::ToStr( End-Start, 5 ) );

    Start = Env->GetSeconds();

    int Sum2 = 0;

    for ( int i = 0; i != 200000000; i++ )    {       Sum2 += a + b;    }

    End = Env->GetSeconds();

    Env->Logger->Log( L_DEBUG, LStr::ToStr( Sum2, 4 ) );
    Env->Logger->Log( L_DEBUG, "Int: " + LStr::ToStr( End-Start, 5 ) );

    Env->RequestExit();

    APPLICATION_EXIT_POINT( Env );
}

APPLICATION_SHUTDOWN
{}

以下是不同目标和编译器的结果。

1.搭载 Core i7 920 的 Windows PC。

VS 2008,调试版本,Win32/x86

(Main):01:30:11.769   Float: 0.72119
(Main):01:30:12.347   Int: 0.57875

floatint 慢。

VS 2008,调试版本,Win64/x86-64

(Main):01:43:39.468   Float: 0.72247
(Main):01:43:40.040   Int: 0.57212

VS 2008,发布版本,Win64/x86-64

(Main):01:39:25.844   Float: 0.21671
(Main):01:39:26.060   Int: 0.21511

VS 2008,发布版本,Win32/x86

(Main):01:33:27.603   Float: 0.70670
(Main):01:33:27.814   Int: 0.21130

int 领先。

2。三星 Galaxy S 智能手机。

GCC 4.3.4、armeabi-v7a、-mfpu=vfp -mfloat-abi=softfp -O3

01-27 01:31:01.171 I/LEngine (15364): (Main):01:31:01.177   Float: 6.47994
01-27 01:31:02.257 I/LEngine (15364): (Main):01:31:02.262   Int: 1.08442

floatint 慢很多。

现在让我们将循环内的加法改为乘法:

float Sum1 = 2.0f;

for ( int i = 0; i != 200000000; i++ )
{
    Sum1 *= af * bf;
}
...
int Sum2 = 2;

for ( int i = 0; i != 200000000; i++ )
{
    Sum2 *= a * b;
}

VS 2008,调试版本,Win32/x86

(Main):02:00:39.977   Float: 0.87484
(Main):02:00:40.559   Int: 0.58221

VS 2008,调试版本,Win64/x86-64

(Main):01:59:27.175   Float: 0.77970
(Main):01:59:27.739   Int: 0.56328

VS 2008,发布版本,Win32/x86

(Main):02:05:10.413   Float: 0.86724
(Main):02:05:10.631   Int: 0.21741

VS 2008,发布版本,Win64/x86-64

(Main):02:09:58.355   Float: 0.29311
(Main):02:09:58.571   Int: 0.21595

GCC 4.3.4、armeabi-v7a、-mfpu=vfp -mfloat-abi=softfp -O3

01-27 02:02:20.152 I/LEngine (15809): (Main):02:02:20.156   Float: 6.97402
01-27 02:02:22.765 I/LEngine (15809): (Main):02:02:22.769   Int: 2.61264

问题是:我缺少什么(任何编译器选项)? ARM 设备上的浮点数学真的慢吗(与 int 相比)?

【问题讨论】:

  • 改变测试顺序:先int,后float。然后检查它是否相同
  • @tuğrul büyükışık:我需要任何额外的编译器开关吗?
  • 删除 a/b af/bf 变量上的 volatile 并将它们传入,您在这里测量的内存性能比浮点性能更多(当然,您不能在此处将 a/b 定义为常量,优化器将删除他们并发布答案)。
  • 从硬件的角度来看,无论是加法还是乘法,浮点比定点涉及更多。两者都使用定点 alu(加法器、乘法器等),但浮点数必须预先准备值并在后端标准化值。理想情况下,这是一个时钟周期,但并非总是如此。 arm fpu(嗯,不止一个)在后端同步,你可以去做其他事情然后回来询问答案,如果没有完成,它就会停止直到答案完成。我不知道 x86 fpus 是如何工作的。由于您添加的数字很小,因此应该非常快。
  • 同意@dwelch,从a/b、af/bf中移除volatile。如果你只是在循环之后使用变量,这足以让优化器删除计算。

标签: c floating-point android-ndk arm linderdaum


【解决方案1】:

-mfloat-abi=softfp 显式调用模拟浮点。检查你的 Galaxy 的规格,如果可能的话,用硬件 FP 编译。

并非所有 ARM CPU 一开始就支持硬件浮点。 NDK 的 ARMEABI 的默认设置需要模拟 FP——它应该与无 FP 的机器兼容。充其量,您可以对 CPU 功能进行一些运行时分支。

【讨论】:

【解决方案2】:

@Seva Alekseyev -mfloat-abi 标志仅控制浮点值如何传递给函数。使用softfp 值通过普通寄存器传递。使用 hardfp 值通过 FPU 寄存器传递。 -mfloat-abi 标志不控制使用哪些硬件指令。

基本上softfp 用于保持与没有 FPU 的设备的向后兼容性。使用softfp 会导致带有 FPU 的设备的一些额外开销。

@Sergey K 比较 x86 和 ARM 就像比较苹果和橘子。它们是两个非常不同的平台。 ARM 的主要设计目标是低功耗而非速度。您可以使用hardfp 看到一些性能改进。还有一个 4.6 版本的编译器可用。考虑到架构差异,我认为您的结果是合理的。

【讨论】:

  • hardfp的陷阱是什么?
  • 您的二进制文件不会在没有 FPU 的设备上运行。大多数较新的手机都有它们。
  • 它会在任何兼容 armv7 的芯片上运行吗?
  • 我不知道。不幸的是,使用 armv7 指令集的芯片组有很多变体。我最好的猜测是没有。
  • 您可以使用android_getCpuFeatures() 来确定FPU 是否可用。看起来所有 armv7 都具有 FPU。来自文档:ANDROID_CPU_ARM_FEATURE_VFPv3 表示设备的 CPU 支持 VFPv3 硬件 FPU 指令集扩展。由于 'armeabi-v7a' 的定义,如果 ANDROID_CPU_ARM_FEATURE_ARMv7 被返回,情况总是如此。
【解决方案3】:

这些结果是可信的。

Exynos 3 SoC 中使用的 Cortex-A8 内核具有非流水线 VFP 实现。我不记得我脑海中的确切数字,但我记得 VFP 加法和乘法的吞吐量大约是该内核上每 8 个周期执行一次操作。

好消息:这是一款非常古老的 SoC,而较新的 ARM SoC 具有更强大的 VFP 实现——加法、减法和乘法完全流水线化,并且吞吐量大大提高。此外,一些(但不是全部)Cortex-A8 SoC 支持 NEON,它为您提供全流水线单精度浮点。

【讨论】:

  • NEON 的优点。 NDK 中有一个关于使用 NEON 的页面。请参阅:文档/CPU-ARM-NEON.html
【解决方案4】:

http://github.com/dwelch67/stm32f4d见float03目录

测试比较了这两个函数fixed vs float

.thumb_func
.globl add
add:
    mov r3,#0
loop:
    add r3,r0,r1
    sub r2,#1
    bne loop
    mov r0,r3
    bx lr

.thumb_func
.globl m4add
m4add:
    vmov s0,r0
    vmov s1,r1
m4loop:
    vadd.f32 s2,s0,s1
    sub r2,#1
    bne m4loop
    vmov r0,s2
    bx lr

结果并不奇怪,0x4E2C 时间是定点,0x4E2E 是浮点数,浮点测试函数中有一些额外的指令可能是造成差异的原因:

00004E2C                                                                        
00004E2C                                                                        
00004E2E                                                                        
00004E2E                                                                        
00004E2C                                                                        
00004E2E    

stm32f4 中的 fpu 是其兄弟姐妹中的 vfp 的受限单精度版本。您应该能够在任何带有 vfp 硬件的 armv7 上执行上述测试。

通过链接 __aeabi_fadd 函数并且每次通过循环进行的额外调用,加上内存访问的额外时间,可能在库函数外部或内部 (vmov) 的转换等,可以添加到您所看到的.答案当然在反汇编中。

【讨论】:

  • 因此很可能 __aeabi_fadd 或您的 gcc 正在使用的任何东西,在通用寄存器中都有操作数,因此除了浮点添加之外,您正在测量的每个操作都有三个 vmov 指令,所以您是尝试比较一条指令加到六个:bl,vmov,vmov,vadd,vmov,bx 以这种方式比较时,无论浮点指令有多快,它总是比单个定点指令慢。如果您可以让编译器在不调用库的情况下进行公平比较,您将看到速度匹配。
  • 为了澄清我的结果,十六进制的数字是 10000 个固定和浮动循环的系统时钟数(可能预分频)。定点加法和浮点加法没有区别。很明显,OP 使用 fpu 的方式会增加几倍的指令开销,这将占执行差异的大部分。苹果与橙子的测试,上面是苹果与苹果的测试。
猜你喜欢
  • 1970-01-01
  • 2022-10-01
  • 2019-04-21
  • 2010-10-15
  • 1970-01-01
  • 2013-02-18
  • 2020-12-16
  • 1970-01-01
  • 2019-10-02
相关资源
最近更新 更多