Testi Lik32 kodunu kullanarak kendi makinemde tekrar çalıştırmaya karar verdim. Windows veya derleyicimin yüksek çözünürlük 1 ms olduğunu düşünerek değiştirmek zorunda kaldım,
mingw32-g ++. exe -O3 -Duvar -std = c ++ 11 -özellikler -g
vector<int> rand_vec(10000000);
GCC, her iki orijinal kodda da aynı dönüşümü gerçekleştirdi.
Üçüncünün her zaman doğru olması gerektiği için sadece ilk iki koşulun test edildiğine dikkat edin, GCC burada bir Sherlock türüdür.
Tersine çevirmek
.L233:
mov DWORD PTR [rsp+104], 0
mov DWORD PTR [rsp+100], 0
mov DWORD PTR [rsp+96], 0
call std::chrono::_V2::system_clock::now()
mov rbp, rax
mov rax, QWORD PTR [rsp+8]
jmp .L219
.L293:
mov edx, DWORD PTR [rsp+104]
add edx, 1
mov DWORD PTR [rsp+104], edx
.L217:
add rax, 4
cmp r14, rax
je .L292
.L219:
mov edx, DWORD PTR [rax]
cmp edx, 94
jg .L293 // >= 95
cmp edx, 19
jg .L218 // >= 20
mov edx, DWORD PTR [rsp+96]
add rax, 4
add edx, 1 // < 20 Sherlock
mov DWORD PTR [rsp+96], edx
cmp r14, rax
jne .L219
.L292:
call std::chrono::_V2::system_clock::now()
.L218: // further down
mov edx, DWORD PTR [rsp+100]
add edx, 1
mov DWORD PTR [rsp+100], edx
jmp .L217
And sorted
mov DWORD PTR [rsp+104], 0
mov DWORD PTR [rsp+100], 0
mov DWORD PTR [rsp+96], 0
call std::chrono::_V2::system_clock::now()
mov rbp, rax
mov rax, QWORD PTR [rsp+8]
jmp .L226
.L296:
mov edx, DWORD PTR [rsp+100]
add edx, 1
mov DWORD PTR [rsp+100], edx
.L224:
add rax, 4
cmp r14, rax
je .L295
.L226:
mov edx, DWORD PTR [rax]
lea ecx, [rdx-20]
cmp ecx, 74
jbe .L296
cmp edx, 19
jle .L297
mov edx, DWORD PTR [rsp+104]
add rax, 4
add edx, 1
mov DWORD PTR [rsp+104], edx
cmp r14, rax
jne .L226
.L295:
call std::chrono::_V2::system_clock::now()
.L297: // further down
mov edx, DWORD PTR [rsp+96]
add edx, 1
mov DWORD PTR [rsp+96], edx
jmp .L224
Yani bu bize çok fazla şey anlatmıyor, ancak son durum bir şube tahmininin gerekmediği.
Şimdi if'lerin 6 kombinasyonunun hepsini denedim, ilk 2 orijinal ters ve sıralanmıştır. yüksek> = 95, düşük <20, orta 20-94 ve her biri 10000000 yineleme.
high, low, mid: 43000000ns
mid, low, high: 46000000ns
high, mid, low: 45000000ns
low, mid, high: 44000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns
high, low, mid: 44000000ns
mid, low, high: 47000000ns
high, mid, low: 44000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 45000000ns
high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 44000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns
high, low, mid: 42000000ns
mid, low, high: 46000000ns
high, mid, low: 46000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 43000000ns
high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 44000000ns
low, mid, high: 44000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns
high, low, mid: 43000000ns
mid, low, high: 48000000ns
high, mid, low: 44000000ns
low, mid, high: 44000000ns
mid, high, low: 45000000ns
low, high, mid: 45000000ns
high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 45000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns
high, low, mid: 43000000ns
mid, low, high: 47000000ns
high, mid, low: 45000000ns
low, mid, high: 45000000ns
mid, high, low: 46000000ns
low, high, mid: 44000000ns
high, low, mid: 43000000ns
mid, low, high: 46000000ns
high, mid, low: 45000000ns
low, mid, high: 45000000ns
mid, high, low: 45000000ns
low, high, mid: 44000000ns
high, low, mid: 42000000ns
mid, low, high: 46000000ns
high, mid, low: 44000000ns
low, mid, high: 45000000ns
mid, high, low: 45000000ns
low, high, mid: 44000000ns
1900020, 7498968, 601012
Process returned 0 (0x0) execution time : 2.899 s
Press any key to continue.
Peki neden sipariş yüksek, düşük, med sonra daha hızlı (marjinal)
Çünkü en tahmin edilemez sondur ve bu nedenle hiçbir zaman bir dal öngörücüsünden geçmez.
if (i >= 95) ++nHigh; // most predictable with 94% taken
else if (i < 20) ++nLow; // (94-19)/94% taken ~80% taken
else if (i >= 20 && i < 95) ++nMid; // never taken as this is the remainder of the outfalls.
Böylece şubelerin alınacağı, alınacağı ve
% 6 + (0,94 *)% 20 yanlış tahmin.
"Sıralama"
if (i >= 20 && i < 95) ++nMid; // 75% not taken
else if (i < 20) ++nLow; // 19/25 76% not taken
else if (i >= 95) ++nHigh; //Least likely branch
Dallar alınmaz, alınmaz ve Sherlock ile tahmin edilir.
% 25 + (0,75 *)% 24 yanlış tahminler
% 18-23 fark veriyor (~% 9 ölçülen fark), ancak% tahmin etmek yerine döngüleri hesaplamamız gerekiyor.
Nehalem CPU'mdaki 17 döngünün cezayı yanlış tahmin ettiğini ve her kontrolün 1 döngünün (4-5 talimat) ve döngü de bir döngünün alındığını varsayalım. Veri bağımlılıkları sayaçlar ve döngü değişkenleridir, ancak yanlış tahminler yoldan çıktığında zamanlamayı etkilememelidir.
Yani "geri" için zamanlamaları alıyoruz (bu Bilgisayar Mimarisinde kullanılan formül olmalı: Sayısal Bir Yaklaşım IIRC).
mispredict*penalty+count+loop
0.06*17+1+1+ (=3.02)
(propability)*(first check+mispredict*penalty+count+loop)
(0.19)*(1+0.20*17+1+1)+ (= 0.19*6.4=1.22)
(propability)*(first check+second check+count+loop)
(0.75)*(1+1+1+1) (=3)
= 7.24 cycles per iteration
ve "sıralama" için de aynı
0.25*17+1+1+ (=6.25)
(1-0.75)*(1+0.24*17+1+1)+ (=.25*7.08=1.77)
(1-0.75-0.19)*(1+1+1+1) (= 0.06*4=0.24)
= 8.26
(8.26-7.24) /8.26 = ölçülen ~% 9'a karşılık% 13.8 (ölçülene yakın!?!).
Yani OP'nin barizliği belli değil.
Bu testlerle, daha karmaşık kodlu veya daha fazla veri bağımlılığına sahip diğer testler kesinlikle farklı olacaktır, bu nedenle durumunuzu ölçün.
Testin sırasını değiştirmek sonuçları değiştirdi, ancak bunun nedeni döngü başlangıcının farklı yeni hizalamalar nedeniyle olabilir; bu, ideal olarak tüm yeni Intel CPU'larda 16 bayt hizalanmalıdır, ancak bu durumda değildir.