6 votes

Erreur d'exécution Fortran execute_command_line, dépend de la consommation de mémoire

J'obtiens des erreurs d'exécution lorsque j'essaie de créer un répertoire en utilisant l'intrinsèque execute_command_line en Fortran. L'erreur se produit à la fois avec Ifort (18.0.3 20180410) et gfortran (4.8.5). Voici un exemple minimal qui échoue avec tous les drapeaux de compilation que j'utilise :

PROGRAM directory_test

    IMPLICIT NONE

    INTEGER :: cstat, estat, i, j
    CHARACTER(LEN=100) :: cmsg

    REAL, DIMENSION(:,:), ALLOCATABLE :: field
    INTEGER, PARAMETER :: fieldsize = 80000

    allocate(field(fieldsize,fieldsize))
    do j=1, fieldsize
        do i=1, fieldsize
            field(i,j) = real(i+j)
        end do
    end do

    call execute_command_line('mkdir -p newdir', WAIT=.true., EXITSTAT=estat, CMDSTAT=cstat, CMDMSG=cmsg)

    write(*,*) 'estat: ', estat
    write(*,*) 'cstat: ', cstat
    write(*,*) 'cmsg:  ', cmsg

END PROGRAM directory_test

Sortie ifort :
estat : 0
cstat : 124
cmsg : Commande non valide fournie à EXECUTE_COMMAND_LINE

Sortie gfortran :
estat : -520880432
cstat : 1
cmsg : Impossible d'obtenir l'état de terminaison de l'interpréteur de langage de commande

Voici le piège : le programme fonctionne très bien tant que la taille du tableau est suffisamment petite. Pour moi, le seuil est d'environ la moitié de la mémoire physique utilisée (ajustez la valeur de "fieldsize" si vous voulez essayer le code). Si le tableau est plus grand que cela, l'erreur se produit. Si le tableau est plus petit, le code s'exécute sans erreur et le répertoire est créé. Les machines que j'ai utilisées pour tester ceci ont toutes 2 CPUs physiques et 128GB-256GB de RAM.
Qu'est-ce que je fais de mal ?

SYSTÈME D'EXPLOITATION : Linux, Opensuse 42.3
shell : bash
système de fichiers : Ext4

Edit : le problème n'est pas exclusif à "execute_command_line()". En essayant de faire la même chose avec "call system()", j'obtiens un comportement similaire. Le nouveau répertoire n'est pas créé dans les cas où la méthode originale échoue avec une erreur d'exécution. Des tests supplémentaires sur des machines à deux sockets plus petites/anciennes, jusqu'à 48 Go de RAM disponible, donnent les mêmes résultats. Certains échouent plus tôt, d'autres ont besoin de presque toute la mémoire physique occupée par le programme pour échouer. Malheureusement, je n'ai pas de machine à socket unique à tester pour le moment.

3voto

janneb Points 17303

Ainsi, la façon dont EXECUTE_COMMAND_LINE ainsi que les intrinsèques SYSTEM sont implémentés sous Linux est que d'abord le processus appelle l'appel syscall fork(), qui crée un clone du processus. Ensuite, l'enfant appelle exec() qui remplace ce processus par le nouveau processus à exécuter.

Ainsi, même si le deuxième processus bifurqué est de très courte durée avant d'être remplacé par le nouveau processus exec()ed, le système a toujours besoin de suffisamment de mémoire virtuelle pour le processus original et le processus enfant bifurqué. Sous Linux, si vous avez accès au superutilisateur, vous pouvez régler les limites (en fonction de la mémoire physique) avec les différents boutons "overcommit".

Si possible, une façon de contourner ce problème est d'appeler EXECUTE_COMMAND_LINE avant d'allouer beaucoup de mémoire, ou après l'avoir désallouée.

1voto

Steve Lionel Points 520

Vous avez également posté ceci dans le Forum Intel Fortran pour Linux . Les réponses indiquaient que votre allocation de tableau utilisait toute la mémoire virtuelle disponible, laissant une mémoire insuffisante pour EXECUTE_COMMAND_LINE ou les alternatives. Trois compilateurs différents ont tous donné des erreurs sur votre exemple - NAGfor a été le plus utile avec une erreur "mémoire virtuelle insuffisante".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X