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

Langage Delphi Discussion :

Différence de temps d'exécution entre 32bits et 64bits, avec des tableaux statiques


Sujet :

Langage Delphi

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2024
    Messages : 5
    Par défaut Différence de temps d'exécution entre 32bits et 64bits, avec des tableaux statiques
    Bonjour à tous,
    J'observe des différences notables de temps d'exécution pour le même code, compilé en 32 bits et 64 bits.
    Le code suivant est un extrait d'une application plus complexe.
    Si vous l'exécutez, le code en 64 bits prendra toujours plus de temps que celui en 32 bits (parfois 3x plus selon la taille du tableau utilisée). Le code peut être testé en utilisant des tableaux de 1, 2 ou 3 reels (options 1, 2 ou 3 dans le code)
    Si on regarde le code assembleur en mode debug, il est différent en 32 et 64 bits.

    Quelqu'un aurait des idées pour faire fonctionner le code 64 bits aussi rapidement que le code 32 bits? (avec des options de compilation ou des ajustements dans le code ?)
    Merci
    Précision : J'utilise Delphi 12.1

    Voici le code :
    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
     
    	Type
    	  {$IF Defined(WIN64)}
    	  t_reel = double;
    	  {$ELSE}
    	  t_reel = single;
    	  {$ENDIF}
     
    	  t_vect1 = Array[0..0] OF t_reel;
    	  t_vect2 = Array[0..1] OF t_reel;
    	  t_vect3 = Array[0..2] OF t_reel;
     
    	const
    	  k_vect1_nul  : t_vect1 = (0.0);
    	  k_vect2_nul  : t_vect2 = (0.0, 0.0);
    	  k_vect3_nul  : t_vect3 = (0.0, 0.0, 0.0);
     
    	procedure test();
    	var iLoop:integer;
    		l_SW1:TStopwatch;
    		l_vec1: t_vect1;
    		l_vec2: t_vect2;
    		l_vec3: t_vect3;
    	begin
    	  l_SW1:=TSTopWatch.StartNew;
     
    	  iLoop:=0;
    	  while (iLoop<900000000) do begin
    		//l_vec1 := k_vect1_nul;  //option 1
    		//l_vec2 := k_vect2_nul;  //option 2
    		l_vec3 := k_vect3_nul;    //option 3
    		inc(iLoop);
    	  end;
     
    	  l_SW1.Stop;
    	  Showmessage(intToStr(l_SW1.ElapsedTicks)+' ticks / '+intToStr(l_SW1.ElapsedMilliseconds)+' ms');
    	end;

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 940
    Billets dans le blog
    6
    Par défaut
    Bonsoir,
    Est-ce vraiment le même code, puisqu'il ne traite pas des données de même type ?
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  3. #3
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 096
    Par défaut
    Si c'est des tableau si petit, pourquoi pas plutôt des record, un peut comme le TPointF et TPoint3D, voire TVector et TVector3D
    Sauf si ton exemple est totalement biaisé, pour ma part, je travaille les performances plutôt sur de grand tableau genre 1Mo dont le SetLength est consommateur de temps, sous FastMM, l'allocation est quasi-instantanée mais l'initialisation à zéro prend 99% du temps.

    Que donne un Move au lieu d'une affecation Move(k_vect3_nul, l_vec3, SizeOf(l_vec3)); fonctionnera pour des tableaux statiques (il faut ajouter [0] pour des tableaux dynamiques)

    As-tu regardé l'ASM, je n'ai pas Delphi sous la main, est-ce qu'il y a des CALL ?
    En ASM64, la convention d'appel est différent de celle du 32, cela peut jouer aussi, tous les pointeurs sont des registres 64bits donc forcément manipuler ces registres prend plus de temps que des registres 32bits, ça se joue sur les MOV / POP / PUSH, Les MOV sont même parallélisés (pipeline vs cycle), si consécutifs sur des registres différents, va savoir comment un processeur de nos jours fonctionnent, c'est bien trop complexe pour des développeurs haut niveau comme nous.

    As-tu vérifié le SizeOf
    Si en 32, c'est un 3 x Single = 12 octet contre le 64 bit 3 x Double soit 24 octets, que la copie de deux fois plus d'octet soit deux fois plus longue, aucune surprise !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    686
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Deux Sèvres (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Novembre 2006
    Messages : 686
    Billets dans le blog
    2
    Par défaut
    Comme tourlourou et ShaiLeTroll, j'étais surpris car le code n'est pas le même en 32 et 64 bits : les types manipulés ne sont pas les mêmes (single en 32 bits, double en 64 bits).

    J'ai repris le code fourni et je constate quand même une différence en prenant le même type de données en 32 et en 64 bits.
    J'ai dupliqué la méthode test pour créer une test2 qui utilise un for à la place du while et créer une méthode test3 qui utilise un TParallel.For.

    Si le type est single voici les résultats sur mon i5-7200u (2 coeurs physiques, 4 logiques). Les tests ont été réalisés en compilant en mode release.
    Avec le type single :
    Nom : single32.png
Affichages : 211
Taille : 4,9 Ko
    Nom : single64.png
Affichages : 207
Taille : 5,5 Ko

    Avec le type double :
    Nom : double32.png
Affichages : 213
Taille : 5,7 Ko
    Nom : double64.png
Affichages : 206
Taille : 5,9 Ko

    Et le type Extended :
    Nom : extended32.png
Affichages : 209
Taille : 5,7 Ko
    Nom : extended64.png
Affichages : 205
Taille : 5,7 Ko

    Les registres 64 bits sont plus longs à manipuler que les registres 32 bits. Le type single est sur 4 octets donc 32 bits et donc manipulable dans un "simple" registre 32 bits. Un processeur 64 bits manipulera un registre 64 bits où seulement la moitié sera réellement la donnée manipulée.
    Le type double est sur 8 octets donc 64 bits. Dans le cas d'une compilation en 32 bits, il faut un processeur 32 bits devra diviser la donnée en 2 morceaux de 32 bits alors qu'un processeur 64 bits n'aura pas cette gestion à faire et utilisera un registre 64 bits directement.
    Le type extended est codé de différentes manières en fonction de l'OS et du compilateur 32 ou 64 bits mais permet une plus grande précision que le double.

    En fonction de votre besoin, le TParallel.For peut être une solution pour améliorer les performances sur des volumes importants car il y a un cout pour découper et gérer plusieurs threads.
    Mon site - Mes tutoriels - GitHub - N'oubliez pas de consulter les FAQ Delphi et les cours et tutoriels Delphi

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2024
    Messages : 5
    Par défaut
    Citation Envoyé par tourlourou Voir le message
    Bonsoir,
    Est-ce vraiment le même code, puisqu'il ne traite pas des données de même type ?
    Je me trompe peux être mais je pensais que pour une appli 32 bit il est plus adapté de travailler avec des réels 32b et pour une appli 64 bits de travailler avec des réels 64 bits...
    D'où le condition de compilation du haut qui utilise des singles ou des doubles suivant que l'on soit en 32b ou 64b.

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 096
    Par défaut
    Faut-il encore trouvé des architectures matérielles 32 bits, actuellement c'est du 32bit émulé sur 64bit.
    Quoi qu'il arrive, en 64bit, cela manipule plus de données, car les pointeurs sont eux même des données échangées sur les registres.
    Utiliser un Single vs Double selon 32 et 64bit me semble étrange pour une question de cible de l'architecture, pour moi, un type doit être utilisé pour satisfaire un besoin métier avant tout.

    Pour le Extended pour ceux qui ne le savent pas c'est en 80 sur 32 et 64 sur 64 :
    En 32, le Extended existe
    En 64, le Extended devient un simple Double
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2024
    Messages : 5
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Faut-il encore trouvé des architectures matérielles 32 bits, actuellement c'est du 32bit émulé sur 64bit.
    Quoi qu'il arrive, en 64bit, cela manipule plus de données, car les pointeurs sont eux même des données échangées sur les registres.
    Utiliser un Single vs Double selon 32 et 64bit me semble étrange pour une question de cible de l'architecture, pour moi, un type doit être utilisé pour satisfaire un besoin métier avant tout.
    Je suis d'accord avec vous.
    Je suis en train de porter une application 32b et 64b. Le type réel initialement utilisé était le single mais ayant noté des problèmes de lenteur en 64 bits, le type réel a été passé en double en 64bits pour voir si cela pouvait arranger les choses.
    Comme le montre gbegreg dans ses tests, en utilisant des singles pour les applis 32 et 64bits, on observe 50% de temps de calcul en plus pour l'appli 64 bits.

  8. #8
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2024
    Messages : 5
    Par défaut
    Merci à tous pour vos commentaires et tests.
    Je n'ai pas essayé avec des record. Si je dois remplacer mes tableaux statiques par des records pour mes applications, cela représenterait un travail colossal. Donc pour l'instant j'essaie de trouver une solution en conservant les tableaux. Cela étant dit, je testerai quand même.
    Je vais également essayer l'instruction Move et voir si cela améliore les résultats.
    J'ai jeté un oeil à l'assembleur, en effet le code est différent en 32b et 64b, mais je ne suis pas assez expert pour faire une analyse plus poussée.

    L'idée sur laquelle je me suis basé est qu'une appli 32 bits utilise mieux des réels 32b et une appli 64 bits utilise mieux des réels 64b.

    D'après ce que vous dites, en fonction du type utilisé, des registres 32b ou 64b sont utilisés et les 64b sont à priori plus lent. OK.

    Pour l'instant la solution que j'ai trouvée et qui fonctionne est de remplacer
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    l_vec3[0] := k_vect3_XXX[0]; 
    l_vec3[1] := k_vect3_XXX[1]; 
    l_vec3[2] := k_vect3_XXX[2];
    Mais je ne peux utiliser cette solution partout.

    Pensez vous que ce problème soit une chose qu'Embarcadero pourrait améliorer au niveau de la compilation et que je doive leur soumettre le problème ?
    En tout cas, merci pour votre aide.

  9. #9
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 096
    Par défaut
    Si l'on regarde les chiffres des mesures,
    Le Double en 32bits est mauvais en performance, sans surprise.
    Le Double en 64bits est plus lent que le Single, sans surprise non plus, on manipule des registres plus grands (même si cela se joue surement en 1/4 cycle CPU)

    Autant rester en Single si il n'y a pas de besoin de précision, surtout que là c'est QUE l'affectation, tu n'as pas mesuré des additions, soustractions, divisions et multiplications, manipulé un Single ou un Double c'est beaucoup plus lent que des Entiers, mathématique assez complexe.
    Note que FMX pour la 3D c'est codé en Single, c'est que cela est suffisant.



    J'ai regardé le code généré pour le cas à 3 champs

    32 Bits, c'est 6 MOV, qui sont 3 couple de 2 MOV, le premier pour l'adresse source vers registre de travail, le second registre de travail vers adresse destination
    64 Bits, c'est 2 LEA et 3 MOVSQ, les LEA définisse la source et la destination dans deux registres d'offset, les MOVSQ gère le transfère adresse source vers adresse destination et déplace les pointeurs dans les deux registres d'offset

    Ce n'est pas du tout codé de la même façon

    Si tu augmentes le nombre d'élément dans le tableau, par exemple 0..4
    Tient le 32 et 64 bits se ressemblent beaucoup plus MOV, LEA et MOVSP/MOVSQ
    Intéressant !

    Si tu augmentes le nombre d'élément dans le tableau, par exemple 0..5

    32 Bits, c'est comme le 64 Bits via MOVSP
    64 Bits, c'est 2 LEA et REP MOVSQ, même principe qu'avant avec un boucle sur registre, le code est ultra compact

    En fait, tu es pile sur un cas particulier
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2024
    Messages
    5
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2024
    Messages : 5
    Par défaut
    Pour info, mon collègue a fait le test équivalent en C++ (MSVC 2019) et il trouve des différences de temps d’exécution à peu près similaires à celle trouvées avec Delphi-12 (CLang).

  11. #11
    Invité
    Invité(e)
    Par défaut
    Je pense que le test n'est pas vraiment pertinent, la comparaison ne devrait pas se limiter seulement au passage des valeurs, il y a aussi les opérations arithmétiques et trigonométriques qui ne sont pas les mêmes et peuvent affecter considérablement le temps d'exécution de chaque type, donc c'est la nature du programme et la précision souhaitée qui déterminent le type de données à utiliser.

  12. #12
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 096
    Par défaut
    Citation Envoyé par lgu17 Voir le message
    Pour l'instant la solution que j'ai trouvée et qui fonctionne est de remplacer
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    l_vec3[0] := k_vect3_XXX[0]; 
    l_vec3[1] := k_vect3_XXX[1]; 
    l_vec3[2] := k_vect3_XXX[2];
    Mais je ne peux utiliser cette solution partout.
    Tu as aussi conserver Single en 32 et Double en 64 ?

    car cela un impact notable


    En fait, avec le code explicite [] tu forces l'utilisation de MOV pour les trois indice, au lieu de LEA et MOVSQ
    LEA avec sa manipulation des registres d'offset est surement plus lente que MOV, tout comme MOVSQ


    Comme, je le disais, tu es sur un cas particulier du 32 bits, passe [0..3] et même le 32Bit passe en LEA/MOVSP
    En 32, cela monte jusque 6 MOV pour 3 Single
    En 64, c'est BEAUCOUP plus subtil :
    1 Single = 2 MOV Single Registre 32 Bits
    2 Single = 2 MOV 2 Single cumulé sur Registre 64 Bits (à mon avis ce cas là devrait être plus rapide en 64 bits pour le tableau [0..1]
    3 Single = LEA MOVSQ MOVSP ... pas de chance c'est surement le cas le plus lent mais c'est 4 instructions contre 6, il aurait pu le coder en 2 MOV 64 puis 2 MOV 32

    Evidemment, si tu passes le 64 bit en Double, tu perds l'optimisation du cas [0..1] of Single ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

Discussions similaires

  1. Réponses: 2
    Dernier message: 09/09/2021, 22h50
  2. Réponses: 20
    Dernier message: 29/04/2015, 18h41
  3. Utiliser ultraVNC entre 2 pc connectés avec des clefs 3G
    Par Fbertran-pro dans le forum Autres Logiciels
    Réponses: 0
    Dernier message: 24/03/2011, 15h00
  4. melange entre guillemet et cote avec des DATE
    Par hoaxpunk dans le forum Oracle
    Réponses: 2
    Dernier message: 26/04/2006, 15h39
  5. Temps de réponse entre deux sites
    Par coup dur dans le forum Décisions SGBD
    Réponses: 6
    Dernier message: 16/10/2003, 15h26

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