allocate语句的顺序或语法是否会影响性能? (的Fortran)

时间:2016-03-11 16:45:21

标签: memory fortran dynamic-memory-allocation

由于在将代码从静态分配传递到动态分配时出现性能问题,我开始讨论如何在Fortran代码中管理内存分配。

具体来说,在这个问题中,如果用于allocate语句的顺序或语法有所不同,我就会徘徊。也就是说,分配矢量是否有任何区别:

allocate(x(DIM),y(DIM))

allocate(x(DIM))
allocate(y(DIM))

语法表明,在第一种情况下,程序会立即为向量分配所有空间,可能会提高性能,而在第二种情况下,它必须一次为一个向量分配空间,以这种方式他们可能会彼此远离。如果没有,也就是说,如果语法没有任何区别,我会徘徊,如果有办法控制该分配(例如,为所有空间分配一个向量并使用指针来解决分配为多个变量的空间)。

最后,我现在注意到我甚至不知道一件事:一个分配语句保证至少一个向量占用内存中的一个连续空间(或者它能做到最好?)。

2 个答案:

答案 0 :(得分:2)

从语言标准的角度来看,如何编写它们都是可能的。编译器可以自由地在需要的地方分配数组。它通常调用malloc()来分配一些内存,并从该部分生成可分配的数组。

是否可以在单个allocate语句中为两个不同的数组分配单个内存取决于编译器,但我没有听说过任何编译器这样做。

我刚刚确认我的gfortran在这种情况下只调用__builtin_malloc两次。

High Performance Mark已经指出了另一个问题。即使成功返回malloc(),仍可能无法分配实际的内存页面。在Linux上,当您第一次访问该阵列时发生。

如果那些阵列在内存中相互靠近或不相交,我认为这不太重要。如果需要,CPU可以缓存来自地址空间不同区域的数组。

有没有办法控制分配?是的,您可以通过自己的分配器重载malloc,这会做一些聪明的事情。它可以用于始终将内存对齐到32个字节或类似的目的(example)。是否通过以某种方式彼此接近来分配事物来提高代码的性能是值得怀疑的,但是你可以尝试一下。 (当然这完全是依赖于编译器的东西,编译器根本不需要使用malloc(),但大多数情况下都是这样。)不幸的是,这仅在调用malloc时不起作用内联。

答案 1 :(得分:2)

这里至少有两个问题,首先是分配内存所花费的时间,其次是数组中内存的位置以及这对性能的影响。虽然High Performance Mark建议的链接和Vadimir F的答案涵盖了这一点,但我对实际的分配过程了解不多。

从您的问题来看,似乎您对数组彼此相邻所给出的缓存命中和内存位置更感兴趣。我猜不会保证allocate语句确保两个数组在内存中彼此相邻。这是基于在一个类型中分配数组,在fortran 2003 MAY 2004 WORKING DRAFT J3/04-007 standard

  

注4.20   除非结构包含SEQUENCE语句,否则使用此术语绝不意味着这些组件以此顺序或任何其他顺序存储。也没有要求使用连续存储。

从与Vadimir F的讨论中,如果你将可分配数组放在一个类型中并使用sequence关键字,例如

type botharrays
    SEQUENCE
    double precision, dimension(:), allocatable :: x, y
end type

这并不能确保它们在内存中被分配为相邻的。对于静态数组或大量变量,顺序类型听起来像它可能像“为所有空间分配向量并使用指针来寻址分配为多个变量的空间”的想法。我认为公共块(Fortran 77)允许您指定数组的内存位置与内存中的变量之间的关系,但也不能使用可分配的数组。

简而言之,我认为这意味着您无法确保两个已分配的数组在内存中相邻。即使你可以,我也看不出这将如何减少缓存未命中或提高性能。即使您通常一起使用这两者,除非数组足够小以至于缓存将在一次读取中包含多个数组(假设允许读取超出数组边界),您将无法从内存位置中受益。