Question

Voici un extrait d'une liste de deux séquences d'assemblage Pentium. Nous avons une boucle extérieure qui tente de temps nos séquences et est en train de faire une table d'appel par se rendre à ces routines. Par conséquent, l'appel extérieur est fabriqué à partir du même endroit à chaque fois. Les deux séquences diffèrent en ce que le premier a une instruction inférieure à la seconde.

Les résultats que nous obtenons sur deux machines Intel sont très différentes.

L'instruction CPUID dit la famille, modèle, et pas à pas.

Machine 1: Famille 6, Modèle 15 Stepping 11. rapports CPUZ
"Intel Core 2 Duo E6750" Les instructions exécutent à la même vitesse statistiquement.

Machine 2: 15 Famille, modèle 3, Stepping 3. Rapports CPUZ "Intel Pentium 4"
La première séquence dure environ 8% plus longue que la seconde séquence.

Nous ne pouvons pas expliquer l'augmentation du temps. Il ne devrait pas être différent hold-off de drapeau, prédiction de branches, inscrivez-vous des problèmes d'utilisation, etc. Au moins pas que nous pouvons dire.

Est-ce que quelqu'un a une idée pourquoi la première séquence prendrait plus de temps à exécuter sur une machine?

Edit: Ajout de "XOR PTR ereg, 0" à la première séquence ne fait le moment correspondre à la seconde sur le Pentium 4. Curieux

.

Première séquence:

00000040               ALUSHIFT_AND_C_V_E LABEL NEAR
00000040  0F B7 04 55       MOVZX   EAX, gwr[(SIZEOF WORD) * EDX]       ; EAX = 0000000000000000 LLLLLLLLLLLLLLLL
   00000000 E
00000048  0F B7 14 4D       MOVZX   EDX, gwr[(SIZEOF WORD) * ECX]       ; EDX = 0000000000000000 RRRRRRRRRRRRRRRR
   00000000 E
00000050  23 C2             AND     EAX, EDX                            ; AX = L&R      (result)
00000052  A3 00000000 E     MOV     dvalue, EAX                         ; Save the temporary ALU/Shifter result
00000057  C3                RET                                         ; Return

Deuxième séquence:

00000060               ALUSHIFT_AND_C_V_NE LABEL NEAR
00000060  0F B7 04 55       MOVZX   EAX, gwr[(SIZEOF WORD) * EDX]       ; EAX = 0000000000000000 LLLLLLLLLLLLLLLL
   00000000 E
00000068  0F B7 14 4D       MOVZX   EDX, gwr[(SIZEOF WORD) * ECX]       ; EDX = 0000000000000000 RRRRRRRRRRRRRRRR
   00000000 E
00000070  23 C2             AND     EAX, EDX                            ; AX = L&R      (result)
00000072  80 35 00000000 E  XOR     BYTE PTR ereg, 1                    ; E = ~E
   01
00000079  A3 00000000 E     MOV     dvalue, EAX                         ; Save the temporary ALU/Shifter result
0000007E  C3                RET                                         ; Return
Était-ce utile?

La solution

Après le Pentium I ou II, la plupart des optimisations effectuées par le compilateur, ne sont pas nécessaires. La puce se décompose ces instructions en micro ops et optimiser pour vous. t pourrait être les différences de prédiction de branchement entre les puces ou le fait que le XOR + RET est tout aussi cher comme RET plaine. Je ne suis pas aussi familier avec quels modèles de Pentiums vous regardent ci-dessus pour dire. Une autre possibilité est que cela pourrait aussi être un problème cache en ligne ou la différence du matériel.

Il peut y avoir quelque chose dans les docs Intel ou il ne peut pas.

Peu importe. codeurs de montage expérimentés savent que la seule vérité est obtenue au moyen de tests, ce qui est ce que vous faites.

Autres conseils

Il se trouve qu'il ya une certaine interaction avec curieuse où le code est situé qui provoque l'augmentation. Même si tout est aligné cache, la commutation des blocs de code a provoqué l'augmentation du temps sur le Pentium-4

Merci à tous ceux qui ont pris le temps d'enquêter sur ce ou regarder.

Vous pouvez en ajouter un, deux, etc NOP devant ce code (rien changer d'autre) de se déplacer où ces terres dans le cache pour voir s'il y a des effets cache (ou tout simplement désactiver le cache). Avertissement si aussi peu que un nop supplémentaire peut changer une instruction ailleurs qui ne peut plus atteindre quelque chose en utilisant par rapport au pc d'adressage, qui peut causer plus d'octets d'instruction causant à la fois le code en cours de test pour passer plus de choix, ainsi que peut-être une réaction en chaîne de d'autres instructions relativement adressées au changement.

Même si vous jouez le jeu de cache la nature de la bête est la magie ici à l'intérieur de la puce qui prend un flux d'instructions et il divise entre les unités d'exécution.

Tweak et le test est ce qui obtient vraiment des performances à la fin même si vous ne comprenez pas pourquoi. Bien que dès que vous déplacez ce code à une puce plus ou puce différente ou plus récente carte mère ou même famille à puce, mais différent pas à pas tous vos réglages de performance peuvent activer vous.

Il y a quelques mois, j'ai eu quelque chose de semblable se me. Mon projet a une configuration commutateur pour permettre l'utilisation de __thread pour les variables locales de thread. Sans elle, il utiliserait pthread_getspecific et les goûts. Ce dernier ne tout autant que la version __thread plus un appel de fonction ainsi que quelques instructions supplémentaires pour la mise en place des arguments, des registres d'épargne, et ainsi de suite. Fait intéressant, la version la plus laborieuse était toujours plus rapide. Seulement le Pentium 4, cependant. Tous les autres puces se comportaient sanely.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top