Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
774 connectés 

 


 Mot :   Pseudo :  
 
 Page :   1  2
Page Suivante
Auteur Sujet :

[C++/résolu] operator [][] () et types variants

n°1330726
nargy
Posté le 23-03-2006 à 01:19:04  profilanswer
 

Reprise du message précédent :
elles te permettent toutes les deux d effectuer un code différent en fonction d un type d objet, à l execution.

mood
Publicité
Posté le 23-03-2006 à 01:19:04  profilanswer
 

n°1330727
chrisbk
-
Posté le 23-03-2006 à 01:23:59  profilanswer
 

non mais ok, mais derriere une fonction virtuelle = un pointeur de fonction

n°1330732
nargy
Posté le 23-03-2006 à 01:47:25  profilanswer
 

ben, elles ont la même fonctionnalité mais n effectuent pas le travail de la même façon.
 
En gros une fonction virtuelle est un pointeur sur une liste tableau de pointeurs de fonctions.


Message édité par nargy le 23-03-2006 à 01:48:32
n°1330733
chrisbk
-
Posté le 23-03-2006 à 01:49:30  profilanswer
 

nan mais re-ok, mais basiquement derriere c'est le meme boulot qui est effectué (grosso merdo dans le code asm generé y'a juste un mov en plus). De la a perdre 27fps c'est un peu inquietant

n°1330734
chrisbk
-
Posté le 23-03-2006 à 01:50:04  profilanswer
 

et dans ton code je vois aussi un tableau de pointeur de fonctions, non ?

n°1330735
nargy
Posté le 23-03-2006 à 01:57:49  profilanswer
 

1 déréférence sur sig:
   Signal& operator=( Signal const& sig )
   { sig_->convert( sig.signal() ); return *this; }
1 déréférence vtable, 1 déréférences code:
   virtual void doConvert( SignalType const& ) = 0;
Total 3
 
1 déréférence tableau, 1 déréférence code    
(conversions[mytype][o.mytype])(pval,o.pval)
Total 2

n°1330736
nargy
Posté le 23-03-2006 à 02:00:10  profilanswer
 

pour le 27 fps, il faudrait que je fasse de meilleurs tests, mais ça correspond à une différence de 2 à 2,5 fois plus lent.

n°1330737
nargy
Posté le 23-03-2006 à 02:13:25  profilanswer
 

Si, c est ça, de 5 à 25 fps, soit un facteur 5.
 
C est pas seulement à cause du pointeur sur fonction, c est aussi que la méthode avec les fonctions virtuelle necessite un new et un delete, que ++fab n a pas indiqué, mais qui doit s y trouver pour allouer le pointeur vers SignalType.
 
Or, un new/delete effectue une opération sur le tas qui coûte (au moins) deux fois plus qu une allocation/désallocation sur la pile.

n°1330738
nargy
Posté le 23-03-2006 à 02:15:39  profilanswer
 

ça peut s arranger un peu (dans mon cas particulier) en surchargeant new pour le forcer à allouer sur une pile.

n°1330739
nargy
Posté le 23-03-2006 à 02:28:27  profilanswer
 

Ha ouais, et pour le pointeur sur SignalType et son coût, c est pas possible de le virer, cf la page précédente, quand j ai essayé de m en débarasser.


Message édité par nargy le 23-03-2006 à 02:29:32
mood
Publicité
Posté le 23-03-2006 à 02:28:27  profilanswer
 

n°1330831
nargy
Posté le 23-03-2006 à 10:38:03  profilanswer
 

ha ouais, il y une autre méthode pour faire des classes convertissable, je m en suis rendu compte en étudiant l interface QVariant de Qt:
 
Avoir un type dont la précision est >= à tous les autres qui est utilisé pour convertir de/vers les autres types.
 
D après les autres méthodes étudiées, pour être efficace, il faut que le type de précision absolue ne fasse pas plus de quelques mots machines.
J étudie ça et j essaye de le chiffrer.
 
edit: RGBA64


