当前,由Go构建的ARM程序在进行除法运算时会调用runtime.udiv()函数。在这个过程中,它会检测硬件除数是否可用,如果不可用,则使用软件除法。
主要原因是硬件除数对于ARMv7机器来说是一个可选组件。但在现实世界中,大多数ARMv7 SOC都配备了硬件除数,例如树莓派2。
GOARM=8意味着程序将在arm64机器的aarch32模式(与ARMv7兼容)下运行,而在这种模式下,硬件除数是必须的。因此:
- 编译器将直接生成SDIV/UDIV指令用于除法和取模操作。
- 使用GOARM=8构建的程序也可以在具有硬件除数的ARMv7上运行,例如树莓派2。
go1基准测试确实显示了直接生成SDIV/UDIV指令相对于运行时检测的改进。
9条答案
按热度按时间w51jfk4q1#
在状态 WaitingForInfo 中超时。关闭。(我只是个机器人,如果这是个错误或者你有请求的信息,请大声说出来。)
3gtaxfhh2#
遗憾的是,go1基准测试显示硬件除法运行时检查几乎没有改进。
ymzxtsji3#
"GOARM=8"之所以能发挥良好作用,是因为:
使用"GOARM=8",编译器可以将更多的分割值填充到保存的寄存器中,从而提高go1基准测试性能。
因此,我强烈建议添加GOARM=8,正如ARM的官方定义:
GOARM=8不仅能提高除法速度,还具有潜在的好处(在armv8机器上运行arm32程序)
ncecgwcz4#
$\dfrac{1}{3}$
w1e3prcc5#
我认为为仅有两个指令引入另一个GOARM值并不是一个好主意,性能提升小于geomean的1%。在这种情况下,我认为动态特征检测仍然更好。
我不确定这是否适用于这里(甚至可能与现代内存保护机制一起使用),但在过去,动态特征检测有时是通过在运行时逐个调用来对可执行文件进行打补丁实现的。
zpqajqem6#
你的意见是什么?
628mspwn7#
我认为为仅有的两个指令引入另一个GOARM值并不是一个好主意,性能提升小于geomean的1%。在这种情况下,我认为动态特征检测仍然更好。如果运行时的调用开销比我们想象的要大,我们可以内联生成特征测试和条件分支。与除法操作相比,我认为条件分支的开销是可接受的。
kokeuurv8#
这听起来像是提案中的GOARM=8表示ARMv7+hwdivide。
而ARMv8是64位的ARM,对吧?
所以用32位的ARMv7和hw divide来调用GOARM=8有点奇怪。
从性能Angular 来看,这似乎并不重要。也许编译器应该发出代码来进行检查+分支,就像我们已经为写屏障所做的那样?这至少可以允许对硬件代码路径进行更多的优化(不进行不必要的溢出/重新加载等)。
一个非常依赖除法的函数可能只需要两个副本,编译器可以将检查从循环或其他主体中提升出来,以实现摊销,而无需使用GOARM=。
另一个选择是遵循GOMIPS并将GOARM=7+divide。但是,尝试更快的分支检查(类似于写屏障)似乎更好。
xmjla07d9#
Can someone please try the faster branch check in the previous comment? We should have that data before making any decision to expose this detail to users.