2

我希望以 VFP Android 设备为目标 ARMv6。

我的Android.mk文件中有以下行可以启用VFP

LOCAL_CFLAGS    := -marm -mfloat-abi=softfp -mfpu=vfp -Wmultichar

我相信我的目标ARMv5VFP.

我编辑android-ndk-r8b\toolchains\arm-linux-androideabi-4.6\setup.mk删除-msoft-float. 我也试过原版setup.mk

我的代码在 99.99% 的情况下都可以正常工作,但有时在 ARMv6 设备上会发疯。我有特殊的代码来检测它何时发疯。

代码

glm::vec3 D = P1 - P2;
float f1 = sqrtf(D.x*D.x + D.y*D.y + D.z*D.z);
if(!(f1 < 5)){
    // f1 is bigger then 5 or NaN
    mylog_fmt("Crazy %f %f %f %f", P1.x, P1.y, P1.z, f1);
    mylog_fmt("%f %f %f", P2.x, P2.y, P2.z);
}

日志猫

12-14 00:59:08.214: I/APP(17091): Crazy -20.000031 0.000000 0.000000 20.000000
12-14 00:59:08.214: I/APP(17091): -20.000000 0.000000 0.000000

它计算2点之间的距离。通常它是 0.000031 但是当crazy mode它是 20.0

当我在 ARMv7 CPU 上运行它时,问题不存在。它仅存在于 ARMv6 CPU 上。

我相信它应该是一些与编译器设置或版本相关的常见已知错误。可能是代码缺少内存屏障。

我希望看到一些对类似错误的参考。解决它的方法。或关于错误的性质。

当 ARMv7 上的相同代码不给出 NaN 时,我也经常在 ARMv6 上得到 NaN 值。

我已经调试了 2 周的代码并在网上搜索。如果有人可以分享类似问题的链接,那将是一个很大的帮助!

PS。这是编译命令之一的示例。我已经尝试了许多不同的设置。

编译器设置

c:/soft/Android/android-ndk-r8b/toolchains/arm-linux-androideabi-4.6/prebuilt/windows/bin/arm-linux-androideabi-g++
-MMD -MP -MF ./obj/local/armeabi/objs/main/sys/base.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector 
-D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__
-D__ARM_ARCH_5TE__  
-march=armv5te -mtune=arm6 
-mfloat-abi=softfp -mfpu=vfp
-fno-exceptions -fno-rtti -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 
-Ijni/main/ -Ijni/main/sys -Ijni/main/bullet/src -Ijni/main/bullet/src/LinearMath -Ijni/main/bullet/src/BulletCollision/BroadphaseCollision 
-Ijni/main/bullet/src/BulletCollision/CollisionDispatch -Ijni/main/bullet/src/BulletCollision/CollisionShapes -Ijni/main/bullet/src/BulletCollision/NarrowPhaseCollision 
-Ijni/main/bullet/src/BulletDynamics/ConstraintSolver -Ijni/main/bullet/src/BulletDynamics/Dynamics -Ijni/main/../libzip/ -Ic:/soft/Android/android-ndk-r8b/sources/cxx-stl/stlport/stlport 
-Ic:/soft/Android/android-ndk-r8b/sources/cxx-stl//gabi++/include -Ijni/main 
-DANDROID

-marm -march=armv6 -mfloat-abi=softfp -mfpu=vfp -Wmultichar

-Wa,--noexecstack  -frtti  -O2 -DNDEBUG -g   -Ic:/soft/Android/android-ndk-r8b/platforms/android-5/arch-arm/usr/include -c  jni/main/sys/base.cpp
-o ./obj/local/armeabi/objs/main/sys/base.o

更新 2

所有这些设备都有高通 MSM7227A 它有 ARM1136JF-S

到目前为止我了解到的是,该错误可能与de-norms 我在某处读到 ARMv7 与 ARMv6 的差异有关,该差异denorms默认情况下已刷新为零,而 ARM1136SF-S 可以选择使用它。 http://infocenter.arm.com/help/topic/com.arm.doc.ddi0211k/DDI0211K_arm1136_r1p5_trm.pdf

尚不确定如何验证 ARM 上的 Flush-To-ZERO 标志。

更新 3

这个 CPU 的 VFP 被称为VFP11 I found --vfp11-denorm-fixoption。他们还--vfp-denorm-fix 纠正了VFP11cpus 中的错误。看起来像我的目标问题。发现一些关于 VFP11 勘误的帖子。希望它能修复代码。

4

2 回答 2

2

好像我发现了错误。

它是 VFP11(ARMv6 协处理器)denorm 错误中的错误。 非正规数是非常小的数。

我在物理代码中得到这个数字,实现带有倾倒的弹簧