Message édité par nargy le 23-03-2006 à 10:39:57
n°1331113
nargy
Posté le 23-03-2006 à 15:36:48  profilanswer
 

> Avoir un type dont la précision est >= à tous les autres qui est utilisé pour convertir de/vers les autres types.
 
Ben c est encore une connerie, ça marche à la compilation, mais pour que ça marche à l execution il faut utiliser en parallèle une autre méthode:
- gros switch
- classes abstraites
- pointeurs sur fonctions
 
... ce qui rends la méthode innefficace lorsque sizeof(variant)>sizeof(void*) c est à dire dans tous les cas pratiques

n°1331179
nargy
Posté le 23-03-2006 à 16:29:04  profilanswer
 

Merci aux participants :jap:

n°1331430
++fab
victime du syndrome IH
Posté le 24-03-2006 à 00:24:16  profilanswer
 

nargy a écrit :

C est pas seulement à cause du pointeur sur fonction, c est aussi que la méthode avec les fonctions virtuelle necessite un new et un delete, que ++fab n a pas indiqué, mais qui doit s y trouver pour allouer le pointeur vers SignalType.


 
Il y a un new dans l'appel à clone() bien sur. ça a le mérite de garantir la validité du pointeur SignalType pendant la durée de vie de l'objet Signal. Ta technique avec le void* ne garantie rien. l'objet pointé par le void*, peut avoir une durée de vie plus courte que l'objet Signal. Pour moi, c'est sécurité avant tout.
Et je pense que ce qui plombe le temps d'exécution, mais ce n'est pas l'appel virtuel, mais plutot l'allocation.  
Dans ce cas, manipuler de façon brute l'allocateur standard améliorera surement les choses. Si ça ne suffit toujours pas, pool allocator de chez Boost.  
 
Je serais vraiment surpris qu'un appel virtuel soit plus cher qu'un appel via un tableau de pointeur de fonction -- qui au passage t'oblige a stocker un autre champ. Comme le disais bk, un appel virtuel, c'est (sur les machines que j'utilise) une instruction supplémentaire par rapport à un appel non virtuel. L'un comme l'autre, pas d'inlining.
Mais bon, on pourrait discourrir longtemps, sors ton gprof et regarde ce qui se passe.
 

Citation :

Or, un new/delete effectue une opération sur le tas qui coûte (au moins) deux fois plus qu une allocation/désallocation sur la pile.


Au moins, comme tu dis ...

n°1331450
nargy
Posté le 24-03-2006 à 01:34:28  profilanswer
 

> Ta technique avec le void* ne garantie rien.
 
D un point de vue typage, le ``void* pval;`` dans la classe Signal ne pose pas plus de problème qu un pointeur vers une classe abstraite: je ne vais jamais mettre qu un objet variant convertissable là dedans.
 
La seule chose qui pose problème c est le void* dans l appel à la fonction de conversion. Je l ai en partie résolu en faisant un template:

Code :
  1. template <class ColorFrom, class ColorTo>
  2.   void convert(void* to, const void* from)
  3.   { *((ColorTo*)to)=*((ColorFrom*)from); }
  4. SignalConversion conversions[4][4]=
  5. {
  6.   { &convert<RGBA64,RGBA64>, &convert<RGBA32,RGBA64>, &convert<RGB32,RGBA64>, &convert<GRAY8,RGBA64> },
  7.   { &convert<RGBA64,RGBA32>, &convert<RGBA32,RGBA32>, &convert<RGB32,RGBA32>, &convert<GRAY8,RGBA32> },
  8.   { &convert<RGBA64,RGB32>, &convert<RGBA32,RGB32>, &convert<RGB32,RGB32>, &convert<GRAY8,RGB32> },
  9.   { &convert<RGBA64,GRAY8>, &convert<RGBA32,GRAY8>, &convert<RGB32,GRAY8>, &convert<GRAY8,GRAY8> }
  10. };


 
> l'objet pointé par le void*, peut avoir une durée de vie plus courte que l'objet Signal.
A méditer... le void* pointe vers la mémoire vidéo, ça dépends du flux vidéo. Tu n a pas indiqué ce qu il y avait dans RGBA:public SignalType, aussi on peut supposé qu il peut contenir un pointeur vers la zone vidéo.
En cas de problème je peut soit faire une copie avec new/delete, soit une copie en RGBA-64 (cf ci dessus: type variant de plus grande précision).
 
Note: en fait la méthode avec pfonctions est exactement la même qu avec classe virtuelle, mais avec un étage de pointeur en moins.
 
> Je serais vraiment surpris qu'un appel virtuel soit plus cher qu'un appel via un tableau de pointeur de fonction
- ben soit surpris :) tu peut essayer toi même avec un programme de test, l appel des fonctions virtuelles est deux fois plus lent. Et ça s explique très bien quand tu considère qu il faut minimum 1 déréférence de plus.
 
