免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3557 | 回复: 0
打印 上一主题 下一主题

ARM GCC浮点相关总结 . [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-23 01:27 |只看该作者 |倒序浏览

名字解释:
ABI,application binary interface (ABI),应用程序二进制接口。

编译版本问题:
  GCC 4.0 为分界线
  4.0版本以下,由于采用OABI接口,其对浮点的支持不太好
  4.0版本以上,采用了新的EABI接口,其对软浮点和硬浮点的支持都比较好。

考虑在4.0版本以下时,其支持的ARM内核大多数没有硬浮点,所以可以分析资料比较少,
现在重点关注4.0版本以上。以下所述都是针对4.0版本以上的。


编译器相关的参数:
  -mfloat-abi=soft    使用这个参数时,其将调用软浮点库(softfloat lib)来支持对浮点的运算,GCC编译器已经有这个库了,一般在libgcc里面。这时根本不会使用任何浮点指令,而是采用常用的指令来模拟浮点运算。但使用的ARM芯片不支持硬浮点时,可以考虑使用这个参数。在使用这个参数时,连接时一般会出现下面的提示:
   undefined reference to `__aeabi_fdiv'
  或者类似的提示,主要因为一般情况下连接器没有去主动寻找软浮点库,这时使用将libgcc库加入即可。

  -mfloat-abi=softfp
  -mfloat-abi=hard
  这两个参数都用来产生硬浮点指令,至于产生哪种类型的硬浮点指令,需要由-mfpu=xxx参数来指令。这两个参数不同的地方是:
         -mfloat-abi=softfp生成的代码采用兼容软浮点调用接口(即使用-mfloat-abi=soft时的调用接口),这样带来的好处是:兼容性和灵活性。库可以采用-mfloat-abi=soft编译,而关键的应用程序可以采用-mfloat-abi=softfp来编译。特别是在库由第三方发布的情况下。
         -mfloat-abi=hard生成的代码采用硬浮点(FPU)调用接口。这样要求所有库和应用程序必须采用这同一个参数来编译,否则连接时会出现接口不兼容错误。
 
 
  -mfpu=vfp
  -mfpu=fpa
  ...
  前面已经讲述了,-mfpu参数就是用来指定要产生哪种硬浮点指令。常见的有vfp,fpa等。


编译器使用时要注意的地方:
  1.确认编译器默认是使用哪种参数来处理浮点操作的。写一个简单的浮点数程序:
  #include <stdio.h>
 int main(void)
{
    double d1 = 10.3;
    double d2 = 2.0;
   
    double dret = d1/d2;
    dret++;
   
    printf("result :%f",dret);
   
    return 0;
}
    
 然后使用
      arm-linux-gcc -c main.c -o main.o
    再使用
      arm-linux-objdump -d main.o
     然后观察产生的指令,从而确定默认使用的是软浮点还是硬浮点。(确认的过程,看个人。晃一眼,里面如果有不熟悉指令,那可能就是硬浮点指令了)

 2.确认编译器所带的库使用哪种参数来编译的。
 3.确认所使用的芯片是否支持硬浮点,如果支持,是哪种类型的浮点指令。如果1,2与使用的芯片相冲突,这时就要考虑另寻编译器了。

这三点确认以后,我们在写自己的应用程序时,就会知道该怎样使用这些参数了。



Linux相关问题:
 这里涉及两个问题:1.使用的ARM芯片不支持硬浮点
                   2.使用的ARM芯片支持硬浮点
问题1:使用的ARM芯片不支持硬浮点
   在配置ARM Linux内核时,应该都会看到这样的配置:
    menu "Floating point emulation"
    comment "At least one emulation must be selected"
    config FPE_NWFPE
        ...
    这个是用来配置在内核里面模拟浮点处理器。
  这个配置有什么作用呢?估计很少有人能够知道。其实它是这样的:
   当使用的ARM芯片不支持硬浮点,而又采用了-mfpu=fpa -mfloat-abi=softfp/hard来编译应用程序。现在应该知道,采用这样的参数是要参数fpa硬浮点指令。但是使用的ARM芯片不支持硬浮点,这时这个配置就其作用了。因为使用了fpa硬浮点指令,但使用的ARM芯片不支持硬浮点,这样当程序运行到fpa硬浮点指令,会出现指令异常,便会陷入到内核里,这时这个模拟浮点处理器就来模拟这些浮点指令。现在应该清楚了,其作用了吧。但是现在有了更好的办法,前面已经讲过了,采用-mfloat-abi=soft参数来编译应用程序,这样效率会快得多。想想从用户态切换到内核态,以及由此产生的cache和TLB表的损失。所以可以考虑将这个配置抛弃了。


问题2:使用的ARM芯片支持硬浮点
一般ARM芯片支持硬浮点,都是采用协处理器方式的。与ARM内核本身一样,协处理器也有自己的寄存器。这样当多个进程同时涉及浮点运算时,会怎样?所以Linux内核为了支持硬浮点,也要做一些工作的。
内核配置:
   config VFP
    bool "VFP-format floating point maths"
    depends on CPU_V6 || CPU_ARM926T || CPU_V7 || CPU_FEROCEON
如果使用的ARM芯片支持硬浮点,同时在应用程序里面使用了硬浮点,那么内核可能需要做一些工作。。上面这个配置是针对vfp硬浮点处理器的;如果是其他硬浮点处理,需要参考相关的资料,来确认要做哪些功能。如果可以确保所有时候,可以确保只有一个进程使用硬浮点处理器,那可以不需要考虑对硬浮点相关寄存器的保存和切换,问题是可以确认吗?



对于浮点运算,针对ARM芯片应该尽量避免。如果无法避免,那就需要综合考虑到底使用哪种方式?如何去操作?性能如何?都需要考虑,去实验测试是最好的。

 

 

 

 

 

 

补充资料:

系统背景:
N800的主要硬件环境是 OMAP2420 SoC,其中 FPU是 VFP指令集。
我安装的是OS2008, maemo 4.0,代号 chinook。 该 linux kernel 支持捕捉浮点指令异常。系统ABI是 EABI4。

本测试主要有这些不同组合:

1、如果使用softfloat, 使用什么softfloat库
2、使用不同FPU指令集

我自己编译了两套不同的工具链:

  • arm-linux-gnueabi_glibc-nptl-softfloat
使用 EABI4,glibc 为 softfloat的,编译出来的程序可以直接在 OS2008 上跑。

  • arm-linux-gnu_glibc-nptl-softfloat
使用 OABI,glibc 为 softfloat的,编译出来的程序需要chroot后才能运行。OABI 不像EABI 指定了浮点函数的接口,所以这种情况下需要独立的float库。我编译了 libfloat,并将 libfloat.a 作为这种情况下的 softfloat 库。

测试程序如下:
#include <stdio.h>

int main(void) {
int i;
double d1 = 1.1;
double d2 = 2.002;
double d3;

for(i = 0; i < 0xFFFFF;++i)d3 = d1*d2;
for(i = 0; i < 0xFFFFF;++i)d3 = d1/d2;

return 0;
}
 

1.测试结果如下:
  • time arm-linux-gnueabi_glibc-nptl-softfloat/linux-gnueabi.soft.soft
    real 0m 1.93s
    user 0m 1.92s
    sys 0m 0.00s
  • 本测试使用gcc提供的 softfloat 库,并且用EABI4的浮点函数,直接在OS2008下运行。
    编译方式:
    linux-gnueabi.soft.soft: test.c
        $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mfloat-abi=soft $< -S -o $@.s
        $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mfloat-abi=soft $@.s -o $@
     
     
    2.
  • time chroot arm-linux-gnueabi_glibc-nptl-softfloat /linux-gnueabi.soft.soft
    real 0m 1.85s
    user 0m 1.80s
    sys 0m 0.00s
  • 本测试使用同样的程序,不过在我编译的 glibc 下 chroot 运行。结果无太大差别。
     
     
    3.
  • time arm-linux-gnueabi_glibc-nptl-softfloat/linux-gnueabi.soft.softfp.fpa
    real 0m 10.10s
    user 0m 0.35s
    sys 0m 9.33s
  • 本测试使用softfp float-abi。不过指令集使用是FPA. 使用soft-float 的调用规范执行浮点硬件指令,这样做能保证linux在捕捉到浮点指令错误的时候在内核态模拟浮点计算。
    omap2420 不支持FPA指令,所以这里的浮点硬件指令全部异常,由linux内核计算,于是sys占用了9秒,总体运行时间是前面的5倍。
    编译方式:
    linux-gnueabi.soft.softfp.fpa: test.c
        $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mfpu=fpa -mfloat-abi=softfp $< -S -o $@.s
        $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mfpu=fpa -mfloat-abi=softfp $@.s -o $@
     


    4.
  • time chroot arm-linux-gnueabi_glibc-nptl-softfloat /linux-gnueabi.soft.softfp.fpa
    real 0m 9.69s
    user 0m 0.21s
    sys 0m 9.46s
  • 本测试类似上面,不过是chroot后运行,结果也类似。
     

    5.
  • time arm-linux-gnueabi_glibc-nptl-softfloat/linux-gnueabi.soft.softfp.vfp
    real 0m 0.23s
    user 0m 0.23s
    sys 0m 0.00s
    本测试仍然使用 softfp float-abi,不过这次使用了正确的 vfp 指令集,时间大大缩短,比软件计算快了五倍。
    编译方式:
    linux-gnueabi.soft.softfp.vfp: test.c
    $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mfpu=vfp -mfloat-abi=softfp $< -S -o $@.s
    $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mfpu=vfp -mfloat-abi=softfp $@.s -o $@
  •  

     

    6.

  • time chroot arm-linux-gnueabi_glibc-nptl-softfloat /linux-gnueabi.soft.softfp.vfp
    real 0m 0.24s
    user 0m 0.23s
    sys 0m 0.00s
  • 本测试类似上面,不过是chroot后运行,结果也类似。
     
     
     
    7.
  • time arm-linux-gnueabi_glibc-nptl-softfloat/linux-gnueabi.soft.hard.fpa
    real 0m 9.67s
    user 0m 0.25s
    sys 0m 9.40s
  • 本测试直接使用硬件fpa指令,从生成的汇编代码看,和 softfp fpa 生成的代码一模一样,所以结果一样。
    linux-gnueabi.soft.hard.fpa: test.c
    $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mhard-float -mfpu=fpa $< -S -o $@.s
    $(LINUX_GNUEABI_SOFT_CC) $(CFLAGS) -mhard-float -mfpu=fpa $@.s -o $@
     
    8.
  • time chroot arm-linux-gnueabi_glibc-nptl-softfloat /linux-gnueabi.soft.hard.fpa
    real 0m 9.68s
    user 0m 0.26s
    sys 0m 9.40s
  • 类似上面,不过在 chroot 下运行。
     
     
     
     

    9.

  • time chroot arm-linux-gnu_glibc-nptl-softfloat /linux-gnu.soft.soft
    real 0m 5.98s
    user 0m 5.94s
    sys 0m 0.00s
  • 最后一个测试使用 libfloat 库,从数据上看该库非常慢。所以编译 ARM Linux 的一般都使用 EABI, 指定target 的时候设置为 arm-linux-gnueabi 而不是 arm-linux-gnu
    编译测试:
    linux-gnu.soft.soft: test.c
        $(LINUX_GNU_SOFT_CC) $(CFLAGS) -mfloat-abi=soft $< -S -o $@.s
        $(LINUX_GNU_SOFT_CC) $(CFLAGS) -mfloat-abi=soft $@.s -lfloat -o $@


    10.
    本测试没有测试 hard-float vfp 指令生成的代码,因为GCC告诉我:
    test.c:1: sorry, unimplemented: -mfloat-abi=hard and VFP

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP