IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Fortran Discussion :

Allocation dynamique dans subroutine d'un argument


Sujet :

Fortran

  1. #1
    Candidat au Club
    Inscrit en
    Septembre 2008
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Allocation dynamique dans subroutine d'un argument
    Bonjour,
    N'étant pas encore très subtil dans le domaine de la programmation, je voudrais si c'est possible une explication a propos du phénomène suivant, qui me laisse dubitatif:

    Je manipule des tableaux tres gros (codes 3D sur machine Blue gene), et dans un soucis vertueux de limiter leur taille, je voudrais allouer dynamiquement la mémoire.

    Un tableau nommé ind est déclaré dans le main, mais pas alloué, et je tente ensuite fourbement de l'allouer dans une subroutine dont il est un argument intent(inout), car je recupere ses dimensions dans un fichier lu dans cette routine...

    Et là, horreur a l execution, segmentation fault lorsque la subroutine alloue !

    Il semblerait que ce type de manip louche soit pas autorisée. Mais par quoi la remplacer alors??

    Merci d'avance pour votre réponse !

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Ce que tu dis faire est permis depuis le TR-15581: Enhanced Data Type Facilities (ajout à Fortran 95, intégré au standard depuis Fortran 2003).

    L'appelant a-t-il accès à l'interface de la fonction appelée ? Ton compilateur supporte t-il TR-15581 ? Peux-tu réduire ton problème à une forme présentable ici ?

  3. #3
    Candidat au Club
    Inscrit en
    Septembre 2008
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Précisons
    En premier lieu, désolé si je nespecte pas encore les formes sur le forum. bien que nouveau, je crois que vu la direction de mes études je vais le hanter assez souvent.

    - Le compilo est l' Intel ifort wrappé dans du openMP ou mpi au choix. La version est récente.

    - je vous résume la chose ci dessous.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    program main:
     
    integer, dimension(:,:), allocatable :: ind
     
    .
    .stuff
    .
     
    end
     
    subroutine index(ind)
    integer, dimension(:,:),intent(inout) :: ind
     
    .
    . stuff
    .
    open(unit=11,file=SDF_piezo)
    read (11,*) n
    allocate(ind(1:n,1:3))
    end
    Le code utilise MPI ou OpenMp.
    L'erreur se produit precisement au niveau de l'allocation, pour chaque process par un segmentation fault.


    Si vous avez une idée, je vous en serais reconnaissant.
    En relisant, il vous faut peut-être plus de code?
    Soit dit en passant, que vient faire libc dans cette affaire? MPI est codé en C peut-être?
    Désolé si je vous paraît très ignorant!

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Le problème est assez simple.

    En Fortran, il n'y a pas de « file scope » pour le code source. Tous les morceaux (unit: program, subroutine, function, ...) sont indépendant. Le compilateur ne peut pas utiliser ce qu'il voit de la subroutine quand il compile le program, quand bien même tu inverserais l'ordre.

    Exceptions à cette règle :
    • Modules: les membres se « voient » entre eux
    • units contenus dans un autre: tous se vois
    • Certains compilateurs émettent un avertissement en cas de non conformance d'appel lorsque l'appelant et l'appelé sont dans le même fichier.


    Ainsi, pour ton programme, quand tu fais « call index( ) », le compilateur ne sait pas que la sub index veut un allocatable. Au lieu de passer la référence à un allocatable, il suppose donc que index est une sub classique (à la F77) et passe donc la référence à l'espace mémoire qui contient le vecteur de ind (et non une référence à la structure descriptive de ind). Comme index s'attend à une référence à la structure descriptive, il y a faute...

    Solution: tu dois dire à program que index s'attend à recevoir un allocatable. Comment ? par une interface. Il y a alors 3 solutions :
    • Tu places index dans un module et tu « use » le module dans program
    • Tu places index dans une section « contains » de program
    • Tu décris « à bras » l'interface à index dans program


    L'ordre va de ma préférée à celle que j'aime le moins...

    Pour les 2 premières méthodes, le compilateur va générer lui-même l'interface alors que pour la 3ième, c'est toi qui le fait. Dans les 3 cas, on parle cependant d'interface explicite. Une interface implicite est celle que tu utilise présentement.

  5. #5
    Candidat au Club
    Inscrit en
    Septembre 2008
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 3
    Points : 2
    Points
    2
    Par défaut Ok
    La première solution fonctionne effectivement très bien.
    Caler la déclaration dans un module est efficace.

    Merci pour votre aide, je retiendrai la leçon...

    Cordialement,

    Nicolas

  6. #6
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 19
    Points : 22
    Points
    22
    Par défaut
    Dans la même lignée que notre ami, j'ai le même problème mais sensiblement différent.

    Dès le départ, ma subroutine est dans un module.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    program main:
    use TOTO
    real, dimension(:,:), allocatable :: TAB
     
    call LIRE(TAB)
     
    end
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    Module TOTO 
    contains 
    subroutine LIRE(TAB)
    real, dimension(:,:), allocatable, intent(inout) :: TAB
     
    .
    .
    .
    open(unit=u,file=toto)
    read (u,*) n
    allocate(TAB(1:n,1:2))
    .
    .
    .
    deallocate(TAB(1:n,1:2))
    close(u)
    end subroutine
    La compilation normale (f95 -o ...) me donne un exécutable parfait qui ne bug pas.

    Par contre, la compilation en mode débug (f95 -c -xpp) s'arrête dans le allocate avec ce message :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    internal error : code=fw-interface-iexp1-910
    Je ne comprends pas : je fais bien mon allocate, deallocate, j'appelle tout bien ...

    Merci de votre aide !

  7. #7
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Il manque au moins l'attribut allocatable dans la subroutine. Je suis surpris que le compilateur ne détecte pas l'erreur (tenter d'allocater un non allocatable).

  8. #8
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 19
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par Sylvain Bergeron Voir le message
    Il manque au moins l'attribut allocatable dans la subroutine. Je suis surpris que le compilateur ne détecte pas l'erreur (tenter d'allocater un non allocatable).
    Pardon !
    J'ai écris mon message trop vite : j'ai bien évidemment mis allocatable dans ma subroutine.
    En fait, j'ai mis un programme quelconque dans le code et j'ai simplifié au maximum.

    C'est vraiment le mode debug qui bloque ...

  9. #9
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Pure spéculation : « Internal error ... », c'est très près de « Internal Compiler Error » (ICE).

    Un ICE, c'est un bug du compilateur, pas du programme à compiler. Il faut alors soumettre le bug à l'éditeur du compilateur.

    Tu devrais essayer avec un autre compilateur.

  10. #10
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 19
    Points : 22
    Points
    22
    Par défaut
    Citation Envoyé par Sylvain Bergeron Voir le message
    Pure spéculation : « Internal error ... », c'est très près de « Internal Compiler Error » (ICE).

    Un ICE, c'est un bug du compilateur, pas du programme à compiler. Il faut alors soumettre le bug à l'éditeur du compilateur.

    Tu devrais essayer avec un autre compilateur.
    Merci !
    J'avance grâce à vous : j'ai le même programme (bourré de allocate) qui utilise une autre option de debug (f90 -o) et qui marche parfaitement !
    je vous tiens au courant

  11. #11
    Membre à l'essai
    Inscrit en
    Août 2008
    Messages
    19
    Détails du profil
    Informations forums :
    Inscription : Août 2008
    Messages : 19
    Points : 22
    Points
    22
    Par défaut
    J'ai trouvé le problème :
    trop optimiste, j'ai mis dans mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    allocate(TAB, stat =err)
    Il n'aime pas la gestion d'erreur de allocate ...
    Cela m'apprendra à être propre ...

    Merci pour votre aide en tout cas !

  12. #12
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Citation Envoyé par Sylvain Bergeron Voir le message
    Solution: tu dois dire à program que index s'attend à recevoir un allocatable. Comment ? par une interface. Il y a alors 3 solutions :
    • Tu places index dans un module et tu « use » le module dans program
    • Tu places index dans une section « contains » de program
    • Tu décris « à bras » l'interface à index dans program


    L'ordre va de ma préférée à celle que j'aime le moins...
    Hello,

    Merci pour ces explications en français, j'ai du mal à comprendre le Fortran (reprise de code scientifique sans avoir appris le langage avant, j'ai du mal encore un peu ).

    Est-il possible d'utiliser la première solution sans placer index dans module ? Je veux dire par là que j'ai plusieurs fonctions qui existent déjà (plus ou moins longues) et que l'une d'elles a ce problème d'allocatable. Et je n'ai pas envie de mettre le code de la fonction dans le module (car je soupçonne que j'aurai besoin d'autres fonctions bientôt et que je n'ai pas envie d'avoir 100 000 lignes de code dans un seul fichier). Peut-on simplement mettre une déclaration ?

  13. #13
    Modérateur

    Profil pro
    Inscrit en
    Août 2006
    Messages
    974
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 974
    Points : 1 346
    Points
    1 346
    Par défaut
    Tu veux donc avoir les avantages du module, sans y placer le code de la routine. Il y a 2 solutions utilisées en pratique respectant ces contraintes :
    • Tu combines les solutions 1 et 3 exposées plus haut : les fonctions restent externes, mais des interfaces à ces fonctions sont placées dans un module. Le « client » doit alors faire un use du module pour obtenir les interfaces. Avantages : fichiers plus petits à entretenir et risque réduit de cascade de compilation (compilation de toute la chaine de dépendance) car l'interface et la source sont séparées. Désavantages : les interfaces doivent être créées et entretenues manuellement.
    • Tu insères les fonctions dans le module à l'aide d'instruction include. Avantages : fichiers plus petits et interfaces explicites automatiques. Désavantages : cascade de compilation.

    Comme je déteste les interfaces manuelles (risque d'erreur élevé), je favorise personnellement la solution 2. Tu peux aussi tout mettre dans de petits sous-modules et tu recomposes un module « public » par des uses des sous-modules :

    Fichier LaFonction1.f90 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    module ModuleLaFonction1
    ...
    contains
       function LaFonction1(...)
    ...
    end module
    Fichier LaFonction2.f90 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    module ModuleLaFonction2
    ...
    contains
       function LaFonction2(...)
    ...
    end module
    ...

    Fichier ModuleGlobal.f90 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    module ModuleGlobal
       use ModuleLaFonction1
       use ModuleLaFonction2
    ...
       use ModuleLaFonctionN
    end module
    Fichier client quelconque :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    program ou function ou subroutine ...
       use ModuleGlobal
    ...
       x = LaFonction1(...)
    ...

  14. #14
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Points : 20 970
    Points
    20 970
    Par défaut
    Merci, ta solution me semble simple et efficace

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Allocation dynamique dans une subroutine
    Par Kaluza dans le forum Fortran
    Réponses: 1
    Dernier message: 05/05/2011, 17h53
  2. Allocation dynamique dans une fonction
    Par Kaluza dans le forum Langage
    Réponses: 8
    Dernier message: 26/04/2011, 10h23
  3. allocation dynamique dans une structure !
    Par grodashe dans le forum C
    Réponses: 2
    Dernier message: 31/12/2009, 11h17
  4. Allocation dynamique dans une fonction
    Par n0mad dans le forum Débuter
    Réponses: 5
    Dernier message: 05/02/2009, 22h42
  5. [D7] - Allocation dynamique dans une DLL
    Par david_chardonnet dans le forum Delphi
    Réponses: 6
    Dernier message: 05/07/2006, 15h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo