Pourquoi le fait de commenter les deux premières lignes de cette boucle for et de décommenter la troisième entraîne-t-il une accélération de 42 % ?
int count = 0;
for (uint i = 0; i < 1000000000; ++i) {
var isMultipleOf16 = i % 16 == 0;
count += isMultipleOf16 ? 1 : 0;
//count += i % 16 == 0 ? 1 : 0;
}
Derrière le timing se cache un code d'assemblage très différent : 13 contre 7 instructions dans la boucle. La plate-forme est Windows 7 exécutant .NET 4.0 x64. L'optimisation du code est activée et l'application de test a été exécutée en dehors de VS2010. [ Mise à jour : Projet de reproduction utile pour vérifier les paramètres du projet].
L'élimination du booléen intermédiaire est une optimisation fondamentale, l'une des plus simples de mon expérience des années 1980. Livre du Dragon . Comment se fait-il que l'optimisation n'ait pas été appliquée lors de la génération du CIL ou du JIT du code machine x64 ?
Existe-t-il un interrupteur "Vraiment compilateur, je voudrais que vous optimisiez ce code, s'il vous plaît" ? Bien que je comprenne le sentiment selon lequel l'optimisation prématurée est assimilable à la l'amour de l'argent Je comprends la frustration qu'il y a à essayer de profiler un algorithme complexe dont les routines sont parsemées de problèmes de ce type. Vous travaillez sur les points chauds, mais vous n'avez aucune idée de la région chaude plus large qui pourrait être grandement améliorée en modifiant à la main ce que nous prenons normalement pour acquis du compilateur. J'espère vraiment que j'ai raté quelque chose ici.
Mise à jour : Des différences de vitesse se produisent également pour x86, mais elles dépendent de l'ordre dans lequel les méthodes sont compilées en juste-à-temps. Voir Pourquoi la commande JAT affecte-t-elle les performances ?
Code d'assemblage (comme demandé) :
var isMultipleOf16 = i % 16 == 0;
00000037 mov eax,edx
00000039 and eax,0Fh
0000003c xor ecx,ecx
0000003e test eax,eax
00000040 sete cl
count += isMultipleOf16 ? 1 : 0;
00000043 movzx eax,cl
00000046 test eax,eax
00000048 jne 0000000000000050
0000004a xor eax,eax
0000004c jmp 0000000000000055
0000004e xchg ax,ax
00000050 mov eax,1
00000055 lea r8d,[rbx+rax]
count += i % 16 == 0 ? 1 : 0;
00000037 mov eax,ecx
00000039 and eax,0Fh
0000003c je 0000000000000042
0000003e xor eax,eax
00000040 jmp 0000000000000047
00000042 mov eax,1
00000047 lea edx,[rbx+rax]