> qui au passage t'oblige a stocker un autre champ
oui, je l ai donc réduit à 16 bits. il y a aussi le stockage du(des) pointeur(s) de fonctions, notamment dans le cas général d une struct qui contient un pfonction. C est en celà que la fonction virtuelle est plus efficace: au niveau mémoire.
 
Note qu il y a avec ma méthode aussi 1 multiplication et 2 (1?) additions en plus, mais leur coût est négligeable par rapport à la lecture en RAM.
 
> Mais bon, on pourrait discourrir longtemps, sors ton gprof et regarde ce qui se passe.
- J en suis autant étonné que sûr. J ai fait les tests sur une classe virtuelle et une struct avec pfonction, sans gprof mais au bout de milliards d appels quand tu obtient un facteur 2 c est louche. Alors j ai rajouté un  étage de pointeur supplémentaire sur la pfonction et là j ai obtenu les même temps. Après plusieurs essais je me suis rappelé que en assembleur i586/i686 le coût d une ou de deux déréférences est presque le même. Donc entre 2 déréférences et 3 déréférences il y a un facteur 2. Je n ai pas été jusqu à sortir le listing assembleur.
 
> un appel virtuel, c'est (sur les machines que j'utilise) une instruction supplémentaire par rapport à un appel non virtuel.
- exact, c est bien ce que je dit.
 
> Or, un new/delete effectue une opération sur le tas qui coûte (au moins) deux fois plus qu une allocation/désallocation sur la pile.
> Au moins, comme tu dis ...
- je ne connais pas l algo de malloc/free, mais me basant sur l algo du pool c est au moins deux.
 
Bref, on peut continuer à discuter du problème, mais je pense avoir trouver toutes les solutions possibles pour coder des variants. Maintenant c est à moi de faire le bon choix pour l implémentation particulière que j en fait.
 
Je suis bien conscient que ma méthode n est réellement utile que pour de très petits objets, comme les pixels. Je ne vais pas au niveau pixel sacrifier de la performance, si je peut contourner la sécurité.
 
Et déjà comme ça, la structure de mon programme est beaucoup plus flexible que le code que j avais avant.

n°1331452
nargy
Posté le 24-03-2006 à 02:07:41  profilanswer
 

> qui au passage t'oblige a stocker un autre champ
> - oui, je l ai donc réduit à 16 bits.
 
donc: sizeof(MonSignal) < sizeof(TonSignal)
car: MonSignal = (void*)+16bits = 48 bits
et:  TonSignal = (SignalType*)+(&vtable) = 64 bits
 
ouais, ok, j admet que ça ressemble plus à de la bidouille qu a du bon c++. N empêche, c est ce qu il y a de plus rapide parmi toutes les méthodes que j ai testées.

n°1336606
++fab
victime du syndrome IH
Posté le 31-03-2006 à 19:18:01  profilanswer
 

nargy a écrit :

> Je serais vraiment surpris qu'un appel virtuel soit plus cher qu'un appel via un tableau de pointeur de fonction
- ben soit surpris :) tu peut essayer toi même avec un programme de test, l appel des fonctions virtuelles est deux fois plus lent. Et ça s explique très bien quand tu considère qu il faut minimum 1 déréférence de plus.


