2010-10-21 18 views
7

J'ai une question concernant la vitesse de déréférencement du pointeur. J'ai une structure comme ça:Vitesse de déréférencement de pointeur de structure C

typedef struct _TD_RECT TD_RECT; 
struct _TD_RECT { 
    double left; 
    double top; 
    double right; 
    double bottom; 
}; 

Ma question est, laquelle d'entre elles serait plus rapide et pourquoi?


CAS 1:

TD_RECT *pRect; 
... 
for(i = 0; i < m; i++) 
{ 
    if(p[i].x < pRect->left) ... 
    if(p[i].x > pRect->right) ... 
    if(p[i].y < pRect->top) ... 
    if(p[i].y > pRect->bottom) ... 
} 

CAS 2:

TD_RECT *pRect; 
double left = pRect->left; 
double top = pRect->top; 
double right = pRect->right; 
double bottom = pRect->bottom; 
... 
for(i = 0; i < m; i++) 
{ 
    if(p[i].x < left) ... 
    if(p[i].x > right) ... 
    if(p[i].y < top) ... 
    if(p[i].y > bottom) ... 
} 

Ainsi, dans le cas 1, la boucle est déréférencement directement le pointeur PRect pour obtenir la comparaison valeurs. Dans le cas 2, de nouvelles valeurs ont été créées sur l'espace local de la fonction (sur la pile) et les valeurs ont été copiées de la variable pRect vers les variables locales. Grâce à une boucle, il y aura beaucoup de comparaisons.

Dans mon esprit, ils seraient tout aussi lent, car la variable locale est également une référence de mémoire sur la pile, mais je ne suis pas sûr ...

Aussi, serait-il préférable de garder le référencement p [] par index, ou incrémenter p d'un élément et le déréférencer directement sans index.

Des idées? Merci :)

+13

Cessez de perdre votre temps avec une optimisation prématurée qui ne fera probablement pas une différence. –

+1

peut-être la fraction d'un smidge importe, mais si c'est le cas, pourquoi ne pas le mesurer? – kenny

+0

Pour Win32, pourrais-je utiliser GetTickCount() pour mesurer le temps avant et après l'appel de la boucle pour mesurer la vitesse, ou y a-t-il un meilleur moyen? – oldSkool

Répondre

1

Je pense que le deuxième cas est susceptible d'être plus rapide parce que vous n'êtes pas déréférencer le pointeur de pRect sur chaque itération de la boucle.

Pratiquement, un compilateur effectuant l'optimisation peut remarquer ceci et il pourrait y avoir aucune différence dans le code qui est généré, mais la possibilité de pRect étant un alias d'un élément dans p [] pourrait empêcher cela.

12

Vous trouverez probablement que cela ne fera pas de différence avec les compilateurs modernes. La plupart d'entre eux effectueraient probablement une sous-expression commune d'élimination des expressions qui ne changent pas dans la boucle. Il n'est pas judicieux de supposer qu'il existe un mappage un-à-un simple entre vos instructions C et le code d'assemblage. J'ai vu gcc pomper du code qui ferait honte à mes compétences d'assembleur.

Mais ce n'est pas une question C ou C++ puisque la norme ISO ne précise pas comment cela est fait. La meilleure façon de vérifier avec certitude est de générer le code de l'assembleur avec quelque chose comme gcc -S et d'examiner les deux cas en détail.

Vous obtiendrez également plus de retour sur investissement si vous vous éloignez de ce type de micro-optimisation et concentrez-vous davantage sur le niveau macro, tel que la sélection d'algorithmes et autres.

Et, comme pour toutes les questions d'optimisation, mesure, ne pas deviner! Il y a trop de variables qui peuvent l'affecter, vous devriez donc comparer différentes approches dans l'environnement cible, et avec des données réalistes.

+0

Je demande parce que la fonction que j'écris est la découpe de polygones pour des cartes vectorielles qui contiennent des millions des sommets ... toute la vitesse que je peux en tirer est utile car j'ai besoin de découper chaque section à 1 degré. – oldSkool

+2

C'est bien. La bonne chose à faire est de faire des benchmarks dans le monde réel car cela dépend d'un grand nombre de facteurs, dont très peu sont connus. Au strict minimum, votre machine cible, le compilateur, le processeur, d'autres problèmes architecturaux comme la mémoire et les sous-systèmes d'E/S, la composition de vos données, le niveau d'optimisation, etc. – paxdiablo

+0

Que vous en ayez des millions, regardez mon commentaire ci-dessous. Créez un index sur votre carte vectorielle (c'est-à-dire p?), Trié par x et par y. (Est-ce que ça reste assez statique?). Ou trier sur x et avoir un index sur y. Utilisez la recherche binaire pour trouver tout x droit, tout y bas. Donc, si vous avez dit 4 millions c'est 22 comparaisons pour chacun, 88 au total, au lieu des 16 millions que vous avez maintenant! – CashCow

0

Un compilateur d'optimisation verra que les accès à la structure sont invariants en boucle et ainsi faire un Loop-invariant code motion, rendant vos deux cas se ressemblent.

3

Il ne s'agit probablement pas d'une différence critique de performance. Vous pouvez profiler chaque option plusieurs fois et voir. Assurez-vous que vos optimisations de compilateur sont définies dans le test.

En ce qui concerne le stockage des doubles, vous pourriez obtenir des performances en utilisant const. Quelle est la taille de votre tableau? En ce qui concerne l'utilisation de l'arithmétique du pointeur, cela peut être plus rapide, oui.

Vous pouvez instantanément optimiser si vous savez gauche < directement dans votre rect (sûrement il doit être). Si x < est à gauche, il ne peut pas être> également à droite, donc vous pouvez mettre un "else". Votre grande optimisation, s'il y en a une, proviendrait de ne pas avoir à parcourir tous les éléments de votre tableau et de ne pas avoir à effectuer 4 contrôles sur chacun d'eux. Par exemple, si vous avez indexé ou trié votre tableau sur x et y, vous pourrez, à l'aide de la recherche binaire, trouver toutes les valeurs qui ont x < à gauche et les parcourir uniquement.

0

Je serais surpris si même une compilation totalement non-optimisée (- O0) produira un code différent pour les deux cas présentés. Pour effectuer une opération sur un processeur moderne, les données doivent être chargées dans des registres. Ainsi, même lorsque vous déclarez des variables automatiques, ces variables n'existent pas dans la mémoire principale mais plutôt dans l'un des registres à virgule flottante des processeurs. Cela sera vrai même si vous ne déclarez pas les variables vous-même et par conséquent, je ne m'attends à aucune différence dans le code machine généré même lorsque vous déclarez les variables temporaires dans votre code C++.

Mais comme d'autres l'ont dit, compilez le code en assembleur et voyez par vous-même.