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

x86 32-bits / 64-bits Assembleur Discussion :

Besoin de routines ASM optimisées pour Delphi


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Inactif  

    Inscrit en
    Juillet 2004
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 46
    Points : 135
    Points
    135
    Par défaut Besoin de routines ASM optimisées pour Delphi
    Je travaille sur une bibliotheque d'outils tournes vers la gestion sous Delphi (Pascal) J'aurai besoin de quelques routines en ASM bien optimisées. Je sais que cela n'est pas très pationnant de n'ecri(re que deux ou trois routines mais j'autoriserai leut auteur à les utiliser!

    Je pense que la meme base peut servir pour les deux premieres routines.
    Si il y a un volontaire qui est interressé je pourrai expliqué mieux.

    Merci
    John
    En relite une movemem et un fillmem

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Août 2003
    Messages
    247
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2003
    Messages : 247
    Points : 276
    Points
    276
    Par défaut Re: besoin de routines en ASM
    Citation Envoyé par John Fullspeed
    mais j'autoriserai leut auteur à les utiliser!
    On croit rêver...


    De plus, tu as tout à y perdre en mettant de l'ASM dans du Delphi. Surtout pour les fonction de manipulation de mémoire que tu cite qui doivent déjà être implémentées et optimisées.

  3. #3
    Responsable Pascal, Lazarus et Assembleur


    Avatar de Alcatîz
    Homme Profil pro
    Ressources humaines
    Inscrit en
    Mars 2003
    Messages
    7 944
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ressources humaines
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2003
    Messages : 7 944
    Points : 59 432
    Points
    59 432
    Billets dans le blog
    2
    Par défaut
    Pour cela il y a un forum Offres d'emplois : http://www.developpez.net/forums/viewforum.php?f=41

    Plus sérieusement, Selenite a raison : les cas où du code Assembleur sera mieux optimisé que du code Delphi doivent être rarissimes.
    Explique-nous en détail ce que tu veux exactement !
    Règles du forum
    Cours et tutoriels Pascal, Delphi, Lazarus et Assembleur
    Avant de poser une question, consultez les FAQ Pascal, Delphi, Lazarus et Assembleur
    Mes tutoriels et sources Pascal

    Le problème en ce bas monde est que les imbéciles sont sûrs d'eux et fiers comme des coqs de basse cour, alors que les gens intelligents sont emplis de doute. [Bertrand Russell]
    La tolérance atteindra un tel niveau que les personnes intelligentes seront interdites de toute réflexion afin de ne pas offenser les imbéciles. [Fiodor Mikhaïlovitch Dostoïevski]

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Citation Envoyé par Alcatîz
    les cas où du code Assembleur sera mieux optimisé que du code Delphi doivent être rarissimes.
    Pour les librairies fournies avec Delphi, c'est peut-être le cas (encore que j'aie un doute sur FillMem.

    Sinon, le code généré par Delphi est carrément catastrophique côté optimisations, il est très facile de faire mieux en assembleur.
    Il serait temps que Borland se penche sur le problème, sans parler des bugs de l'EDI et de la VCL.

    Pour obtenir le meilleur code optimisé, je n'ai jusqu'à présent rien trouvé de mieux que le Visual C++, dans lequel on peut éventuellement intégrer le Intel C++ Compiler, un peu meilleur pour quelques points, mais pas globalement (bien évidemment, je n'ai pas testé tous les compilateurs, et mon avis n'est que relatif à ce que j'ai essayé).

    @John Fullspeed : D'après tes interventions dans d'autres posts, tu recherches avant tout la vitesse, au détriment de la lisibilité, alors un conseil : abandonne Delphi.
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

  5. #5
    Inactif  

    Inscrit en
    Juillet 2004
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 46
    Points : 135
    Points
    135
    Par défaut Rouines delphi
    En réalité les libs delphi sont pas optimisées du tout. Dans la version pro les souirces sont livrés et bien on arrive facilement à faire plus vite et il y a des routines qui font peur.
    J'ai une application de gestion assez importante (80 sources) et je me suis amusé à rechercher les fonctions que l'on utilise le plus dedans


    Les resultats sont net : avec 6 routines d'optimisées
    on va accroitre les performances de manière sensible.

    1- fonction POS recherche d'une chaine dans une autre
    2- Fonction Concat
    3- Fonction NumtoString
    4- Fonction StringToNum
    5- Fonction Movemem
    6 fonction fill mem

    Pour l'instant on a refait (en pulverisant) le POS
    Mêm Resultat pour le NumToString et le String To Num

    Avant de faire le concat je voudrais d'abord refaire le MoveMem qui risque d'être reutilise dans le concat.






    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    asm
    {     ->EAX     Pointer to source       }
    {       EDX     Pointer to destination  }
    {       ECX     Count                   }
     
            PUSH    ESI
            PUSH    EDI
     
            MOV     ESI,EAX
            MOV     EDI,EDX
     
            MOV     EAX,ECX
     
            CMP     EDI,ESI
            JA      @@down
            JE      @@exit
     
            SAR     ECX,2           { copy count DIV 4 dwords       }
            JS      @@exit
     
            REP     MOVSD
     
            MOV     ECX,EAX
            AND     ECX,03H
            REP     MOVSB           { copy count MOD 4 bytes        }
            JMP     @@exit
     
    @@down:
            LEA     ESI,[ESI+ECX-4] { point ESI to last dword of source     }
            LEA     EDI,[EDI+ECX-4] { point EDI to last dword of dest       }
     
            SAR     ECX,2           { copy count DIV 4 dwords       }
            JS      @@exit
            STD
            REP     MOVSD
     
            MOV     ECX,EAX
            AND     ECX,03H         { copy count MOD 4 bytes        }
            ADD     ESI,4-1         { point to last byte of rest    }
            ADD     EDI,4-1
            REP     MOVSB
            CLD
    @@exit:
            POP     EDI
            POP     ESI
    end;
    Cela ne me parait pas du plus rapide

    John

  6. #6
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Bonjour,

    Le problème pour ce genre de fonction, qui déplace éventuellement beaucoup de mémoire, est que l'optimisation dépend de plusieurs facteurs:

    - 1) Le processeur utilisé (dans le monde du PC, on n'optimise pas totalement de la même manière un Pentium ou un Athlon, pour ne pas parler des vieux 486 ou pire)

    - 2) Pour un type de processeur, la version (les PII, PIII et P4 ne s'optimisent pas de la même manière, idem avec les versions de l'Athlon, sans parler des versions successives qui portent le même nom)

    - 3) Et aussi, beaucoup de l'alignement des données à déplacer, ce qui implique que l'utilisateur prenne soin d'aligner ses données (ce qui est assez rarement le cas)


    On peut concevoir une routine qui prenne tout en compte avec 2 approches différentes:

    - 1) Avec des directives de compilation, ne compiler que pour un processeur donné, ce qui conduit à xxx versions du programme

    - 2) Que la routine détecte en ligne le processeur utilisé, avec l'inconvénient que l'on va certainement gagner pour les déplacements de grandes quantités de mémoire, mais aussi évidemment perdre quand on n'a pas grand chose à déplacer.


    Si tu veux te lancer là dedans, va sur les sites des fabricants Intel et AMD, tu trouveras tout ce qu'il te faut.
    (Je ne le ferais pas à ta place, un travail non négligeable pour un résultat pas très utile pour moi).

    Bon courage
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    J'ai du mal à comprendre qu'on parle d'optimiser des fonctions sur les chaines. Il est vrai que ce sont des fonction très employées et qu'il est regrétable que Boland n'est pas passé plus de temps dessus.

    Mais il faut bien comprendre qu'une fonction de concaténation de chaine n'est pas appellée 1 000 fois par secondes, et qu'il n'est donc pas vraiment indispensable de l'optimiser à fond. Elle a beau être d'après vos statistiques la fonction la plus appellée, quand moi je code une application avec Borland C++ Builder, (ce sont théoriquement les mêmes fonctions) windows me dit que le temps qu'elle bouffe aux autres processus est trop petit pour être mesurable.

    Partant de ce constat, on peut très bien faire une fonction de concaténation 10 fois plus rapide, on ne verrait pas le moindre changement, sauf en regardant du coté des cycles d'horloges, mais je vous assure que l'utilisateur lambda d'une application windows ne compte pas les cycles (C'est possible sous les dernières versions de Windows, l'OS stocke le nombre de cycles par threads) Il y a un tas de trucs dans la VCL qu'on ne peut pas utiliser pour n'importe quoi : par exemple les fonctions graphiques, pour faire une application 2D qui peut copier 2000 images à la seconde, il faut oublier la VCL.


    La copie est un problème assez complexe, et d'abord elle limitée par la vitesse de la mémoire plus que du processeur. Donc on peut faire un code merdique de copie qui va aussi vite qu'un autre ! Mais on peut aussi faire une fonction de copie en mémoire 5 fois plus lente qu'une autre. Elle a évidement été traité par Intel, et je pense par AMD aussi :

    Citation Envoyé par How to optimize for the Pentium family of microprocessors

    27.8 Moving blocks of data (All processors)

    There are several ways of moving blocks of data. The most common method is REP MOVSD, but under certain conditions other methods are faster.

    On PPlain and PMMX it is faster to move 8 bytes at a time using floating point registers if the destination is not in the cache:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    TOP:    FILD    QWORD PTR [ESI]
            FILD    QWORD PTR [ESI+8]
            FXCH
            FISTP   QWORD PTR [EDI]
            FISTP   QWORD PTR [EDI+8]
            ADD     ESI, 16
            ADD     EDI, 16
            DEC     ECX
            JNZ     TOP
    The source and destination should of course be aligned by 8. The extra time used by the slow FILD and FISTP instructions is compensated for by the fact that you only have to do half as many write operations. Note that this method is only advantageous on the PPlain and PMMX and only if the destination is not in the level 1 cache. You cannot use FLD and FSTP (without I) on arbitrary bit patterns because denormal numbers are handled slowly and certain bit patterns are not preserved unchanged.

    On the PMMX processor it is faster to use MMX instructions to move eight bytes at a time if the destination is not in the cache:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    TOP:    MOVQ    MM0,[ESI]
            MOVQ    [EDI],MM0
            ADD     ESI,8
            ADD     EDI,8
            DEC     ECX
            JNZ     TOP
    There is no need to unroll this loop or optimize it further if cache misses are expected, because memory access is the bottleneck here, not instruction execution.

    On PPro, PII and PIII processors the REP MOVSD instruction is particularly fast when the following conditions are met (see chapter 26.3):

    * both source and destination must be aligned by 8

    * direction must be forward (direction flag cleared)

    * the count (ECX) must be greater than or equal to 64

    * the difference between EDI and ESI must be numerically greater than or
    equal to 32

    * the memory type for both source and destination must be either
    writeback or write-combining (you can normally assume this).

    On the PII it is faster to use MMX registers if the above conditions are not met and the destination is likely to be in the level 1 cache. The loop may be rolled out by two, and the source and destination should of course be aligned by 8.

    On the PIII the fastest way of moving data is to use the MOVAPS instruction if the above conditions are not met or if the destination is in the level 1 or level 2 cache:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            SUB     EDI, ESI
    TOP:    MOVAPS  XMM0, [ESI]
            MOVAPS  [ESI+EDI], XMM0
            ADD     ESI, 16
            DEC     ECX
            JNZ     TOP
    Unlike FLD, MOVAPS can handle any bit pattern without problems. Remember that source and destination must be aligned by 16.

    If the number of bytes to move is not divisible by 16 then you may round up to the nearest number divisible by 16 and put some extra space at the end of the destination buffer to receive the superfluous bytes. If this is not possible then you have to move the remaining bytes by other methods.

    On the PIII you also have the option of writing directly to RAM memory without involving the cache by using the MOVNTQ or MOVNTPS instruction. This can be useful if you don't want the destination to go into a cache. MOVNTPS is only slightly faster than MOVNTQ.

    [edit] Le compilateur Borland C++ (ce doit être le même puisqu'il compile c++/pascal/asm optimise plutôt bien au niveau de l'assembleur, si ce n'est que certaines instructions lui sont inconnues, comme movzx oO) pour peu qu'on spécifie 486 et version release dans les options. [/edit]

  8. #8
    Inactif  

    Inscrit en
    Juillet 2004
    Messages
    46
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 46
    Points : 135
    Points
    135
    Par défaut Routine ASM
    Les chaines c'est le boulot de la gestion . Pour un logiciel de calcul ou de dessin pas de pb c'est pas le temps pour affichier le titre de la fenetre qui mets ton applivcation à genoux.
    Je ne vais t'assomer avec mes def mais dans mon soft par exemple j'ai plus de 2000 lignes de description de buffer: tout est dfans un format proche du PASCAL longueur+ char
    Alors tu imagines un buffer de 10 Ko divise en string dont le plus grand fais 27 : combien de zone je recupere et que je remets en forme: c'est le seul travail du logiciel: Lecture d'une carte Vitale et explosion des donnees pour remplir un feuille de soins(le format des feuilles de Soins est char[128} a piocher dans la Vitale
    Alors moi la concatenation c'est peut etre 3 ou 4 000 fois pour UNE factures
    Alors imagines que la CQ elle gere 1 milliard de factures. Tu compends mieux l'interet d'aller vite: secondes de gagner c'est 1 millirad de seconde de gagne. Avec ce genre d'optimisation certains mettent 1 lminute la ou d'autre mettent 12 secondes l'utilisateurs esty pas fou il s'en rends compte

    Alors certains seront interresse par la performance de move, d'autre du concat et l'autre du sin. A cvhacun son trip!

    Pour les moves je vois avec lplaisir que le passage par le FPU a toujours de beau reste. C'est une option que j'ai eu l'occasion, dans une autre vie, de travailler avec les ingenieurs de chez Motorola. Mais elle n'est pas universelle.
    Moi mon r^ve c'est de faire un move avec le FPU et EN MEME temps avec l'unité entiere. Puisse qu'elles sont parralléle chacune un morceau à recopier et en avant: la proportion pour chaque unité dpendant des capacité des deux unités.

    J'avoue que je vais essayer les exemples pour essaye de voir
    Mais visiblement on peut aller plus vite...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    TOP:    FILD    QWORD PTR [ESI]
            FILD    QWORD PTR [ESI+8]
            FXCH
            FISTP   QWORD PTR [EDI]
            FISTP   QWORD PTR [EDI+8]
            ADD     ESI, 16
            ADD     EDI, 16
            DEC     ECX
            JNZ     TOP
    dans cette routine le temps du move lui même est on peut faire confiance à leurs auteurs par contre au niveau de l'algo general on peut faire mieux
    C'est comme cela que c'est ecrit sur le mac:


    au lieu de faire une boucle sur chaque Move(ou FISTP) on fait un switch
    avec 16 (par exemple etiquettes)

    et on fait

    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
    21
    22
    23
    @debut
       if (nb < 16) goto fin
     
       1: Move
           Store
           dec Nb
     
       2: Move
           Store
           dec Nb
       4: Move
           Store
           dec Nb
       14: Move
           Store
           dec Nb
      1 5: Move
           Store
          dec Nb
       16: Move
           Store
          dec Nb
      ii nb>16 goto 1:
    (petit calcul pour calculer le saut differentiel pour les derniers octets)

    Cela devrait le faire. Quand pensez vous?
    John

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Citation Envoyé par John Fullspeed
    Quand pensez vous?
    Le plus souvent possible.

    Citation Envoyé par John Fullspeed
    10 Ko divise en string dont le plus grand fais 27
    En clair, tes concats vont ajouter au maximum 27 caractères à une chaine ?
    Si c'est ça, tu auras de la peine à optimiser vraiment par rapport aux routines classiques.

    Citation Envoyé par John Fullspeed
    Tu compends mieux l'interet d'aller vite: (1) seconde de gagner c'est 1 millirad de seconde de gagne.
    Que viennent faire les millirad ici ?
    Blague à part, tu auras de la peine à gagner 1 seconde en gérant 10K au total, même avec plein de concat etc...
    Si la CQ, comme tu dis, avait besoin de gagner 1 seconde / facture (si j'ai bien compris ton problème), en gérant 1 milliard de factures, elle n'aurait jamais réussi à faire quoi que ce soit.
    1 milliard de secondes = 31.69 années, en prenant 1 année = 365.25 jours.

    Avec cela, si tu veux quand même optimiser:
    Plutôt que d'uliliser la FPU, utilise les MMX, c'est plus performant (et oui, je sais bien que les MMX utilisent la FPU, mais c'est quand même plus performant).

    Dans les 2 cas, il est nécessaire d'aligner tes données sur un multiple de 8, et même encore mieux, multiple de 16.
    De plus, il serait bon que les données aient une longueur multiple de 16.

    Tu peux effectivement envisager de dérouler la boucle, mais les manuels de Intel et AMD pour l'optimisation ne le recommandent pas, donc...
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    Je vais pas être très original, mais effectivement, comme l'affirme Thewo, tu ne gagneras jamais une seconde, pis comme j'ai pas envie d'être blague à part, la sécu a pas un milliard de fiche, et elle ne gère pas un milliard de fiches d'un coups, et elle fait pas toutes les minutes un traitement d'un milliards de fiches qui dure dix secondes chacune avec trois millions de concaténations.

    Ensuite, ca a été dit au début par Alcatiz, et je le maintiens encore, il est très rare qu'on ait besoin d'utiliser de l'optimisation asm. Et particulièrement pas quand il s'agit de routines générales ! Vous cherchez à optimiser une fonction qui agit sur des données dont on ne sait pratiquement rien. Alignées ? non alignées ? De taille > 16 ? de distance > 32 ? Et en particulier dans le cas de la concaténation, c'est pas aligné, les opérandes peuvent être n'importe où. Et finalement, si vous avez lu un minimum la citation, vous vous rendez compte que vous ne pouvez pas faire d'optimisation qui marche à tous les coups.

    Dans ces cas-là, on dit qu'il est inutile de passer des heures à s'emmerder avec l'assembleur, lorsque l'on peut écrire des routines, pas meilleures, pas pires, dans un langage évolué en une poignée de minutes. C'est à peu près ce que ca veut dire qu'il est rare d'avoir recours à l'assembleur. Pour optimiser, il faut déjà savoir quand c'est pertinent de se creuser la tête. Il me semble assez répendu qu'une qualité très apréciée des programmeurs, est de programmer vite.


    Blustuff.

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    633
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 633
    Points : 711
    Points
    711
    Par défaut
    Bonjour,

    Oups, j'avais oublié de répondre à ceci:
    Citation Envoyé par Blustuff
    Le compilateur Borland C++ (ce doit être le même puisqu'il compile c++/pascal/asm optimise plutôt bien au niveau de l'assembleur, si ce n'est que certaines instructions lui sont inconnues, comme movzx oO) pour peu qu'on spécifie 486 et version release dans les options.
    C'est presque vrai, pour le 486, C++ Builder générait du code presque bon.

    Mais, depuis, les processeurs ont évolué, et disposent de possibilités d'optimisation que ni Delphi, ni C++ Builder ne prennent en compte. Ils se contentent de continuer à générer leur code 486.

    PS: générer du code optimisé pour les processeurs récents n'empêche pas le fonctionnement sur un 486, tant que l'on n'utilise pas les MMX et autres SSE
    Compilation sans erreur ne signifie pas programme sans erreur.
    L'indentation n'a pas été imaginée pour faire beau, mais pour faciliter la lecture des programmes.

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    842
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 842
    Points : 696
    Points
    696
    Par défaut
    486 correspond au jeu d'instructions, et non à "optimisé pour un 486". Du reste que voulez vous que le compilateur fasse ? Il organise bien les instructions, les alternants pour permettre les executions en // ou le pairing du PPlain et PMMX. Tout cela n'était pas nécessaire pour le 486. Difficile d'implementer beaucoup plus d'optimisations non spécifiques.

Discussions similaires

  1. Réponses: 2
    Dernier message: 22/08/2007, 14h39
  2. Version de Windows pour Delphi 8
    Par alainvh dans le forum EDI
    Réponses: 8
    Dernier message: 22/06/2004, 11h37
  3. C/asm : problème pour link
    Par SteelBox dans le forum Autres éditeurs
    Réponses: 3
    Dernier message: 06/04/2004, 23h03
  4. Réponses: 2
    Dernier message: 18/09/2003, 13h46
  5. [Kylix] CLX pour Delphi 6 ?
    Par amelie gaya dans le forum EDI
    Réponses: 2
    Dernier message: 24/05/2002, 09h12

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