force1 = (Center - P1) * k1         // force1 directed to center 
force2 = - Velocity * k2            // force2 directed against velocity
Object->applyForce(force1)
Object->applyForce(force2)

当对象归档时,两种力量都变得非常小Center,最后我得到denormal了值。

我可以重写 sring 和 dump,但我不能重写洞 BulletPhysics 或所有数学代码并预测非正规数的每次(甚至内部)出现。

链接器具有修复代码选项--vfp11-denorm-fix--vfp-denorm-fix http://sourceware.org/binutils/docs-2.19/ld/ARM.html

NDK 链接器有--vfp11-denorm-fix 这个选项有帮助。代码看起来更可重复,但它不能 100% 解决问题。

我现在看到的错误越来越少。

但是,如果我等待稳定对象,那么我终于得到了 denorm -> NaN

我必须等待更长的时间,但同样的问题来了。

如果您知道可以修复代码的解决方案,--vfp11-denorm-fix那么我应该给您赏金。

我都试过--vfp11-denorm-fix=scalar--vfp11-denorm-fix=vector

清零位

      int x;
      // compiles in ARM mode
      asm(
              "vmrs %[result],FPSCR \r\n"
              "orr %[result],%[result],#16777216 \r\n"
              "vmsr FPSCR,%[result]"
              :[result] "=r" (x) : :
      );

不知道为什么,但它需要LOCAL_ARM_MODE := armAndroid.mk May 中-mfpu=vfp-d16,而不是 justvfp是必需的。

手动清除非正规数

我有上面描述的弹簧代码。我通过手动清除非正规数来改进它,而不使用具有以下功能的 FPU。

inline void fixDenorm(float & f){
    union FloatInt32 {
        unsigned int u32;
        float f32;
    };
        FloatInt32 fi;
        fi.f32 = f;

        unsigned int exponent = (fi.u32 >> 23) & ((1 << 8) - 1);
        if(exponent == 0)
            f = 0.f;
}

在许多地方,原始代码在 15-90 秒内失败。

在物理模拟 10 分钟后,当前代码仅在一个地方显示了可能与此错误有关的问题。


参考错误和修复 http://sourceware.org/ml/binutils/2006-12/msg00196.html

他们说GCC只使用 scalr 代码--vfp11-denorm-fix=scalar就足够了。它增加了 1 个额外的命令来减速。但即使--vfp11-denorm-fix=vector增加了 2 个额外的命令也是不够的。

问题不容易重现。在频率较高的 800Mhz 的手机上,我经常看到它,然后在较慢的 600Mhz 上看到它。当市场上没有快速 CPU 时,修复可能已经完成。


我们项目中有很多文件,每次配置编译大约需要 10 分钟。使用当前修复状态进行测试需要大约 10 分钟才能在手机上播放。+ 我们在灯下加热手机。热电话更快地显示错误。

我希望测试不同的配置并报告最有效的修复方法。但是现在我们必须添加 hack 来杀死最后一个可能与 denorms 相关的 bug。

我希望能找到能修复它的灵丹妙药,但只有-msoft-float在 10 倍性能下降或在 ARMv7 上运行应用程序时才能做到这一点。


在我用 spring/dumping 代码中的新函数替换以前的fixDenorm函数并fixDenormE为 ViewMatrix 应用新函数后,我摆脱了最后一个错误。

inline void fixDenormE(float & f, float epsilon = 1e-8){
    union Data32 {
        unsigned int u32;
        float f32;
    };
        Data32 d;
        d.f32 = f;

        unsigned int exponent = (d.u32 >> 23) & ((1 << 8) - 1);
        if(exponent == 0)
            f = 0.f;
        if(fabsf(f) < epsilon){
          f = 0.f;
        }
}
于 2012-12-18T23:12:19.887 回答
0

这个页面有一个关于 ARM FPU 选项的有趣讨论:VfpComparison

我认为如果您想为 ARM v6 构建,您可以这样做:(-march=armv6 -mcpu=generic-armv6 -mfloat-abi=softfp并省略 -mfpu 选项)。如果您没有专门针对您上面提到的处理器,则通用 armv6 没有保证的 fpu。

另一种选择是尝试-mfloat-abi=hard,理论上softfp 周围存在编译器错误。

还要检查代码中是否有任何堆栈损坏等,当传递浮点值时,您可能会破坏它们。

PS 您可能还想尝试一个浮点测试器,例如TestFloat或古老的 netlib paranoia。虽然您有一个在此特定处理器和这些编译器选项上出现浮点失败的示例,但您不知道它的问题有多普遍。它可能比你想象的更糟:)

于 2012-12-18T20:33:31.013 回答