fortran中静态变量的性能



在Fortran中,如果不显式声明子例程或函数为recursive,则不能递归调用它们。一位Fortran程序员告诉我,正因为如此,编译器可以为所有局部变量分配静态存储,这提高了程序的速度。我对这种说法感到非常惊讶,因为现在大多数处理器都经过了优化,可以快速引用堆栈。我认为,从静态地址加载的局部变量可能会导致大量缓存未命中,因为与堆栈相反,其他子例程不会使用静态地址。

静态地址的局部变量真的有加速吗?哪些其他优化可能会禁止递归子例程和函数?

您咨询的Fortran程序员有一些倒退的事情-对递归的限制是因为以前(假设的)编译器只能为任何变量分配静态存储。绩效大多是一个无关紧要的考虑因素——尽管我想如果你根本做不到什么,那么你就不太可能很快做到。

早期的Fortran(F77及以前版本)被设计为允许整个程序的内存需求在程序运行之前由Fortran处理器静态确定。这适用于那个时代的一些有限的机器架构。在这种"必须能够通过静态分析计算总内存"的限制下,很难让递归(内存需求可能因程序输入而异)之类的东西在一般情况下工作,因此语言不允许这样做

具体的处理器如何实际实现该语言取决于他们——如果他们想对局部变量使用基于堆栈的stoge,那么他们可以。在标准边界之外编写的Fortran程序员可能在历史上一直习惯于期望使用静态存储(未保存的变量在调用之间记住它们的值等)所获得的行为,但对底层实现敏感的程序并不符合标准。

(具有此限制的体系结构在F90时已经过时。该标准引入了几种方式,程序内存需求可以根据程序输入动态变化——最明显的是分配语句,但现在也允许使用自动变量。)

对于较小的未保存的局部变量(标量),相关存储在堆栈上的速度很可能更快(假设硬件合理)。

区分能够递归的过程和不能递归的过程在今天仍然有一些实际价值——如果局部变量很大(数组或长字符),那么它可能根本不适合堆栈。为了避免这种情况,如果一个过程没有被标记为递归,并且数组的大小已知,那么fortran处理器可以使用静态存储。这避免了与动态内存分配相关的任何开销,动态内存分配可能相当昂贵。如果过程被标记为递归(并且局部变量未保存),或者在编译时数组的大小未知,那么fortran处理器别无选择——它要么希望数据适合堆栈,要么使用动态内存分配。

这只是因为一些大型机cpu根本没有堆栈(例如s/360)。编译器必须生成特殊的代码来模拟它。因此,一个非递归函数包含了更简单/更少的代码。我不知道这在今天是否仍然相关。

引用特定地址而不是堆栈上的位置并不意味着会有更多的缓存未命中。相反,静态地址简化了优化器的工作,因为它可以根据它们的使用情况将它们放在内存中。

最新更新