ifort与gfortran数组初始化运行时性能对比及性能差异原因咨询
为什么ifort和gfortran在数组初始化场景下性能差异这么大?
我来帮你拆解这个性能差异的问题——这本质上是两个编译器在优化策略和调试标志设计上的不同导致的,先理清楚测试背景,再一步步分析原因:
测试基础信息
环境与编译命令
- 系统:CentOS Linux 7
- 编译器:gfortran 10.1.0、ifort 19.1.3.304
- 带初始化标志的编译命令:
# ifort ifort array-initialize.f90 -O3 -init=arrays,zero,minus_huge,snan -g -o intel-array.out # gfortran gfortran array-initialize.f90 -O3 -finit-local-zero -finit-integer=-2147483647 -finit-real=snan -finit-logical=True -finit-derived -g -o gnu-array.out
测试代码
program array_initialize implicit none integer :: i, j, limit real :: my_max real :: start, finish my_max = -1.0 limit = 10000 call cpu_time(start) do j=1, limit do i=1, limit my_max = max(my_max, initializer(i, j)) end do end do call cpu_time(finish) print *, my_max print '("Time = ", f6.3," seconds.")', finish-start contains function initializer(i, j) implicit none real :: initializer real :: arr(2) integer :: i, j arr(1) = -1.0/(2*i+j+1) arr(2) = -1.0/(2*j+i+1) initializer = max(arr(1), arr(2)) end function end program array_initialize
关键测试结果
| 测试场景 | gfortran耗时 | ifort耗时 |
|---|---|---|
| 开启数组初始化标志 | 0.096秒 | 0.392秒 |
| 关闭数组初始化标志 | 0.098秒 | 0.057秒 |
| 数组替换为单独变量 | 0.099秒 | 0.065秒 |
性能差异的核心原因
1. gfortran:直接跳过了冗余的初始化
gfortran在-O3优化级别下,做了一个很聪明的判断:
函数initializer里的数组arr(2),在声明之后立刻被完全赋值覆盖(arr(1)和arr(2)都被重新赋值,没有任何地方会读取初始化后的值)。所以哪怕你加了-finit-local-zero这些初始化标志,gfortran的优化器直接把这些初始化操作当成冗余代码删掉了——这就是为什么开不开初始化标志,gfortran的耗时几乎没变化。
2. ifort:死磕初始化,没做冗余消除
ifort的-init=arrays,...标志本质是为调试设计的,目的是确保所有数组都被初始化,避免未定义行为。哪怕在-O3优化模式下,它也没针对“初始化后立刻被完全覆盖”的场景做优化:
每次调用initializer,ifort都会先把arr(2)的两个元素按规则初始化,然后才执行后续的赋值。而这个函数被调用了1亿次(10000×10000),每次多出来的初始化操作积少成多,直接把耗时从0.057秒拉到了0.392秒。
3. 数组换变量的场景验证
当你把数组换成两个单独变量时,不管是gfortran还是ifort,都能轻易判断变量的初始化是冗余的(或者变量初始化的开销远小于数组),所以两者的性能差距就缩小了,和关闭初始化标志时的结果接近。
总结
这个差异既不是gfortran没执行初始化,也不是ifort初始化效率低,完全是两个编译器的策略不同:
- gfortran在优化模式下会激进地消除冗余操作,哪怕是你指定的初始化;
- ifort的
-init标志在优化模式下依然优先保证初始化的执行,适合调试,不适合性能敏感的场景。
内容的提问来源于stack exchange,提问作者nadavhalahmi
相关产品推荐
相关产品推荐

