C ++ vs Java? Pourquoi l’ICC génère-t-il un code plus lent que VC?

Ce qui suit est une simple boucle en C ++. Le minuteur utilise QueryPerformanceCounter () et est assez précis. J’ai trouvé que Java prenait 60% du temps en C ++ et ce n’est pas possible? Que fais-je mal ici? Même un aliasing ssortingct (qui n’est pas inclus dans le code ici) n’aide pas du tout …

long long var = 0; std::array arr; int* arrPtr = arr.data(); CHighPrecisionTimer timer; for(int i = 0; i < 1024; i++) arrPtr[i] = i; timer.Start(); for(int i = 0; i < 1024 * 1024 * 10; i++){ for(int x = 0; x < 1024; x++){ var += arrPtr[x]; } } timer.Stop(); printf("Unrestricted: %lld us, Value = %lld\n", (Int64)timer.GetElapsed().GetMicros(), var); 

Ce C ++ s’exécute en environ 9,5 secondes. J’utilise le compilateur Intel 12.1 avec l’optimisation du processeur hôte (spécifiquement pour le mien) et tout est au maximum. Donc, c’est le compilateur Intel à son meilleur! La mise en parallèle automatique consum 70% du processeur au lieu de 25% mais ne permet pas d’accélérer le travail;) …

Maintenant, j’utilise le code Java suivant pour la comparaison:

  long var = 0; int[] arr = new int[1024]; for(int i = 0; i < 1024; i++) arr[i] = i; for(int i = 0; i < 1024 * 1024; i++){ for(int x = 0; x < 1024; x++){ var += arr[x]; } } long nanos = System.nanoTime(); for(int i = 0; i < 1024 * 1024 * 10; i++){ for(int x = 0; x < 1024; x++){ var += arr[x]; } } nanos = (System.nanoTime() - nanos) / 1000; System.out.print("Value: " + var + ", Time: " + nanos); 

Le code Java est appelé avec une optimisation agressive et la machine virtuelle du serveur (pas de débogage). Il fonctionne en 7 secondes environ sur ma machine (utilise un seul thread).

Est-ce une défaillance du compilateur Intel ou suis-je trop bête?

[EDIT]: Ok maintenant c’est le truc … Ça ressemble plus à un bogue dans le compilateur Intel ^^. [Veuillez noter que je tourne sur Intel Quadcore Q6600, qui est plutôt ancien. Et il se peut que le compilateur Intel fonctionne beaucoup mieux sur les processeurs récents, comme Core i7]

 Intel x86 (without vectorization): 3 seconds MSVC x64: 5 seconds Java x86/x64 (Oracle Java 7): 7 seconds Intel x64 (with vectorization): 9.5 seconds Intel x86 (with vectorization): 9.5 seconds Intel x64 (without vectorization): 12 seconds MSVC x86: 15 seconds (uhh) 

[EDIT]: Un autre bon cas;). Considérons l’expression lambda sortingviale suivante

 #include  #include  #include  #include  #include  #include  #include  template struct ArrayList { private: std::vector m_Ensortinges; public: template void Foreach(TCallback inCallback) { for(int i = 0, size = m_Ensortinges.size(); i < size; i++) { inCallback(i); } } void Add(TValue inValue) { m_Entries.push_back(inValue); } }; int _tmain(int argc, _TCHAR* argv[]) { auto t = [&]() {}; ArrayList arr; int res = 0; for(int i = 0; i < 100; i++) { arr.Add(i); } long long freq, t1, t2; QueryPerformanceFrequency((LARGE_INTEGER*)&freq); QueryPerformanceCounter((LARGE_INTEGER*)&t1); for(int i = 0; i < 1000 * 1000 * 10; i++) { arr.Foreach([&](int v) { res += i; }); } QueryPerformanceCounter((LARGE_INTEGER*)&t2); printf("Time: %lld\n", ((t2-t1) * 1000000) / freq); if(res == 4950) return -1; return 0; } 

Le compilateur Intel brille à nouveau:

 MSVC x86/x64: 12 milli seconds Intel x86/x64: 1 second 