J'ai trouvé le temps le faire quelques tests sur ma machine : i686-pc-linux-gnu, pentium4.
Il ne m'apparait pas de différences significatives. (La fonction appellé est très simple, elle incremente un entier)
 
compilateur ------------ appel virtuel ------------ tableau de pointeur de fonction
g++ 3.4.5 -O2 ---------     7.03        ------------      7.97
g++ 3.4.5 -O3 ---------     6.12        ------------      6.08
g++ 4.0.2 -O2 ---------     7            ------------      7.83
g++ 4.0.2 -O3 ---------     6.88        ------------      6.08
g++ 4.0.2 -O3 -funroll-loops 6.26       ------------      6.26
g++ 4.1.0 -O2 ---------     6.89        ------------      7.84
g++ 4.1.0 -O3 ---------     6.89        ------------      6.07
g++ 4.1.0 -O3 -funroll-loops 6.26       ------------      6.19
icc  -O2         ---------     8.61        ------------      9.47
icc  -O3         ---------     8.61        ------------      9.47
 
( Les appels virtuels pour g++ ont l'air moins preformants sur 4.X -O3, mais en fait c'est juste que g++ 3.4.5 se permet de dérouler partiellement la boucle de test )
 
Je ne suis donc pas surpris.
 

Citation :

> Mais bon, on pourrait discourrir longtemps, sors ton gprof et regarde ce qui se passe.
- J en suis autant étonné que sûr. J ai fait les tests sur une classe virtuelle et une struct avec pfonction, sans gprof mais au bout de milliards d appels quand tu obtient un facteur 2 c est louche. Alors j ai rajouté un  étage de pointeur supplémentaire sur la pfonction et là j ai obtenu les même temps. Après plusieurs essais je me suis rappelé que en assembleur i586/i686 le coût d une ou de deux déréférences est presque le même. Donc entre 2 déréférences et 3 déréférences il y a un facteur 2. Je n ai pas été jusqu à sortir le listing assembleur.

Je ne comprends pas ce facteur 2.
 

Citation :

> un appel virtuel, c'est (sur les machines que j'utilise) une instruction supplémentaire par rapport à un appel non virtuel.
- exact, c est bien ce que je dit.


Je parlais d'un appel non virtuel, sans passer par un tableau de pointeur de fonction.

n°1336695
nargy
Posté le 31-03-2006 à 20:55:44  profilanswer
 

Moi j ai ça:


gcc -O0:
 
test1: fonction virtuelle
6.169370
test2: objet avec pointeur sur fonction
5.177712
test3: tableau statique de fonctions
6.780691
test4: tableau dynamique de fonctions
6.457658
test5: pointeur sur tableau dynamique de fonctions
7.508628
 
gcc -O2:
 
test1: fonction virtuelle
4.119002
test2: objet avec pointeur sur fonction
2.256751
test3: tableau statique de fonctions
2.143197
test4: tableau dynamique de fonctions
2.306905
test5: pointeur sur tableau dynamique de fonctions
2.464254


 
avec ça:


 
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
 
 
// test1: fonction virtuelle
class Test1
{
  public:
  // forcer le compilateur à ne pas inliner
  virtual void fct();
};
void Test1::fct() {}
 
 
// test2: objet avec pointeur sur fonction
typedef void(*pfct)();
 
// forcer le compilateur à ne pas inliner
void tst();
void tst() {}
 
struct Test2
{ pfct fct; };
 
// test3: tableau statique de fonctions
pfct test3[10][10];
 
// test4: tableau dynamique de fonctions
struct Test4
{
  pfct fct[10][10];
};
 
