Android的NDK:ARMv6的VFP +设备。 计算错误,NaN的,非正规的数字,VFP1

2019-08-04 02:29发布

我想指定的ARMv6 VFP与Android设备。

我在下面一行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);
}

logcat的

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上。

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

我想看到一些参考类似错误。 的方式来解决它。 或约错误的性质。

我也经常得到的ARMv6 NaN值当的ARMv7相同的代码不给NaN的。

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

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我读某处的ARMv6是有差异的ARMv7 denorms默认和ARM1136SF-S零冲洗有它可选。 http://infocenter.arm.com/help/topic/com.arm.doc.ddi0211k/DDI0211K_arm1136_r1p5_trm.pdf

尚未确定如何验证ARM是嵌入式到零标志。

更新3

该CPU的VFP称为VFP11我发现--vfp11-denorm-fix选项。 还有--vfp-denorm-fix他们纠正勘误VFP11的CPU。 看起来像我的目标问题。 几个有关VFP11勘误发现帖子。 希望这将修复代码。

Answer 1:

好像我认定错误。

正是在VFP11(ARMv6的协处理器)非正规化错误的bug。 非正规数字是非常小的数目。

我得到这个数字在物理代码执行春季倾销

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

这两种力量得到很小的时候对象archieve Center ,我得到denormal的最终值。

我可以重新写入SRING和倾倒,但我不能重新写入孔BulletPhysics或全部数学代码和预测的非正规每隔数(甚至内部)次数。

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

NDK接头具有--vfp11-denorm-fix此选项可帮助。 代码看起来更可复制的,但它并不适用于100%解决问题。

我现在看到更少的错误。

但如果我等待消费满稳定对象,然后我终于我得到非正规化 - > 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可能-mfpu=vfp-d16 ,而不是仅仅的vfp是必需的。

手工清除非正规号码

我有上述弹簧的代码。 我通过手动清除反规范数,而无需使用与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分钟,在玩手机。 +我们在灯下加热电话。 热门手机显示错误更快。

我想测试不同的配置,并报告有什么解决方法是最有效的。 但现在我们必须添加的黑客攻击,杀掉最后的bug可能与非正规化。

我希望能够找到灵丹妙药,将解决它,但只有-msoft-float与10倍的性能退化或正在运行的应用程序上的ARMv7做的。


之后,我取代了以前的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;
        }
}


Answer 2:

此页面对ARM FPU选择一个有趣的讨论: VfpComparison

我想,如果你想建立的ARM v6的,你可以这样做: -march=armv6 -mcpu=generic-armv6 -mfloat-abi=softfp (并离开了-mfpu选项)。 如果你没有特别靶向您上面提到的处理器,通用的ARMv6没有保证FPU。

另一种选择是尝试-mfloat-abi=hard ,从理论上说有一个编译器错误的地方周围softfp。

同时检查代码中的任何堆栈损坏等,有可能的是,当浮点值传递你揍他们。

PS你也可能想尝试一个浮点测试仪等TestFloat或古老的NETLIB 偏执 。 虽然你有浮点否则在这个特定的处理器以及与这些编译器选项的例子,你不知道它是多么普遍的一个问题。 这可能是比你想象的更糟糕:)



文章来源: Android NDK: ARMv6 + VFP devices. wrong calculations, NaN, denormal numbers, VFP11 bug