programas - problemas resueltos de programación en fortran 95 pdf
Fortran: matrices dinámicas frente a matriz automática Evitar la asignación de memoria (2)
Como la matriz de work
solo se usa dentro de la subrutina de bar
, puede agregarle el atributo de save
y asignarla cuando se invoque la subrutina por primera vez. Si work1
o work2
es diferente en comparación con llamadas anteriores, puede reasignar la matriz en ese caso.
Esto deja el problema de la desasignación una vez que ya no se necesita la subrutina. Si necesita llamar durante toda la vida útil del programa, no hay problema, ya que el sistema operativo debe desasignar la memoria cuando se cierra el programa. Por otro lado, si solo lo necesita durante la inicialización, la memoria permanecerá asignada incluso cuando no sea necesaria. Tal vez pueda agregar un argumento a la subrutina que le indique desasignar la matriz de work
, si el uso de memoria es un problema.
Al perfilar uno de nuestros códigos fortran, hay dos subrutinas que ocupan la mayor parte del tiempo computacional (22.1% y 17.2%). En cada rutina, ~ 5% del tiempo se gasta en asignar y liberar memoria. Estas rutinas se ven como
MODULE foo
CONTAINS
SUBROUTINE bar( ... )
...
IMPLICIT NONE
...
REAL, ALLOCATABLE, DIMENSION(:,:) :: work
...
ALLOCATE (work(size1,size2))
...
DEALLOCATE (work)
END SUBROUTINE bar
...
END MODULE foo
Estas subrutinas son llamadas del orden de 4000-5000 veces en mi punto de referencia, por lo que me gustaría deshacerme de ALLOCATE y DEALLOCATE. Cambiar estos a arreglos automáticos cambia a la salida del generador de perfiles.
MODULE foo
CONTAINS
SUBROUTINE bar( ... )
...
IMPLICIT NONE
...
REAL, DIMENSION(size1,size2) :: work
...
END SUBROUTINE bar
...
END MODULE foo
Cambia el perfil resultante a
Running Time Symbol Name
20955.0ms 17.0% __totzsp_mod_MOD_totzsps
7.0ms 0.0% malloc
5.0ms 0.0% free
2.0ms 0.0% user_trap
16192.0ms 13.2% __tomnsp_mod_MOD_tomnsps
20.0ms 0.0% free
3.0ms 0.0% malloc
1.0ms 0.0% szone_size_try_large
Parece que Gfortran los está asignando a la pila y no a ese montón, pero me preocupa cuándo ocurre cuando estas matrices se vuelven demasiado grandes.
El segundo enfoque que estoy tomando es asignar y desasignar estas matrices una vez.
work_array.f
MODULE work_array
IMPLICIT NONE
REAL(rprec), ALLOCATABLE, DIMENSION(:,:) :: work
END MODULE work_array
Asigno estos una vez en una parte diferente del código. Ahora mi subrutina parece
MODULE foo
CONTAINS
SUBROUTINE bar( ... )
...
USE work_array
IMPLICIT NONE
...
END SUBROUTINE bar
...
END MODULE foo
Sin embargo, cuando ejecuto el código ahora el perfil empeora.
Running Time Symbol Name
30584.0ms 21.6% __totzsp_mod_MOD_totzsps
3494.0ms 2.4% free
3143.0ms 2.2% malloc
27.0ms 0.0% DYLD-STUB$$malloc_zone_malloc
19.0ms 0.0% szone_free_definite_size
6.0ms 0.0% malloc_zone_malloc
24325.0ms 17.1% __tomnsp_mod_MOD_tomnsps
2937.0ms 2.0% free
2456.0ms 1.7% malloc
23.0ms 0.0% DYLD-STUB$$malloc_zone_malloc
3.0ms 0.0% szone_free_definite_size
¿De dónde vienen estos mallocs extra y libres? ¿Cómo puedo configurar esto para que yo asigne estas matrices una vez?
Si puede salir adelante con una única asignación en la inicialización del programa, entonces no hay ninguna razón para que la matriz se defina como asignable. Ponlo en común.
Si solo necesita un tamaño fijo, pero no conoce ese tamaño hasta el tiempo de ejecución, necesitará ir con su opción final, una asignación única en la inicialización. Sin embargo, no tiene sentido que esto haya incrementado el impacto en el rendimiento de la asignación. Necesitaría ver la definición y el código de asignación para decir más.
Como lo que se asigna es la memoria virtual, el "uso de la memoria" no es realmente un problema, a menos que la matriz sea tan grande que afecte el espacio de direcciones disponible.