// test5: pointeur sur tableau dynamique de fonctions
struct Test5
{
  Test4* fcts;
};
 
 
int main()
{
  // nombre de tests
  const unsigned int ntests=1000*1000*500;
 
#ifdef TEST1
  printf("test1: fonction virtuelle\n" );
  // construction objet
  Test1* t=new Test1();
#else
#ifdef TEST2
  printf("test2: objet avec pointeur sur fonction\n" );
  // construction structure
  Test2* t=(Test2*)malloc(sizeof(Test2));
  t->fct=tst;
#else
#ifdef TEST3
  printf("test3: tableau statique de fonctions\n" );
  // construction tableau
  for(unsigned int i=0;i<10;i++)
    for(unsigned int j=0;j<10;j++)
      test3[i][j]=tst;
  // forcer le compilo à ne pas optimiser
  unsigned int r1=rand()%10;
  unsigned int r2=rand()%10;
#else
#ifdef TEST4
  printf("test4: tableau dynamique de fonctions\n" );
  // construction structure
  Test4* t=(Test4*)malloc(sizeof(Test4));
  for(unsigned int i=0;i<10;i++)
    for(unsigned int j=0;j<10;j++)
      t->fct[i][j]=tst;
  // forcer le compilo à ne pas optimiser
  unsigned int r1=rand()%10;
  unsigned int r2=rand()%10;
#else
  printf("test5: pointeur sur tableau dynamique de fonctions\n" );
  // construction structure
  Test5* t=(Test5*)malloc(sizeof(Test5));
  t->fcts=(Test4*)malloc(sizeof(Test4));
  for(unsigned int i=0;i<10;i++)
    for(unsigned int j=0;j<10;j++)
      t->fcts->fct[i][j]=tst;
  // forcer le compilo à ne pas optimiser
  unsigned int r1=rand()%10;
  unsigned int r2=rand()%10;
#endif
#endif
#endif
#endif
 
  struct timeval tv0; gettimeofday(&tv0,0);
 
  for(unsigned int i=0;i<ntests;i++)
#ifdef TEST5
    t->fcts->fct[r1][r2]();
#else
#ifdef TEST4
    t->fct[r1][r2]();
#else
#ifdef TEST3
    test3[r1][r2]();
#else
    t->fct();
#endif
#endif
#endif
 
  struct timeval tv; gettimeofday(&tv,0);
  int usecs=tv.tv_usec-tv0.tv_usec;
  long secs=tv.tv_sec-tv0.tv_sec;
  if(usecs<0) { usecs+=1000000; secs--; }
  printf("%d.%06d\n",secs,usecs);
 
  return 0;
}


 
Assembleur pour test1:


#APP
 # -------------------------------
 # debut boucle
#NO_APP
 xorl %esi, %esi
 addl $16, %esp
 .p2align 4,,7
.L10:
 subl $12, %esp
 movl (%ebx), %eax
 addl $5, %esi
 pushl %ebx
 call *(%eax)
 movl (%ebx), %eax
 movl %ebx, (%esp)
 call *(%eax)
 movl (%ebx), %eax
 movl %ebx, (%esp)
 call *(%eax)
 movl (%ebx), %eax
 movl %ebx, (%esp)
 call *(%eax)
 movl (%ebx), %eax
 movl %ebx, (%esp)
 call *(%eax)
 addl $16, %esp
 cmpl $499999999, %esi
 jbe .L10
#APP
 # fin boucle
 # -------------------------------
#NO_APP


 
Assembleur pour test3:


 # -------------------------------
 # debut boucle
#NO_APP
 leal (%esi,%esi,4), %esi
 xorl %edi, %edi
 addl $16, %esp
 leal (%ebx,%esi,2), %ebx
 .p2align 4,,7
.L18:
 incl %edi
.LCFI13:
 call *test3(,%ebx,4)
 cmpl $499999999, %edi
 jbe .L18
#APP
 # fin boucle
 # -------------------------------


n°1336699
nargy
Posté le 31-03-2006 à 20:58:08  profilanswer
 

J ai aucune idée de ce qu il fait avec les fonctions virtuelles ?!
Il y a les mêmes tours de boucle, mais toute une série de calls?

n°1336710
++fab
victime du syndrome IH
Posté le 31-03-2006 à 21:18:51  profilanswer
 

gcc -v ?

n°1336712
nargy
Posté le 31-03-2006 à 21:22:59  profilanswer
 

