Android-NDK:ARMv6+;VFP设备。错误计算、NaN、非规范数、VFP11错误

Android-NDK:ARMv6+;VFP设备。错误计算、NaN、非规范数、VFP11错误,android-ndk,arm,nan,armv6,Android Ndk,Arm,Nan,Armv6,我希望将目标对准带有VFP Android设备的ARMv6 我在我的Android.mk文件中有以下行来启用VFP LOCAL_CFLAGS := -marm -mfloat-abi=softfp -mfpu=vfp -Wmultichar 我相信我的目标是ARMv5和VFP 我编辑了android-ndk-r8b\toolschains\arm-linux-androideabi-4.6\setup.mk以删除-msoft float。我还尝试了使用originalsetup.mk 我

我希望将目标对准带有VFP Android设备的ARMv6

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

LOCAL_CFLAGS    := -marm -mfloat-abi=softfp -mfpu=vfp -Wmultichar
我相信我的目标是
ARMv5
VFP

我编辑了
android-ndk-r8b\toolschains\arm-linux-androideabi-4.6\setup.mk
以删除
-msoft float
。我还尝试了使用original
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);
}
它计算两点之间的距离。通常为0.000031 但是当
疯狂模式
开启时,它是20.0

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

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

我想看到一些类似的错误参考。解决这个问题的方法。或者关于虫子的本质

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

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

这里是一个编译命令的例子。我已经尝试了很多不同的设置

编译器设置

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

到目前为止,我学到的是,这个bug可能与
de-normals
我在某个地方读到了ARMv7与ARMv6的不同之处,即默认情况下,ARMv6具有
denorms
flush到零,并且ARM1136SF-S可以选择使用它。

还不确定如何验证ARM上的刷新到零标志

更新3

此CPU的VFP称为
VFP11
我找到了
--vfp11去规范修复
选项。 还有
--vfp denorm fix
它们纠正
VFP11
cpu中的错误。看起来像是我的目标问题。
发现很少有关于VFP11勘误表的帖子。希望它能修复代码。

本页对ARM FPU选项进行了有趣的讨论:

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

另一种选择是尝试
-mfloat abi=hard
,其理论是softfp周围存在编译器缺陷

还要检查代码中是否存在堆栈损坏等问题,当传递浮点值时,可能会对它们进行重击


另外,您可能还想试用浮点测试仪,如或古老的netlib。虽然您有一个在这个特定处理器和这些编译器选项上浮点失败的例子,但您不知道这个问题有多普遍。这可能比你想象的更糟:)

好像我发现了bug

这是VFP11(ARMv6协处理器)denorm错误中的错误。 数量非常少

我在物理代码中得到了这个数字,用转储实现了spring

force1 = (Center - P1) * k1         // force1 directed to center 
force2 = - Velocity * k2            // force2 directed against velocity
Object->applyForce(force1)
Object->applyForce(force2)
这两种力在对象归档时都非常小,最后我得到了非规范值

我可以重写sring和dumping,但我不能重写物理或所有数学代码,也不能预测每一个(甚至是内部)非规范数的发生

链接器具有修复代码选项
--vfp11-denorm-fix
--vfp-denorm-fix

NDK链接器有
--vfp11异常修复程序
这个选项很有帮助。代码看起来更容易回复,但它并不能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\u ARM\u模式:=ARM
Android.mk
可能是
-mfpu=vfp-d16
,而不是仅要求
vfp

手动清除非规范数字

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
我有上面描述的spring代码。 我改进了它,通过手动清除非规范数,而不使用具有以下功能的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;
}

默认情况下,NDK以armeabi(ARMv5TE)为目标。使用
ndk build V=1
查看如何调用编译器。不要无缘无故地与CFLAG为伍。阅读eabis的$NDK/docs/APPLICATION-MK.html。可以有没有VFP的ARMv5,但它们应该崩溃,不会产生奇怪的结果。@auselen谢谢!没有VFP的ARMv5TE工作正常。但是数学的速度慢了10倍,我的应用程序有物理模拟,并且使用OpenGL ES 2.0。我不知道没有VFP的OpenGL ES 2.0手机。我愿意启用VFP,或者至少阅读类似案例或导致问题的bug。您也应该为ARMv7构建。@auselen我愿意。Armv6和armv7代码在armv7设备上运行。问题在于armv6设备上带有Vfp的armv6。代码工作正常,在开始出错后2-3分钟,然后返回正常状态。比如CPU温度的变化。我添加了错误检测器。当计算错误时,它们会记录,如示例中所示。“-mtune=arm6”听起来非常错误。arm6是ARMv3()。但是我不认为这是你的问题。您是否有可以隔离此行为的ARMv6设备?
-mfloat abi=hard
不是个好主意。Android it self是用
-mfloat abi=softfp
编译的,如果我重新编译Android,我就可以使用
硬的
,而不仅仅是我的应用程序。我会看看你的链接。我几乎可以肯定我已经找到了更新3中提到的bug。那将是格雷亚
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;
        }
}