Sen şube tahmin kurbanı başarısız.
Şube Tahmini nedir?
Bir demiryolu kavşağını düşünün:
Mecanismo, Wikimedia Commons üzerinden görüntü . CC-By-SA 3.0 lisansı altında kullanılır .
Şimdi tartışma uğruna, bunun 1800'lerde - uzun mesafe veya radyo iletişiminden önce olduğunu varsayalım.
Bir kavşağın operatörü sizsiniz ve bir trenin geldiğini duyuyorsunuz. Hangi yöne gitmesi gerektiği hakkında hiçbir fikrin yok. Sürücüye hangi yönde istediklerini sormak için treni durdurursunuz. Ve sonra anahtarı uygun şekilde ayarladınız.
Trenler ağırdır ve çok fazla atalete sahiptir. Bu yüzden başlamak ve yavaşlamak sonsuza dek sürüyor.
Daha iyi bir yol var mı? Trenin hangi yöne gideceğini tahmin et!
- Doğru tahmin ederseniz, devam eder.
- Yanlış tahmin ederseniz, kaptan duracak, geri dönecek ve anahtarı çevirmeniz için size bağıracaktır. Sonra diğer yoldan yeniden başlayabilir.
Her seferinde doğru tahmin ederseniz , tren asla durmak zorunda kalmayacak.
Çok sık yanlış tahmin ederseniz , tren durmak, yedeklemek ve yeniden başlamak için çok zaman harcayacaktır.
Bir if ifadesini düşünün: İşlemci düzeyinde, bir dal talimatıdır:
Siz bir işlemcisiniz ve bir şube görüyorsunuz. Hangi yöne gideceğine dair hiçbir fikrin yok. Ne yaparsın? Yürütmeyi durdurur ve önceki talimatlar tamamlanana kadar beklersiniz. Sonra doğru yolda devam.
Modern işlemciler karmaşıktır ve uzun boru hatlarına sahiptir. Bu yüzden sonsuza dek "ısınmak" ve "yavaşlamak" için uğraşırlar.
Daha iyi bir yol var mı? Şubenin hangi yöne gideceğini tahmin edin!
- Doğru tahmin ederseniz, yürütmeye devam edersiniz.
- Yanlış tahmin ederseniz, boru hattını yıkamanız ve şubeye geri dönmeniz gerekir. Ardından diğer yolu yeniden başlatabilirsiniz.
Her seferinde doğru tahmin ederseniz , yürütme asla durmak zorunda kalmayacak.
Çok sık yanlış tahmin ederseniz , durmak, geri dönmek ve yeniden başlatmak için çok zaman harcıyorsunuz.
Bu dal tahmini. Bunun en iyi benzetme olmadığını itiraf ediyorum çünkü tren sadece bir bayrakla yön gösterebiliyordu. Ancak bilgisayarlarda, işlemci bir dalın son ana kadar hangi yöne gideceğini bilmiyor.
Öyleyse, trenin diğer yoldan kaç kez geri gitmesi gerektiğini stratejik olarak tahmin edersiniz? Geçmiş tarihe bakıyorsunuz! Tren zamanın% 99'undan ayrılırsa, o zaman ayrıldınız demektir. Değişiyorsa, tahminlerinizi değiştirirsiniz. Her üç seferde bir şekilde giderse, aynı şeyi tahmin edersiniz ...
Başka bir deyişle, bir deseni belirlemeye ve onu izlemeye çalışırsınız. Şube tahmin edicilerinin çalışma şekli budur.
Uygulamaların çoğunun iyi davranmış dalları vardır. Dolayısıyla, modern şube tahmincileri genellikle% 90'ın üzerinde isabet oranlarına ulaşacaktır. Ancak, tanınabilir paternleri olmayan öngörülemeyen dallarla karşılaşıldığında, dal tahmincileri neredeyse işe yaramaz.
İlave okumalar: Wikipedia'da "Şube öngörücüsü" makalesi .
Yukarıda ima edildiği gibi, suçlu bu if-ifadesidir:
if (data[c] >= 128)
sum += data[c];
Verilerin 0 ile 255 arasında eşit olarak dağıtıldığına dikkat edin. Veriler sıralandığında kabaca yinelemelerin ilk yarısı if-ifadesine girmez. Bundan sonra hepsi if ifadesine girecek.
Şube defalarca aynı yöne gittiğinden, bu durum şube öngörücüsü için çok uygundur. Basit bir doygunluk sayacı bile, yönü değiştirdikten sonraki birkaç yineleme haricinde dalı doğru şekilde tahmin edecektir.
Hızlı görselleştirme:
T = branch taken
N = branch not taken
data[] = 0, 1, 2, 3, 4, ... 126, 127, 128, 129, 130, ... 250, 251, 252, ...
branch = N N N N N ... N N T T T ... T T T ...
= NNNNNNNNNNNN ... NNNNNNNTTTTTTTTT ... TTTTTTTTTT (easy to predict)
Ancak, veriler tamamen rasgele olduğunda, şube öngörücüsü işe yaramaz hale getirilir, çünkü rastgele verileri tahmin edemez. Böylece muhtemelen yaklaşık% 50 yanlış tahmin olacaktır (rastgele tahmin etmekten daha iyi değildir).
data[] = 226, 185, 125, 158, 198, 144, 217, 79, 202, 118, 14, 150, 177, 182, 133, ...
branch = T, T, N, T, T, T, T, N, T, N, N, T, T, T, N ...
= TTNTTTTNTNNTTTN ... (completely random - hard to predict)
Peki ne yapılabilir?
Derleyici, dalı koşullu bir hareketle optimize edemezse, performans için okunabilirliği feda etmek istiyorsanız bazı hack'leri deneyebilirsiniz.
Değiştir:
if (data[c] >= 128)
sum += data[c];
ile:
int t = (data[c] - 128) >> 31;
sum += ~t & data[c];
Bu, dalı ortadan kaldırır ve bazı bitsel işlemlerle değiştirir.
(Bu kesmek kesinlikle orijinal if-ifadesiyle eşdeğer değildir. Ancak bu durumda, tüm giriş değerleri için geçerlidir data[]
.)
Deneyler: Core i7 920 @ 3,5 GHz
Visual Studio 2010 - x64 Sürümü
// Branch - Random
seconds = 11.777
// Branch - Sorted
seconds = 2.352
// Branchless - Random
seconds = 2.564
// Branchless - Sorted
seconds = 2.587
Java - NetBeans 7.1.1 JDK 7 - x64
// Branch - Random
seconds = 10.93293813
// Branch - Sorted
seconds = 5.643797077
// Branchless - Random
seconds = 3.113581453
// Branchless - Sorted
seconds = 3.186068823
Gözlemler:
- Şube ile: Sıralanan ve sıralanmamış veriler arasında büyük bir fark vardır.
- Hack ile: Sıralanmış ve sıralanmamış veriler arasında fark yoktur.
- C ++ durumunda, veri sıralandığında kesmek aslında daldan biraz daha yavaştır.
Genel bir kural, kritik döngülerde (bu örnekte olduğu gibi) verilere bağlı dallanmadan kaçınmaktır.
Güncelleme:
X64 ile -O3
veya -ftree-vectorize
üzerinde GCC 4.6.1, koşullu bir hareket oluşturabilir. Dolayısıyla, sıralanan ve sıralanmamış veriler arasında fark yoktur - her ikisi de hızlıdır.
(Ya da biraz hızlı: zaten sıralanmış durum için, cmov
özellikle GCC bunu sadece yerine kritik yola koyarsa add
, özellikle cmov
2 döngü gecikmesi olan Broadwell'den önce Intel'e daha yavaş olabilir : gcc optimizasyon bayrağı -O3 kodu -O2'den daha yavaş yapar )
VC ++ 2010, bu dal için altında bile koşullu hareketler oluşturamaz /Ox
.
Intel C ++ Derleyici (ICC) 11 mucizevi bir şey yapar. Bu iki döngü alışverişini sağlar , böylece dış döngüye öngörülemeyen dalı kaldırma. Bu yüzden sadece yanlış tahminlere karşı bağışık değil, aynı zamanda VC ++ ve GCC'nin üretebildiği her şeyin iki katı daha hızlı! Başka bir deyişle, ICC karşılaştırmayı yenmek için test döngüsünün avantajlarından yararlandı ...
Intel derleyicisine dalsız kod verirseniz, tam olarak sağda vektörleştirir ... ve dalda olduğu kadar hızlıdır (döngü değişimli).
Bu, olgun modern derleyicilerin bile kodu optimize etme yeteneklerinde çılgınca değişebileceğini gösteriyor ...