虽然Linus Torvalds明确反对内核浮点运算,认为这会引入架构脆弱性,但是我们在实际使用场景中,有些场景就是无法规避在内核中使用浮点运算。当然如果是那种大规模的、复杂的求指求幂运算等类型,还是尽量在用户空间中进行硬浮点运算,如果是一些少量的、简单的浮点运算,尚可。本文测试的硬件环境为A55 ARM-v8.2A,软件环境为Linux kernel 6.12版本。 主要的实施与验证步骤如下:1、 配置相关
1)gcc编译器的编译选项需要关闭 -mgeneral-regs-only,这个选项的作用是强制编译器仅使用通用寄存器,禁止使用浮点寄存器或者向量寄存器。所以关闭之后,就会将浮点相关代码编译为硬浮点指令。 需要注意的是,全局编译打开该选项,针对浮点运算文件关闭该选项,可以最大化降低浮点运算导致内核的不稳定性问题。
2)需要基于当前的Linux kerne版本打开对应的内核配置选项,比如CONFIG_MODE_NEON等;
2、浮点运算需要严格隔离使用
1)将浮点运算代码封装在特定函数中,而且将该函数在独立的C文件中实现。
#include<asm/neon.h>floatfloat_test(float a, float b){ float rslt = 0.0f; kernel_neon_begin(); rslt = a * b; kernel_neon_end(); return rslt;}
并将该函数实现保存在float_test.c文件中; 2、编译选项具体修改方法 基于makefile编译时,会将全局的编译选项递归下发到不同的目录层级,比如全局编译选项的变量命名为 KBUILD_CFLAGS,我们需要将-mgeneral-regs-only过滤掉,具体如下: ccflags-y := $(fileter-out -mgeneral-regs-only, $(KBUILD_CFLAGS))
同时需要将KBUILD_CFLAGS在该目录中置空,KBUILD_CFLAGS := 不然在编译时,会将KBUILD_CFLAGS的编译选项与当前目录的ccflags-y编译选项进行叠加。 ARM平台调用接口分别为:kernel_neon_begin()与kernel_neon_end(),使用方法参考上文的代码示例。4、反汇编.o文件验证 为了防止操作失误,使用了软浮点模拟了浮点运算,可以对编译出的.o文件进行反汇编,查看汇编指令是否使用了硬浮点指令。
执行命令:objdump -Sl *.o文件 查看输出的汇编指令,如果有fmul,fdiv等类似的指令,即可以确认实际使用了硬浮点指令。5、上电启动运算结果对比验证 烧录镜像,上电启动,观察日志,对比浮点运算时间戳。 比对使用硬浮点之后,运算时间是否实际大幅度缩小,预期时间缩小10倍以上。