ha ouais c est une vielle version:
gcc version 3.3.2 (Mandrake Linux 10.0 3.3.2-6mdk)

n°1336715
nargy
Posté le 31-03-2006 à 21:25:07  profilanswer
 

il faudrait comparer l assembleur avec la dernière version, tu peut le faire en copier/collant? (je peut rien installer pour l instant)
 
tu ajoute juste:
  asm("# -------------------------------" ) ;
  asm("# debut boucle" ) ;
et:
  asm("# fin boucle" ) ;
  asm("# -------------------------------" ) ;
 
et tu compile avec option -S...
 
ça serait interessant de comparer.


Message édité par nargy le 31-03-2006 à 21:26:08
n°1336744
++fab
victime du syndrome IH
Posté le 31-03-2006 à 22:24:55  profilanswer
 

i686-pc-linux-gnu-g++-3.3.6 -O2  -DTEST1 --> 2.99 (en moyenne)
i686-pc-linux-gnu-g++-3.3.6 -O2  -DTEST3 --> 2.99 (en moyenne)
i686-pc-linux-gnu-g++-3.3.6 -O3  -DTEST1 --> 2.99 (en moyenne)
i686-pc-linux-gnu-g++-3.3.6 -O3  -DTEST3 --> 3.01 (en moyenne)
 
s/3.3.6/3.4.5
meme resultats
 
s/3.3.6/4.1.0
leger mieux pour les tableaux de pfonctions. J'ignore pourquoi.
 
tu veux le listing asm avec quel compilateur et quelles options ?
 
 

n°1336747
nargy
Posté le 31-03-2006 à 22:32:22  profilanswer
 

-O2 (le plus utilisé), avec compilo le plus récent
et pour TEST1 (puisque test3 ne peut sûrement pas être plus optimisé).

n°1336755
++fab
victime du syndrome IH
Posté le 31-03-2006 à 22:57:11  profilanswer
 

#APP
        # -------------------------------
        # debut boucle
#NO_APP
        xorl    %ebx, %ebx
        .p2align 4,,15
.L6:
        movl    (%esi), %eax
        incl    %ebx
        movl    %esi, (%esp)
        call    *(%eax)
        cmpl    $500000000, %ebx
        jne     .L6
#APP
        # fin boucle
        # -------------------------------
#NO_APP

n°1336758
++fab
victime du syndrome IH
Posté le 31-03-2006 à 23:04:48  profilanswer
 

Tu fais le test avec une fonction non-vide voir un peu complexe, et les résultats changent légèrement en faveur des fonctions virtuelles.
la combinaison d'option qui roxe sous 4.1.0, avec une fonction un peu plus complexe :
i686-pc-linux-gnu-g++-4.1.0 -O2 -fno-rtti -DTEST1 --> 30% plus rapide que -DTEST3
 
ça démontre bien la valeur des benchmarks ...
Utiliser le profiler, sur l'appli directement.

n°1336763
++fab
victime du syndrome IH
Posté le 31-03-2006 à 23:11:16  profilanswer
 

Le code généré avec -fno-rtti -O2
 
#APP
        # -------------------------------
        # debut boucle
#NO_APP
        leal    (%ebx,%ebx,4), %ebx
        xorl    %esi, %esi
        leal    (%edi,%ebx,2), %ebx
        .p2align 4,,15
.L10:
        incl    %esi
        call    *test3(,%ebx,4)
        cmpl    $500000000, %esi
        jne     .L10
#APP
        # fin boucle
        # -------------------------------
#NO_APP

n°1336774
nargy
Posté le 31-03-2006 à 23:40:29  profilanswer
 

le profiler et les benchmarks c est kif kif
le profiler est plus volubile, c est tout
 
même en asm pur, c est pas très précis, moins que de compter les cycles à la main.
 
niveau assembleur, virtuel necessite plus d instructions. mais c est pas du tout évident avec les listings ci dessus.
 
l explication que j ai donné plus haut est plus proche de la réalité:
 
1 déréférence sur sig:
   Signal& operator=( Signal const& sig )
   { sig_->convert( sig.signal() ); return *this; }
