gcc on raspberry half precision floating point (binary16, alternative, __fp16) 使用库函数
gcc on raspberry half precision floating point (binary16, alternative, __fp16) uses library function
我在 raspberry pi 3 上使用了一些基于机器学习的算法,具有大量存储系数,不需要完整的 float32 精度。
我尝试使用半精度浮点来存储此数据以减少程序内存(可能还有内存带宽)占用空间。
算法的其余部分保持不变。
比较 float32 和 float16 版本我在使用 __fp16
时得到了(重要的:我的测试程序运行时间增加了 33%)性能损失,尽管 cpu 应该支持转换.
我查看了 asembler 输出并创建了一个简单的函数,它只读取一个 __fp16
值和 returns 一个它作为 float
似乎一些库函数call 用于转换。 (调用了与实际代码相同的函数)
rapspberry 的 cpu 应该有半精度硬件支持,所以我希望看到一些指令加载数据并且不会看到任何性能影响(或看到由于减少内存带宽要求而有所改进)
我正在使用以下编译器标志:
-O3 -mfp16-format=alternative -mfpu=neon-fp16 -mtune=cortex-a53 -mfpu=neon
这里是小测试函数的一小段代码和汇编程序输出:
const float test(const Coeff *i_data, int i ){
return (float)(i_data[i]);
}
将 float
用于 Coeff
:
.align 2
.global test
.syntax unified
.arm
.fpu neon
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
add r1, r0, r1, lsl #2 @ tmp118, i_data, i,
vldr.32 s0, [r1] @, *_5
bx lr @
将 __fp16
用于 Coeff
(-mfp16-format=alternative
):
.align 2
.global test
.syntax unified
.arm
.fpu neon
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
lsl r1, r1, #1 @ tmp118, i,
push {r4, lr} @
ldrh r0, [r0, r1] @ __fp16 @, *_5
bl __gnu_h2f_alternative @
vmov s0, r0 @,
pop {r4, pc} @
对 Coeff
使用 __fp16
(-mfp16-format=ieee
):
.align 2
.global test
.syntax unified
.arm
.fpu neon
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
lsl r1, r1, #1 @ tmp118, i,
push {r4, lr} @
ldrh r0, [r0, r1] @ __fp16 @, *_5
bl __gnu_h2f_ieee @
vmov s0, r0 @,
pop {r4, pc} @
我是不是漏掉了什么?
在 ARM 的网站上:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0774d/chr1421838476257.html
备注
__fp16 类型只是一种存储格式。出于算术和其他运算的目的,C 或 C++ 表达式中的 __fp16 值会自动提升为浮点数。
编译器标志 -mfpu=neon
覆盖了之前的 -mfpu=neon-fp16
,因为 -mfpu=
只能指定一次。
设置两次是错误的(在Makefile的不同地方添加的)。
但由于 raspberry 3 的 vfpv4 始终支持 fp16,因此最佳规格是 -mfpu=neon-vfpv4
。
在这种情况下,编译器不会为转换生成任何库调用。
编辑:根据这个ghist
-mfpu=neon-fp-armv8 -mneon-for-64bits
可用于 Raspberry 3。
我在 raspberry pi 3 上使用了一些基于机器学习的算法,具有大量存储系数,不需要完整的 float32 精度。
我尝试使用半精度浮点来存储此数据以减少程序内存(可能还有内存带宽)占用空间。
算法的其余部分保持不变。
比较 float32 和 float16 版本我在使用 __fp16
时得到了(重要的:我的测试程序运行时间增加了 33%)性能损失,尽管 cpu 应该支持转换.
我查看了 asembler 输出并创建了一个简单的函数,它只读取一个 __fp16
值和 returns 一个它作为 float
似乎一些库函数call 用于转换。 (调用了与实际代码相同的函数)
rapspberry 的 cpu 应该有半精度硬件支持,所以我希望看到一些指令加载数据并且不会看到任何性能影响(或看到由于减少内存带宽要求而有所改进)
我正在使用以下编译器标志:
-O3 -mfp16-format=alternative -mfpu=neon-fp16 -mtune=cortex-a53 -mfpu=neon
这里是小测试函数的一小段代码和汇编程序输出:
const float test(const Coeff *i_data, int i ){
return (float)(i_data[i]);
}
将 float
用于 Coeff
:
.align 2
.global test
.syntax unified
.arm
.fpu neon
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
add r1, r0, r1, lsl #2 @ tmp118, i_data, i,
vldr.32 s0, [r1] @, *_5
bx lr @
将 __fp16
用于 Coeff
(-mfp16-format=alternative
):
.align 2
.global test
.syntax unified
.arm
.fpu neon
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
lsl r1, r1, #1 @ tmp118, i,
push {r4, lr} @
ldrh r0, [r0, r1] @ __fp16 @, *_5
bl __gnu_h2f_alternative @
vmov s0, r0 @,
pop {r4, pc} @
对 Coeff
使用 __fp16
(-mfp16-format=ieee
):
.align 2
.global test
.syntax unified
.arm
.fpu neon
.type test, %function
test:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
lsl r1, r1, #1 @ tmp118, i,
push {r4, lr} @
ldrh r0, [r0, r1] @ __fp16 @, *_5
bl __gnu_h2f_ieee @
vmov s0, r0 @,
pop {r4, pc} @
我是不是漏掉了什么?
在 ARM 的网站上:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0774d/chr1421838476257.html
备注 __fp16 类型只是一种存储格式。出于算术和其他运算的目的,C 或 C++ 表达式中的 __fp16 值会自动提升为浮点数。
编译器标志 -mfpu=neon
覆盖了之前的 -mfpu=neon-fp16
,因为 -mfpu=
只能指定一次。
设置两次是错误的(在Makefile的不同地方添加的)。
但由于 raspberry 3 的 vfpv4 始终支持 fp16,因此最佳规格是 -mfpu=neon-vfpv4
。
在这种情况下,编译器不会为转换生成任何库调用。
编辑:根据这个ghist
-mfpu=neon-fp-armv8 -mneon-for-64bits
可用于 Raspberry 3。