在x86和ARM上浮动VS int的性能差异如此之大?

Ser*_* K. 7 c floating-point arm android-ndk linderdaum

我想知道如何将智能手机上的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
{}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

float比...慢int.

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

(Main):01:43:39.468   Float: 0.72247
(Main):01:43:40.040   Int: 0.57212
Run Code Online (Sandbox Code Playgroud)

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

(Main):01:39:25.844   Float: 0.21671
(Main):01:39:26.060   Int: 0.21511
Run Code Online (Sandbox Code Playgroud)

VS 2008,发布版本,Win32/x86

(Main):01:33:27.603   Float: 0.70670
(Main):01:33:27.814   Int: 0.21130
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

float比...慢得多int.

现在让我们改变循环中乘法的加法:

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;
}
Run Code Online (Sandbox Code Playgroud)

VS 2008,调试版本,Win32/x86

(Main):02:00:39.977   Float: 0.87484
(Main):02:00:40.559   Int: 0.58221
Run Code Online (Sandbox Code Playgroud)

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

(Main):01:59:27.175   Float: 0.77970
(Main):01:59:27.739   Int: 0.56328
Run Code Online (Sandbox Code Playgroud)

VS 2008,发布版本,Win32/x86

(Main):02:05:10.413   Float: 0.86724
(Main):02:05:10.631   Int: 0.21741
Run Code Online (Sandbox Code Playgroud)

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

(Main):02:09:58.355   Float: 0.29311
(Main):02:09:58.571   Int: 0.21595
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

Sev*_*yev 5

-mfloat-abi=softfp显式调用模拟浮点。检查您的 Galaxy 的规格,并在可能的情况下使用硬件 FP 进行编译。

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

  • 不,“softfp”允许使用硬件浮点指令生成代码,但仍然使用软浮点调用约定。http://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html (3认同)
  • 使用硬浮点虽然可以/可能避免额外的函数调用层。 (2认同)

Fro*_*zie 5

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

基本上softfp用于保持与没有 FPU 的设备的向后兼容性。对于具有 FPU 的设备来说,使用softfp将会产生一些额外的开销。

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

  • 我不知道。不幸的是,使用armv7指令集的芯片组有很多变体。我最好的猜测是“不”。 (2认同)

old*_*mer 3

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

该测试比较了这两个函数固定与浮动

.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
Run Code Online (Sandbox Code Playgroud)

结果并不太令人惊讶,0x4E2C 时间是定点时间,而 0x4E2E 是浮点时间,浮点测试函数中有一些额外的指令可能解释了差异:

00004E2C                                                                        
00004E2C                                                                        
00004E2E                                                                        
00004E2E                                                                        
00004E2C                                                                        
00004E2E    
Run Code Online (Sandbox Code Playgroud)

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

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