En este programa de muestra estoy haciendo lo mismo (al menos eso creo) de dos maneras diferentes. Estoy ejecutando esto en mi PC con Linux y monitoreando el uso de memoria con top. Usando gfortran encuentro que en la primera forma (entre "1" y "2") la memoria utilizada es de 8.2GB, mientras que en la segunda forma (entre "2" y "3") el uso de la memoria es de 3.0GB. Con el compilador de Intel, la diferencia es aún mayor: 10GB frente a 3GB. Esto parece una penalización excesiva por usar punteros. ¿Por qué pasó esto?
program test
implicit none
type nodesType
integer:: nnodes
integer,dimension(:),pointer:: nodes
end type nodesType
type nodesType2
integer:: nnodes
integer,dimension(4):: nodes
end type nodesType2
type(nodesType),dimension(:),allocatable:: FaceList
type(nodesType2),dimension(:),allocatable:: FaceList2
integer:: n,i
n = 100000000
print *, '1'
read(*,*)
allocate(FaceList(n))
do i=1,n
FaceList(i)%nnodes = 4
allocate(FaceList(i)%nodes(4))
FaceList(i)%nodes(1:4) = (/1,2,3,4/)
end do
print *, '2'
read(*,*)
do i=1,n
deallocate(FaceList(i)%nodes)
end do
deallocate(FaceList)
allocate(FaceList2(n))
do i=1,n
FaceList2(i)%nnodes = 4
FaceList2(i)%nodes(1:4) = (/1,2,3,4/)
end do
print *, '3'
read(*,*)
end program test
El fondo es el refinamiento de la red local. Elegí la lista vinculada para agregar y eliminar caras fácilmente. El número de nodos es 4 de forma predeterminada, pero puede aumentar según los refinamientos locales.
performance
fortran
Chris
fuente
fuente
Respuestas:
Realmente no sé cómo funcionan los compiladores fortran, pero según las características del lenguaje, puedo adivinar.
Las matrices dinámicas en fortran vienen con metadatos para trabajar con funciones intrínsecas como forma, tamaño, lbound, ubound y asignadas o asociadas (asignables vs punteros). Para matrices grandes, el tamaño de los metadatos es insignificante, pero para matrices pequeñas, como en su caso, puede sumar. En su caso, las matrices dinámicas de tamaño 4 probablemente tengan más metadatos que datos reales, lo que está llevando a su globo de uso de memoria.
Recomiendo encarecidamente contra la memoria dinámica en la parte inferior de sus estructuras. Si está escribiendo un código que trata con sistemas físicos en cierto número de dimensiones, puede configurarlo como una macro y volver a compilar. Si se trata de gráficos, puede asignar estáticamente un límite superior en el número de bordes o me gusta. Si se trata de un sistema que realmente necesita un control dinámico de memoria de grano fino, entonces probablemente sea mejor cambiar a C.
fuente
n
punteros necesarios para el primer método.Como ha señalado maxhutch , el problema es probablemente la gran cantidad de asignaciones de memoria separadas. Sin embargo, además de los metadatos, probablemente existan los datos y la alineación adicionales que necesita el administrador de memoria, es decir, probablemente esté redondeando cada asignación a un múltiplo de 64 bytes o más.
Para evitar asignar un pequeño fragmento para cada nodo, puede intentar asignar a cada nodo una parte de una matriz preasignada:
Mi Fortran está un poco oxidado, pero lo anterior debería funcionar, si no en principio.
Todavía tendría los gastos generales de lo que su compilador Fortran cree que necesita almacenar para un tipo de PUNTERO, pero no tendrá los gastos generales del administrador de memoria.
fuente
nodesType%nodes
es un puntero a una matriz dinámica.Oh. Este es el mismo problema que sufrí. Esta pregunta es muy antigua, pero sugiero un estilo de código un poco diferente. Mi problema era la matriz de sentencias asignables en el tipo de datos derivados, como sigue el código.
De alguna prueba, confirme que si utilicé la instrucción asignable o la instrucción de puntero en el tipo derivado como código siguiente sobre cuatro casos, la pérdida de memoria ocurre muy grande. En mi caso, rojo el archivo de 520MB de tamaño. Pero el uso de memoria fue de 4 GB en modo de lanzamiento en Intel Fortran. ¡Eso es 8 veces más grande!
La pérdida de memoria no ocurre cuando uso una instrucción asignable o de puntero sin tipo derivado. En mi opinión, si declaro la variable de tipo asignable o de puntero en tipo derivado y asigno grande la variable de tipo derivado no variable variable en el tipo derivado, se produce una fuga de memoria. Para resolver este problema, cambié mi código que no incluye el tipo derivado como código siguiente.
o que tal este estilo?
La variable NumNodes significa el número de nodos en cada cara y la variable Node es el número de nodo que coincide con la variable NumNodes. Tal vez no se haya producido una pérdida de memoria en este estilo de código, creo.
fuente