1 déréférence vtable, 1 déréférences code:
   virtual void doConvert( SignalType const& ) = 0;
Total 3
// ci dessus il a viré 1 déréférence sur sig
// si max. optimisé dans le cas de ce topic, peut remplacer cette déréférence par add
 
1 déréférence tableau, 1 déréférence code + 1 add
(conversions[mytype][o.mytype])(pval,o.pval)
Total 2 deref +1 add
// ci dessus il a viré 1 addition
 
En fait c est kif kif à peu de cycles près.
 
les problèmes de cache ne rentrent pas en compte après le premier tour de boucle.
 
> Tu fais le test avec une fonction non-vide voir un peu complexe, et les résultats changent légèrement en faveur des fonctions virtuelles.
ouais, mais tu ne mesure plus seulement la fonction virtuelle
 
tout ça, ça me donne envie de me remettre à l ASM. :)

n°1336779
++fab
victime du syndrome IH
Posté le 01-04-2006 à 00:01:14  profilanswer
 

nargy a écrit :

le profiler et les benchmarks c est kif kif
le profiler est plus volubile, c est tout


Pas du tout.
 

Citation :

En fait c est kif kif à peu de cycles près.


Oui, je crois aussi.  
 

Citation :

les problèmes de cache ne rentrent pas en compte après le premier tour de boucle.


Pourquoi ?
 

Citation :

> Tu fais le test avec une fonction non-vide voir un peu complexe, et les résultats changent légèrement en faveur des fonctions virtuelles.
ouais, mais tu ne mesure plus seulement la fonction virtuelle


Le compilateur peut peut-etre traiter différemment une fonction complexe d'une moins complexe, pour je ne sais quelles raisons ... Genre de truc impévisible. En tout cas, "la moitié du temps", les fonctions virtuelles sont plus efficace sur mon implémentation. Et ça change suivant le compilateur, les options de compil, la complexité de la fonction, etc.  

n°1336786
nargy
Posté le 01-04-2006 à 00:25:19  profilanswer
 

> profiler ~~ benchmark
- avec un système à vide
 
> les problèmes de cache ne rentrent pas en compte après le premier tour de boucle.
- là je parle pour les ``calls``, le code des vfonctions  ou des pfonctions est déjà en cache (sauf s il est vraiment trop gros bien sûr)
 
> Et ça change suivant le compilateur, les options de compil, la complexité de la fonction, etc.  
- ouais, parce que tu optimize différemment ce qui est à l intéreur de la fonction. le ``this`` par exemple est mieux optimisé comparé à un pointeur que tu passerai sur la structure (enfin c est comme ça avec beaucoup de compilateurs: this=registre, argument=pile)

n°1336844
nargy
Posté le 01-04-2006 à 09:49:54  profilanswer
 

remarque quil ne fait pas d optimisation sur la boucle, en inversant la boucle tu gagne 4 octets de code et probablement qq cycles par tour:
  for(int i=ntests-1;i>0;i--)
 
.L10:
        call    *test3(,%ebx,4)
        decl    %esi
        jnc     .L10


Message édité par nargy le 01-04-2006 à 09:50:21
mood
Publicité
Posté le   profilanswer
 

 Page :   1  2
Page Suivante

Aller à :
Ajouter une réponse
 

Sujets relatifs
[Résolu][EXCEL] Recopie d'un fichier à l'autre par comparaison[RESOLU]Créer une Imputbox sur word avec VBA
[PHP] Comment éviter qu'un formulaire se vide si on revient ? [Résolu][resolu] suppression caracteres invisibles retour charriot
[Résolu] Erreur internet explorer sur forum phpbb[résolu] strtok, ou comment prendre ce qu'il ya apres un espace
[Résolu] Changement de port sur une page webprobleme avec DataSource [Resolu]
besion d'aide sur un tuto de tomcat avec jndi [resolu][Résolu] Image aléatoire
Plus de sujets relatifs à : [C++/résolu] operator [][] () et types variants


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR