是Intel的编译器出问题了吗 ?

intel_iclifort 2010-02-28 11:42:53
是Intel的编译器出问题了吗?

随着越来越多的HPC系统采用了基于IA架构的硬件平台,大量已有的FORTRAN程序开始被移植到IA平台。由于硬件体系结构的变更,使用新平台上的编译器对原有代码进行重新编译就成为了这些移植工作中一个必不可少的步骤。Intel Fortran编译器由于其在IA系统上的良好性能而成为了众多开发人员的首选工具。

在新平台上使用Intel编译器的过程中程序员有时候会碰到一些奇怪的现象:
- 同一段程序多次运行,接收同样的输入,输出的数值结果却是随机变化的不确定值
- 同一段程序在没有打开编译器的优化选项的时候能够给出正确的数值输出结果,但是在打开某些优化选项的时候却给出错误的结果,有时甚至会出现程序崩溃的现象

由于这些程序在原有的系统上往往都是能够正常运行的,在这种情况下大多数人的第一反应就是:Intel的编译器出了问题!但是事实真的是这样吗?我看未必。这时可能有人要问了:明明我的程序在先前的系统上运行的好好的,现在仅仅是换了一个编译器,或是加了一个优化开关就出错了,难道这不是编译器的问题吗?事情往往没有我们想象的那么简单。大量已有的程序调试经验告诉我们:如果一个程序出现了上述的两种情况,那么极有可能是程序的代码中存在bug,而不是编译器生成了错误的代码。能引起上面所述现象的常见程序错误有这么两类:


程序中存在未经过初始化就引用的变量

使用Intel编译器时,未经初始化的自动变量在运行时会具有随机的初始值。由于语言标准和具体编译器实现的原因,某些平台上的编译器具有自动把未初始化的变量设为0的选项。那么在这类平台上开发进行Fortran程序开发的人员很可能会养成变量不初始化就加以引用的习惯。当这些程序被移植到新平台上后,由于Intel的编译器不支持这一功能,那么程序编译虽然可以通过,但运行时就会输出随机变化的不确定值。

程序中存在数组越界访问

对某个数组的越界访问往往会破坏其它相邻数据结构的值,有时甚至会出现内存访问错误导致程序崩溃。这时有人会问,既然越界访问存在,那么在先前的系统上为什么一点问题都没有呢?这是因为不同平台上的内存分配机制和策略是不同的,同一个平台上使用不同的优化选项也会导致运行时采用不同的内存的分配。所以有时就会出现同一个程序打开优化和不打开优化时有完全不同的行为或输出结果

针对上面的程序问题,Intel编译器提供了丰富的运行时检查选项来帮助我们找出相关的错误。下面列出几个最常用的供大家参考,这样在出现上述情况时可以自己先测试一下。

-CU (Linux), /CU (Windows)
打开针对未初始化变量进行引用的运行时检查。如果一个非SAVE属性且类型为整型,浮点型,复数型或逻辑型的局部变量在写入之前就进行了读操作,那么程序将发生一个运行错误。这里给出一个简单的例子。

$ cat test.f90
real ra
write (*,*) "ra = ", ra
end

$ ifort -CU test.f90
$./a.out
forrtl: severe (193): Run-Time Check Failure. The variable 'main$test_$RA' is being used without being defined
Image PC Routine Line Source
a.out 0000000000470F0D Unknown Unknown Unknown
a.out 000000000046FA15 Unknown Unknown Unknown
a.out 00000000004202D9 Unknown Unknown Unknown
a.out 0000000000403CEF Unknown Unknown Unknown
a.out 0000000000404708 Unknown Unknown Unknown
a.out 0000000000402B76 Unknown Unknown Unknown
a.out 0000000000402ADC Unknown Unknown Unknown
libc.so.6 0000003D48A1D974 Unknown Unknown Unknown
a.out 00000000004029D9 Unknown Unknown Unknown

可以看到对未初始化变量“ra”的引用在打开“-CU”选项的情况下引发了一个运行时错误,而且错误信息指出了是变量“ra”未经初始化就被引用。

-CB (Linux),/CB (Windows)
打开对数组越界访问的编译时和运行时检查。当程序存在超过数组下标界限的访问时给出一个错误。例如:
$ cat test.f90
real ra(10)
integer i
ra = 0.0
i = 11
write (*,*) "ra = ", ra(i)
end

$ ifort -CB test.f90
$ ./a.out
forrtl: severe (408): fort: (2): Subscript #1 of the array RA has value 11 which is greater than the upper bound of 10

Image PC Routine Line Source
a.out 0000000000470F5D Unknown Unknown Unknown
a.out 000000000046FA65 Unknown Unknown Unknown
a.out 0000000000420329 Unknown Unknown Unknown
a.out 0000000000403D3F Unknown Unknown Unknown
a.out 0000000000404142 Unknown Unknown Unknown
a.out 0000000000402BB8 Unknown Unknown Unknown
a.out 0000000000402ADC Unknown Unknown Unknown
libc.so.6 0000003D48A1D974 Unknown Unknown Unknown
a.out 00000000004029D9 Unknown Unknown Unknown

可以看到,打开-CB 选项后对数组“ra”进行的越界访问出发了运行时错误,这样程序员很快就可以发现并改正错误代码。

-zero (Linux),/Qzero (Windows)
把所有未初始化,具有save属性且类型为整型,浮点型,复数型或逻辑型的局部变量自动初始化为0。
-save (Linux),/Qsave (Windows)
把所有非递归过程中且没有AUTOMATIC属性的局部变量分配到静态存储空间,也就是相当于把他们加上了SAVE属性。

把上面两个选项同时使用可以起到把未初始化的变量自动设置为零的功能,可以用来判断出现问题的程序中是否存在引用未初始化变量的问题。如果加上这两个选项后有问题的程序能够始终给出稳定的正确输出结果,那么代码中就很有可能存在变量未初始化的问题。这里要注意的是由于save选项改变了变量内存分配策略,很有可能带来其它的副作用,所以即使程序在加上这两个选项后可以解决问题,得到输出正确结果,也不要用它们作为最终解决方案,而是要找出代码中的错误并加以改正。


结束语

上面我们讨论了在把其他平台上的Fortran程序移植到使用Intel编译器的IA平台上时可能遇到的问题,以及在把这些看似编译器错误引起的问题提交给Intel之前进行进一步确认的常用编译器选项,希望能对大家的工作有所帮助。
...全文
751 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
intel_iclifort 2011-12-30
  • 打赏
  • 举报
回复
在最新编译器版本中,推荐使用如下的选项:

-warn

-check
alexander_david 2010-03-09
  • 打赏
  • 举报
回复
谢谢。长知识了。
回复太短了?
suling2002 2010-03-02
  • 打赏
  • 举报
回复
沙发!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

566

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