Uhm ?! Eh bien, je suppose que 90 fois plus lent n’est pas une mauvaise chose …

Je ne suis plus vraiment sûr que cela s’applique: D’accord et basé sur une réponse à ce sujet: Le compilateur Intel est connu (et je le savais aussi, mais je ne pensais pas qu’ils pourraient abandonner le support de leurs processeurs) pour avoir des performances terribles sur des processeurs qui ne sont pas “connus” du compilateur, comme les processeurs AMD, et peut-être même des processeurs Intel obsolètes comme le mien … Donc, si quelqu’un avec un processeur Intel récent pouvait l’essayer, ce serait bien;).

Voici la sortie x64 du compilateur Intel:

  std::array arr; int* arrPtr = arr.data(); QueryPerformanceFrequency((LARGE_INTEGER*)&freq); 000000013F05101D lea rcx,[freq] 000000013F051022 call qword ptr [__imp_QueryPerformanceFrequency (13F052000h)] for(int i = 0; i < 1024; i++) arrPtr[i] = i; 000000013F051028 mov eax,4 000000013F05102D movd xmm0,eax 000000013F051031 xor eax,eax 000000013F051033 pshufd xmm1,xmm0,0 000000013F051038 movdqa xmm0,xmmword ptr [__xi_z+28h (13F0521A0h)] 000000013F051040 movdqa xmmword ptr arr[rax*4],xmm0 000000013F051046 paddd xmm0,xmm1 000000013F05104A movdqa xmmword ptr [rsp+rax*4+60h],xmm0 000000013F051050 paddd xmm0,xmm1 000000013F051054 movdqa xmmword ptr [rsp+rax*4+70h],xmm0 000000013F05105A paddd xmm0,xmm1 000000013F05105E movdqa xmmword ptr [rsp+rax*4+80h],xmm0 000000013F051067 add rax,10h 000000013F05106B paddd xmm0,xmm1 000000013F05106F cmp rax,400h 000000013F051075 jb wmain+40h (13F051040h) QueryPerformanceCounter((LARGE_INTEGER*)&t1); 000000013F051077 lea rcx,[t1] 000000013F05107C call qword ptr [__imp_QueryPerformanceCounter (13F052008h)] var += arrPtr[x]; 000000013F051082 movdqa xmm1,xmmword ptr [__xi_z+38h (13F0521B0h)] for(int i = 0; i < 1024 * 1024 * 10; i++){ 000000013F05108A xor eax,eax var += arrPtr[x]; 000000013F05108C movdqa xmm0,xmmword ptr [__xi_z+48h (13F0521C0h)] long long var = 0, freq, t1, t2; 000000013F051094 pxor xmm6,xmm6 for(int x = 0; x < 1024; x++){ 000000013F051098 xor r8d,r8d var += arrPtr[x]; 000000013F05109B lea rdx,[arr] 000000013F0510A0 xor ecx,ecx 000000013F0510A2 movq xmm2,mmword ptr arr[rcx] for(int x = 0; x < 1024; x++){ 000000013F0510A8 add r8,8 var += arrPtr[x]; 000000013F0510AC punpckldq xmm2,xmm2 for(int x = 0; x < 1024; x++){ 000000013F0510B0 add rcx,20h var += arrPtr[x]; 000000013F0510B4 movdqa xmm3,xmm2 000000013F0510B8 pand xmm2,xmm0 000000013F0510BC movq xmm4,mmword ptr [rdx+8] 000000013F0510C1 psrad xmm3,1Fh 000000013F0510C6 punpckldq xmm4,xmm4 000000013F0510CA pand xmm3,xmm1 000000013F0510CE por xmm3,xmm2 000000013F0510D2 movdqa xmm5,xmm4 000000013F0510D6 movq xmm2,mmword ptr [rdx+10h] 000000013F0510DB psrad xmm5,1Fh 000000013F0510E0 punpckldq xmm2,xmm2 000000013F0510E4 pand xmm5,xmm1 000000013F0510E8 paddq xmm6,xmm3 000000013F0510EC pand xmm4,xmm0 000000013F0510F0 movdqa xmm3,xmm2 000000013F0510F4 por xmm5,xmm4 000000013F0510F8 psrad xmm3,1Fh 000000013F0510FD movq xmm4,mmword ptr [rdx+18h] 000000013F051102 pand xmm3,xmm1 000000013F051106 punpckldq xmm4,xmm4 000000013F05110A pand xmm2,xmm0 000000013F05110E por xmm3,xmm2 000000013F051112 movdqa xmm2,xmm4 000000013F051116 paddq xmm6,xmm5 000000013F05111A psrad xmm2,1Fh 000000013F05111F pand xmm4,xmm0 000000013F051123 pand xmm2,xmm1 for(int x = 0; x < 1024; x++){ 000000013F051127 add rdx,20h var += arrPtr[x]; 000000013F05112B paddq xmm6,xmm3 000000013F05112F por xmm2,xmm4 for(int x = 0; x < 1024; x++){ 000000013F051133 cmp r8,400h var += arrPtr[x]; 000000013F05113A paddq xmm6,xmm2 for(int x = 0; x < 1024; x++){ 000000013F05113E jb wmain+0A2h (13F0510A2h) for(int i = 0; i < 1024 * 1024 * 10; i++){ 000000013F051144 inc eax 000000013F051146 cmp eax,0A00000h 000000013F05114B jb wmain+98h (13F051098h) } } QueryPerformanceCounter((LARGE_INTEGER*)&t2); 000000013F051151 lea rcx,[t2] 000000013F051156 call qword ptr [__imp_QueryPerformanceCounter (13F052008h)] printf("Unrestricted: %lld ms, Value = %lld\n", ((t2-t1)*1000/freq), var); 000000013F05115C mov r9,qword ptr [t2] long long var = 0, freq, t1, t2; 000000013F051161 movdqa xmm0,xmm6 printf("Unrestricted: %lld ms, Value = %lld\n", ((t2-t1)*1000/freq), var); 000000013F051165 sub r9,qword ptr [t1] 000000013F05116A lea rcx,[string "Unrestricted: %lld ms, Value = %"... (13F0521D0h)] 000000013F051171 imul rax,r9,3E8h 000000013F051178 cqo 000000013F05117A mov r10,qword ptr [freq] 000000013F05117F idiv rax,r10 long long var = 0, freq, t1, t2; 000000013F051182 psrldq xmm0,8 printf("Unrestricted: %lld ms, Value = %lld\n", ((t2-t1)*1000/freq), var); 000000013F051187 mov rdx,rax long long var = 0, freq, t1, t2; 000000013F05118A paddq xmm6,xmm0 000000013F05118E movd r8,xmm6 printf("Unrestricted: %lld ms, Value = %lld\n", ((t2-t1)*1000/freq), var); 000000013F051193 call qword ptr [__imp_printf (13F052108h)] 

Et celui-ci est l’assemblage de la version MSVC x64:

 int _tmain(int argc, _TCHAR* argv[]) { 000000013FF61000 push rbx 000000013FF61002 mov eax,1050h 000000013FF61007 call __chkstk (13FF61950h) 000000013FF6100C sub rsp,rax 000000013FF6100F mov rax,qword ptr [__security_cookie (13FF63000h)] 000000013FF61016 xor rax,rsp 000000013FF61019 mov qword ptr [rsp+1040h],rax long long var = 0, freq, t1, t2; std::array arr; int* arrPtr = arr.data(); QueryPerformanceFrequency((LARGE_INTEGER*)&freq); 000000013FF61021 lea rcx,[rsp+28h] 000000013FF61026 xor ebx,ebx 000000013FF61028 call qword ptr [__imp_QueryPerformanceFrequency (13FF62000h)] for(int i = 0; i < 1024; i++) arrPtr[i] = i; 000000013FF6102E xor r11d,r11d 000000013FF61031 lea rax,[rsp+40h] 000000013FF61036 mov dword ptr [rax],r11d 000000013FF61039 inc r11d 000000013FF6103C add rax,4 000000013FF61040 cmp r11d,400h 000000013FF61047 jl wmain+36h (13FF61036h) QueryPerformanceCounter((LARGE_INTEGER*)&t1); 000000013FF61049 lea rcx,[rsp+20h] 000000013FF6104E call qword ptr [__imp_QueryPerformanceCounter (13FF62008h)] 000000013FF61054 mov r11d,0A00000h 000000013FF6105A nop word ptr [rax+rax] for(int i = 0; i < 1024 * 1024 * 10; i++){ for(int x = 0; x < 1024; x++){ 000000013FF61060 xor edx,edx 000000013FF61062 xor r8d,r8d 000000013FF61065 lea rcx,[rsp+48h] 000000013FF6106A xor r9d,r9d 000000013FF6106D mov r10d,100h 000000013FF61073 nop word ptr [rax+rax] var += arrPtr[x]; 000000013FF61080 movsxd rax,dword ptr [rcx-8] 000000013FF61084 add rcx,10h 000000013FF61088 add rbx,rax 000000013FF6108B movsxd rax,dword ptr [rcx-14h] 000000013FF6108F add r9,rax 000000013FF61092 movsxd rax,dword ptr [rcx-10h] 000000013FF61096 add r8,rax 000000013FF61099 movsxd rax,dword ptr [rcx-0Ch] 000000013FF6109D add rdx,rax 000000013FF610A0 dec r10 000000013FF610A3 jne wmain+80h (13FF61080h) for(int i = 0; i < 1024 * 1024 * 10; i++){ for(int x = 0; x < 1024; x++){ 000000013FF610A5 lea rax,[rdx+r8] 000000013FF610A9 add rax,r9 000000013FF610AC add rbx,rax 000000013FF610AF dec r11 000000013FF610B2 jne wmain+60h (13FF61060h) } } QueryPerformanceCounter((LARGE_INTEGER*)&t2); 000000013FF610B4 lea rcx,[rsp+30h] 000000013FF610B9 call qword ptr [__imp_QueryPerformanceCounter (13FF62008h)] printf("Unrestricted: %lld ms, Value = %lld\n", ((t2-t1)*1000/freq), var); 000000013FF610BF mov rax,qword ptr [rsp+30h] 000000013FF610C4 lea rcx,[string "Unrestricted: %lld ms, Value = %"... (13FF621B0h)] 000000013FF610CB sub rax,qword ptr [rsp+20h] 000000013FF610D0 mov r8,rbx 000000013FF610D3 imul rax,rax,3E8h 000000013FF610DA cqo 000000013FF610DC idiv rax,qword ptr [rsp+28h] 000000013FF610E1 mov rdx,rax 000000013FF610E4 call qword ptr [__imp_printf (13FF62138h)] return 0; 000000013FF610EA xor eax,eax 

Intel Comstackr configuré sans vectorisation, 64 bits, optimisations les plus élevées (ce qui est étonnamment lent, 12 secondes):

 000000013FC0102F lea rcx,[freq] double var = 0; long long freq, t1, t2; 000000013FC01034 xorps xmm6,xmm6 std::array arr; double* arrPtr = arr.data(); QueryPerformanceFrequency((LARGE_INTEGER*)&freq); 000000013FC01037 call qword ptr [__imp_QueryPerformanceFrequency (13FC02000h)] for(int i = 0; i < 1024; i++) arrPtr[i] = i; 000000013FC0103D mov eax,2 000000013FC01042 mov rdx,100000000h 000000013FC0104C movd xmm0,eax 000000013FC01050 xor eax,eax 000000013FC01052 pshufd xmm1,xmm0,0 000000013FC01057 movd xmm0,rdx 000000013FC0105C nop dword ptr [rax] 000000013FC01060 cvtdq2pd xmm2,xmm0 000000013FC01064 paddd xmm0,xmm1 000000013FC01068 cvtdq2pd xmm3,xmm0 000000013FC0106C paddd xmm0,xmm1 000000013FC01070 cvtdq2pd xmm4,xmm0 000000013FC01074 paddd xmm0,xmm1 000000013FC01078 cvtdq2pd xmm5,xmm0 000000013FC0107C movaps xmmword ptr arr[rax*8],xmm2 000000013FC01081 paddd xmm0,xmm1 000000013FC01085 movaps xmmword ptr [rsp+rax*8+60h],xmm3 000000013FC0108A movaps xmmword ptr [rsp+rax*8+70h],xmm4 000000013FC0108F movaps xmmword ptr [rsp+rax*8+80h],xmm5 000000013FC01097 add rax,8 000000013FC0109B cmp rax,400h 000000013FC010A1 jb wmain+60h (13FC01060h) QueryPerformanceCounter((LARGE_INTEGER*)&t1); 000000013FC010A3 lea rcx,[t1] 000000013FC010A8 call qword ptr [__imp_QueryPerformanceCounter (13FC02008h)] for(int i = 0; i < 1024 * 1024 * 10; i++){ 000000013FC010AE xor eax,eax for(int x = 0; x < 1024; x++){ 000000013FC010B0 xor edx,edx var += arrPtr[x]; 000000013FC010B2 lea ecx,[rdx+rdx] for(int x = 0; x < 1024; x++){ 000000013FC010B5 inc edx for(int x = 0; x < 1024; x++){ 000000013FC010B7 cmp edx,200h var += arrPtr[x]; 000000013FC010BD addsd xmm6,mmword ptr arr[rcx*8] 000000013FC010C3 addsd xmm6,mmword ptr [rsp+rcx*8+58h] for(int x = 0; x < 1024; x++){ 000000013FC010C9 jb wmain+0B2h (13FC010B2h) for(int i = 0; i < 1024 * 1024 * 10; i++){ 000000013FC010CB inc eax 000000013FC010CD cmp eax,0A00000h 000000013FC010D2 jb wmain+0B0h (13FC010B0h) } } QueryPerformanceCounter((LARGE_INTEGER*)&t2); 000000013FC010D4 lea rcx,[t2] 000000013FC010D9 call qword ptr [__imp_QueryPerformanceCounter (13FC02008h)] 

Compilateur Intel sans vectorisation, optimisation 32 bits et plus élevée (celle-ci est clairement gagnante maintenant, tourne en 3 secondes environ et l’assemblage est bien meilleur):

 00B81088 lea eax,[t1] 00B8108C push eax 00B8108D call dword ptr [__imp__QueryPerformanceCounter@4 (0B82004h)] 00B81093 xor eax,eax 00B81095 pxor xmm0,xmm0 00B81099 movaps xmm1,xmm0 for(int x = 0; x < 1024; x++){ 00B8109C xor edx,edx var += arrPtr[x]; 00B8109E addpd xmm0,xmmword ptr arr[edx*8] 00B810A4 addpd xmm1,xmmword ptr [esp+edx*8+40h] 00B810AA addpd xmm0,xmmword ptr [esp+edx*8+50h] 00B810B0 addpd xmm1,xmmword ptr [esp+edx*8+60h] for(int x = 0; x < 1024; x++){ 00B810B6 add edx,8 00B810B9 cmp edx,400h 00B810BF jb wmain+9Eh (0B8109Eh) for(int i = 0; i < 1024 * 1024 * 10; i++){ 00B810C1 inc eax 00B810C2 cmp eax,0A00000h 00B810C7 jb wmain+9Ch (0B8109Ch) double var = 0; long long freq, t1, t2; 00B810C9 addpd xmm0,xmm1 } } QueryPerformanceCounter((LARGE_INTEGER*)&t2); 00B810CD lea eax,[t2] 00B810D1 push eax 00B810D2 movaps xmmword ptr [esp+4],xmm0 00B810D7 call dword ptr [__imp__QueryPerformanceCounter@4 (0B82004h)] 00B810DD movaps xmm0,xmmword ptr [esp] 

tl; dr: Ce que vous voyez ici semble être l’échec de la tentative de vectorisation de la boucle par ICC .

Commençons par MSVC x64:

Voici la boucle critique:

 $LL3@main: movsxd rax, DWORD PTR [rdx-4] movsxd rcx, DWORD PTR [rdx-8] add rdx, 16 add r10, rax movsxd rax, DWORD PTR [rdx-16] add rbx, rcx add r9, rax movsxd rax, DWORD PTR [rdx-12] add r8, rax dec r11 jne SHORT $LL3@main 

Ce que vous voyez ici est le déroulement de la boucle standard par le compilateur. MSVC se déroule sur 4 itérations et divise la variable var en quatre registres: r10 , rbx , r9 et r8 . Ensuite, à la fin de la boucle, ces 4 registres sont résumés ensemble.

Voici où les 4 sums sont recombinées:

 lea rax, QWORD PTR [r8+r9] add rax, r10 add rbx, rax dec rdi jne SHORT $LL6@main 

Notez que MSVC ne fait actuellement pas de vectorisation automatique.


Regardons maintenant une partie de votre sortie ICC:

 000000013F0510A2 movq xmm2,mmword ptr arr[rcx] 000000013F0510A8 add r8,8 000000013F0510AC punpckldq xmm2,xmm2 000000013F0510B0 add rcx,20h 000000013F0510B4 movdqa xmm3,xmm2 000000013F0510B8 pand xmm2,xmm0 000000013F0510BC movq xmm4,mmword ptr [rdx+8] 000000013F0510C1 psrad xmm3,1Fh 000000013F0510C6 punpckldq xmm4,xmm4 000000013F0510CA pand xmm3,xmm1 000000013F0510CE por xmm3,xmm2 000000013F0510D2 movdqa xmm5,xmm4 000000013F0510D6 movq xmm2,mmword ptr [rdx+10h] 000000013F0510DB psrad xmm5,1Fh 000000013F0510E0 punpckldq xmm2,xmm2 000000013F0510E4 pand xmm5,xmm1 000000013F0510E8 paddq xmm6,xmm3 ... 

Ce que vous voyez ici est une tentative d’ICC de vectoriser cette boucle. Cela se fait de la même manière que MSVC (division en plusieurs sums), mais à la place des registres SSE et avec deux sums par registre.

Mais il s’avère que les coûts de la vectorisation dépassent les avantages de la vectorisation.

Si nous passons ces instructions une par une, nous pouvons voir comment ICC essaie de la vectoriser:

 // Load two ints using a 64-bit load. {x, y, 0, 0} movq xmm2,mmword ptr arr[rcx] // Shuffle the data into this form. punpckldq xmm2,xmm2 xmm2 = {x, x, y, y} movdqa xmm3,xmm2 xmm3 = {x, x, y, y} // Mask out index 1 and 3. pand xmm2,xmm0 xmm2 = {x, 0, y, 0} // Arithmetic right-shift to copy sign-bit across the word. psrad xmm3,1Fh xmm3 = {sign(x), sign(x), sign(y), sign(y)} // Mask out index 0 and 2. pand xmm3,xmm1 xmm3 = {0, sign(x), 0, sign(y)} // Combine to get sign-extended values. por xmm3,xmm2 xmm3 = {x, sign(x), y, sign(y)} xmm3 = {x, y} // Add to accumulator... paddq xmm6,xmm3 

Donc, il faut faire du déballage très compliqué pour vectoriser. Le désordre vient de la nécessité d’étendre les entiers 32 bits à 64 bits en utilisant uniquement les instructions SSE.

SSE4.1 fournit réellement l’instruction PMOVSXDQ à cette fin. Mais soit la machine cible ne prend pas en charge SSE4.1, soit ICC n’est pas assez intelligent pour l’utiliser dans ce cas.

Mais le point est:

Le compilateur Intel tente de vectoriser la boucle. Mais la surcharge ajoutée semble dépasser les avantages de la vectorisation en premier lieu. D’où pourquoi c’est plus lent.


EDIT: mise à jour avec les résultats de l’OP sur:

  • ICC x64 pas de vectorisation
  • ICC x86 avec vectorisation

Vous avez changé le type de données pour double . Alors maintenant, c’est en virgule flottante. Il n’y a pas plus de ces décalages de remplissage des affiches laids qui ont affecté la version entière.

Mais depuis que vous avez désactivé la vectorisation pour la version x64, cela devient évidemment plus lent.

ICC x86 avec vectorisation:

 00B8109E addpd xmm0,xmmword ptr arr[edx*8] 00B810A4 addpd xmm1,xmmword ptr [esp+edx*8+40h] 00B810AA addpd xmm0,xmmword ptr [esp+edx*8+50h] 00B810B0 addpd xmm1,xmmword ptr [esp+edx*8+60h] 00B810B6 add edx,8 00B810B9 cmp edx,400h 00B810BF jb wmain+9Eh (0B8109Eh) 

Pas beaucoup ici – vectorisation standard + déroulage en boucle 4x.

ICC x64 sans vectorisation:

 000000013FC010B2 lea ecx,[rdx+rdx] 000000013FC010B5 inc edx 000000013FC010B7 cmp edx,200h 000000013FC010BD addsd xmm6,mmword ptr arr[rcx*8] 000000013FC010C3 addsd xmm6,mmword ptr [rsp+rcx*8+58h] 000000013FC010C9 jb wmain+0B2h (13FC010B2h) 

Pas de vectorisation + seulement 2x déroulement en boucle.

Toutes choses égales par ailleurs, la désactivation de la vectorisation nuira aux performances dans ce cas en virgule flottante.

L’exemple est assez simple pour que les différentes langues ne fassent pas la différence, et assez stupide pour ne rien prouver. La compilation pourrait être optimisée par un compilateur en une simple atsortingbution, ou laissée en marche pour le nombre entier d’itérations, ou certaines des itérations pourraient être déroulées … Je ne sais pas pourquoi vous avez décidé d’écrire ce programme de test, mais ne teste rien en ce qui concerne les langages, car une fois les optimisations logiques effectuées, tout se résume exactement au même assemblage.

De plus, en ce qui concerne les performances du compilateur intel, cela dépendra beaucoup du matériel exact et de la version du compilateur. Le compilateur génère différentes versions du code et a tendance à générer du code horrible pour les processeurs AMD. Même pour Intel, s’il ne reconnaît pas le processeur spécifique, il retombe dans un mode lent sécurisé.

quand vous avez éliminé l’impossible, tout ce qui rest, même improbable, doit être la vérité.

Vous avez des données dans une main et une hypothèse (C ++ est toujours plus rapide que Java) dans l’autre. Pourquoi demander aux gens de justifier votre hypothèse lorsque les données vous indiquent le contraire?

Si vous souhaitez obtenir l’assemblage à partir de la JVM afin de comparer ce qui est en cours d’exécution, l’option de ligne de commande est “-XX: + PrintOptoAssembly”, mais vous devrez télécharger un fichier de débogage pour cela. En regardant l’assemblée, on vous dirait au moins pourquoi l’une est plus rapide que l’autre.

Juste pour mémoire, j’ai lancé les deux codes sur ma boîte (x86_64 linux), le C ++ avec std::array , un plain int[1024] et, pour être complet aussi avec long au lieu de int . Java (open-jdk 1.6) l’a cadencé à 3,8, C ++ (int) à 3,37 et C ++ (long) à 3,9. Mon compilateur était g ++ 4.5.1. Peut-être que c’est juste le compilateur d’Intel qui n’est pas aussi bon que prévu.

Je pense que le compilateur Java implémente JITC (compilation juste à temps, ou une technologie plus récente) pour approcher la vitesse des compilateurs natifs, et pourrait en déduire que votre tableau ne change pas, et donc appliquer un pliage constant à la boucle interne …

Je soupçonne que le coupable est le déroulement en boucle simple. Remplacer

 var += arrPtr[x]; 

avec

 var += arrPtr[x++]; var += arrPtr[x++]; var += arrPtr[x++]; var += arrPtr[x]; 

et observez la vitesse d’exécution de la version C ++.

Je vois que vous exécutez la boucle suivante

 for(int i = 0; i < 1024 * 1024; i++){ for(int x = 0; x < 1024; x++){ var += arr[x]; } } 

deux fois dans le code Java; une fois dans le code c ++; Cela peut amener un échauffement des caches, ce qui rend le code Java plus rapide que le C ++.