主核上无法使用指数为 0 的浮点数(subnormals),报错 sig 8(SIGFPE)
-
1 总结
1.1 报错
warning: node [26528]: user's mpe task: tid= 0, pid= 22346, terminated by sig 8
1.2 解决
使用 sw5cc 编译时,主核上的浮点数默认似乎不遵守 IEEE 标准,指数为 0 的浮点数(subnormals)会被置为 0。如果在主核代码中尝试使用一个 subnormal,会报错 SIGFPE。
打开编译选项
-OPT:IEEE_arith
,主核上能够正常使用 subnormals 了。在后面记录中出现的问题,可以通过以下编译选项解决:-OPT:IEEE_arith=1
,或-OPT:IEEE_arith=2
2 记录
2.1 代码
使用手册里的计算除法的 C 语言例子,在主、从核上使用相同的表达式不断把浮点数除以 1000(数组索引为
j, i
,j
也是线程编号,一共除以(j+1)*i
次 1000)。随后数据由从核传回主核,把所有数据加起来作为 checksum 比较。2.2 编译选项
sw5cc 和 sw5gcc 都试了。主核和从核使用相同选项,
-O1
、-O2
、-O3
都一样报错。2.3 结果
浮点数用 float,从核只用 2 个时,发生以下情形:
- 从核上出现的小于
2^(−127)≈5.877e−39
的数字可以在主核端打印,但不能用于四则运算,否则报错(SIGFPE); - 但是这些数据打印出来的值都超出了 float 的范围。
具体输出结果如下。其中,数组 c 在从核上计算,数组 cc 在主核上计算,紧跟数组值的是 c 中元素的十六进制。
从核 0 的结果:
c[0][0] = 3.6666666623209573e-18, cc[0][0] = 3.6666666623209573e-18 22 87 46 b0 c[0][1] = 3.6666666849391771e-21, cc[0][1] = 3.6666666849391771e-21 1d 8a 85 d3 c[0][2] = 3.6666665082343344e-24, cc[0][2] = 3.6666665082343344e-24 18 8d d8 e8 c[0][3] = 3.6666663171820839e-27, cc[0][3] = 3.6666663171820839e-27 13 91 40 6a c[0][4] = 3.6666663021357562e-30, cc[0][4] = 3.6666663021357562e-30 0e 94 bc d7 c[0][5] = 3.6666662639321898e-33, cc[0][5] = 3.6666662639321898e-33 09 98 4e af c[0][6] = 3.6666663500279674e-36, cc[0][6] = 3.6666663500279674e-36 04 9b f6 76 c[0][7] = 6.9405734356891773e-309, cc[0][7] = 0.0000000000000000e+00 00 27 ed 2d c[0][8] = 6.9415787311951471e-312, cc[0][8] = 0.0000000000000000e+00 00 00 0a 39 c[0][9] = 7.9574842161197712e-315, cc[0][9] = 0.0000000000000000e+00 00 00 00 03 c[0][10] = 0.0000000000000000e+00, cc[0][10] = 0.0000000000000000e+00 00 00 00 00
从核 1 的结果:
c[1][0] = 3.6666666623209573e-18, cc[1][0] = 3.6666666623209573e-18 22 87 46 b0 c[1][1] = 3.6666665082343344e-24, cc[1][1] = 3.6666665082343344e-24 18 8d d8 e8 c[1][2] = 3.6666663021357562e-30, cc[1][2] = 3.6666663021357562e-30 0e 94 bc d7 c[1][3] = 3.6666663500279674e-36, cc[1][3] = 3.6666663500279674e-36 04 9b f6 76 c[1][4] = 6.9415787311951471e-312, cc[1][4] = 0.0000000000000000e+00 00 00 0a 39 c[1][5] = 0.0000000000000000e+00, cc[1][5] = 0.0000000000000000e+00 00 00 00 00
两个从核在循环次数不同的情况下,能够打印出数量不同的 subnormals,并且打印出的结果显示这些数字远远小于 float 类型允许的 subnormals。
其中一个数字使用printf("%.16e\n")
打印出来为
- 十进制:7.9574842161197712e-315
- 十六进制:00 00 00 03
- 二进制:0000 0000 0000 0000 0000 0000 0000 0011
00 00 00 03
这个十六进制数实际对应的 4 字节单精度浮点数为4.2039e-45
。
7.9574842161197712e-315
这个浮点数按 8 字节双精度处理,转换成十六进制是00 00 00 00 60 00 00 00
。2.4 补充
主核上似乎无法使用 subnormals。
float 类型的最后一个指数非 0 的数字是
0x00800000
,这个用于计算不会报错。第一个指数为 0 的数字是0x007fffff
,这个数字用于计算会报错。2.5 问题
请问这是什么情况?主核和从核对浮点数 subnormal 的处理不一样?
有没有办法避免这种情况?在从核上加一个判断把这些数字全部置为 0 是可以正常执行的,但这样有点浪费时间。
-
已解决,编译时加上:
-OPT:IEEE_arith=1
,或-OPT:IEEE_arith=2
-
感谢!解决了问题!
-
感谢楼主提示,这里对新的编译器以及fortran上类似问题做出一些补充
补充:最近申威提供了新版编译器如530和710,这些C或Fortran的编译器无法使用
-OPT:IEEE_arith=1
选项,可以使用-mieee -mfloat-ieee -mieee-conformant
这几个选项代替。详细说明可以使用swgfortran -v --help
查看摘录部分输出内容如下
-mfloat-ieee Do not use VAX fp -mfloat-vax Use VAX fp -mfp-regs Use fp registers -mfp-rounding-mode= Control the generated fp rounding mode -mfp-trap-mode= Control the IEEE trap mode -mgas Assume GAS -mieee Emit IEEE-conformant code, without inexact exceptions -mieee-conformant Request IEEE-conformant math library routines (OSF/1) -mieee-with-inexact This switch lacks documentation