Eşzamanlı çoklu iş parçacığının çalışma prensibi
(blog.codingconfessions.com)- SMT, tek bir CPU çekirdeğinin aynı döngüde birden fazla iş parçacığının komutlarını issue ederek, yalnızca komut düzeyi paralellikle boş kalan yürütme kaynaklarını daha fazla doldurmayı amaçlayan bir tekniktir
- Intel’in Hyper-Threading teknolojisi, çekirdek başına iki iş parçacığı uygulamasıdır; mimari durumu çoğaltarak işletim sistemine tek bir fiziksel çekirdeği iki mantıksal işlemci gibi gösterir
- Gerçek uygulamada tüm kaynaklar basitçe iki katına çıkarılmaz; instruction pointer, ITLB ve RAT çoğaltılır, trace cache ve TLB paylaşılır, uop queue, fiziksel register’lar ve reorder buffer ise eşit bölünür
- Performans kazancı iş yüküne göre değişir: İki iş parçacığı cache’i rekabetçi biçimde kullanırsa yavaşlama olabilir; veri alışverişi yapan işbirlikçi iş parçacıkları ise paylaşılan cache sayesinde hızlanabilir
- Paylaşılan kaynaklar ve spekülatif yürütme güvenlik açıklarına yol açabileceğinden, güvenliğin hassas olduğu ortamlarda veya en yüksek performans/en düşük gecikme gerektiren iş yüklerinde SMT’yi devre dışı bırakmak gerçekçi bir seçenek haline gelir
SMT’ye neden ihtiyaç var?
- Modern işlemciler yüzlerce register’a, birden fazla load/store birimine ve aritmetik birime sahiptir; bunlardan yararlanmak için pipelining, superscalar mimari ve out-of-order execution gibi komut düzeyi paralellik teknikleri kullanılır
- Pipeline, komut yürütmeyi birden fazla aşamaya böler ve her döngüde komutu bir sonraki aşamaya aktarır; derinliği 5 olan bir pipeline’da 5. döngüden sonra en fazla 5 komut aynı anda ilerleyebilir
- Superscalar işlemciler bir döngüde birden fazla komut issue edebilir; yakın dönem Intel Core i7 işlemciler bir döngüde 4 komut issue edebilir
- Gerçek programlarda yeterince bağımsız komut bulmak zor olduğundan yürütme kaynaklarının boş kaldığı zamanlar oluşur
- Yatay israf, tek bir iş parçacığı içinde issue width’i dolduracak kadar bağımsız komut bulunamadığında ortaya çıkar
- Dikey israf, sonraki komutlar o anda yürütülmekte olan komuta bağımlı olduğundan bir döngüde hiçbir komut issue edilemediğinde oluşur
- Geleneksel multithreading, her döngüde yalnızca tek bir iş parçacığının komutunu issue edip sonraki döngüde başka bir iş parçacığına geçerek dikey israfı azaltabilir; ancak yatay israf ve context switch ek yükü kalır
- SMT, context switch olmadan aynı döngüde birden fazla iş parçacığının komutlarını issue ederek yürütme kaynaklarını daha yüksek oranda doldurur
- Intel’in SMT uygulaması olan Hyper-Threading, çekirdek başına iki iş parçacığıyla sınırlıdır
Intel tarzı SMT’nin temel yapısı
- Tipik bir SMT olmayan işlemci aynı anda yalnızca tek bir iş parçacığının komutlarını çalıştırabilir
- Her iş parçacığı register değerleri, program counter, kontrol register’ları vb. içeren bir mimari duruma sahiptir
- İki iş parçacığının komutlarını aynı anda yürütmek için iki iş parçacığının durumunu aynı anda temsil etmek gerekir; bu yüzden SMT uygulaması işlemcinin mimari durumunu çoğaltır
- Bu çoğaltma nedeniyle tek bir fiziksel işlemci, işletim sistemine iki mantıksal işlemci gibi görünür ve işletim sistemi her birine iş parçacığı zamanlayabilir
- Mikro mimari düzeyindeki buffer’lar ve yürütme kaynakları; maliyet, güç ve çip alanı gibi etkenlere bağlı olarak çoğaltılır, paylaşılır veya bölünür
- Tartışmanın odağı ağırlıklı olarak Intel’in SMT uygulamasıdır ve Intel’in 2002 tarihli white paper’ına dayanır
CPU mikro mimarisinin üç bölümü
- İşlemci, programcıya açık arayüz olarak ISA sunar; ISA, komut setini ve komutların kullanabileceği register’ları içerir
- Mikro mimari, aynı ISA’yı destekleyen işlemci modelleri arasında bile değişebilen iç uygulamadır
- Modern işlemcilerin mikro mimarisi genel olarak üç bölüme ayrılır
- Ön uç: Sırada çalıştırılacak program komutlarını getiren ve decode eden komut kontrol birimini içerir
- Arka uç: Fiziksel register’lar, aritmetik birimler ve load/store birimleri gibi yürütme kaynaklarını içerir; decode edilmiş komutlara kaynak atar ve yürütmeyi zamanlar
- retirement unit: Yürütülen komutların sonuçlarını işlemcinin mimari durumuna nihai olarak yansıtır
Ön uçta SMT
- Instruction pointer, sırada getirilecek komutun adresini izler
- SMT destekli işlemciler, iki programın sonraki komutunu bağımsız izlemek için iki instruction pointer setine sahiptir
- trace cache, tekrar tekrar yürütülen komutların decode maliyetini ve yürütme gecikmesini azaltmak için yakın zamanda decode edilmiş komut trace’lerini saklar
- İki mantıksal işlemci ihtiyaçlarına göre dinamik olarak paylaşır
- Bir iş parçacığı daha fazla komut yürütürse trace cache’te daha fazla entry kaplayabilir
- Her entry, iki iş parçacığının komutlarını ayırt etmek için iş parçacığı bilgisiyle tag’lenir
- Trace cache erişimi her döngüde iki mantıksal işlemci arasında arbitre edilir
- Trace cache miss olduğunda ön uç, ilgili adresteki komutu L1 instruction cache’te arar; L1 instruction cache miss olursa bir sonraki cache katmanından veya ana bellekten getirmek gerekir
- L1 instruction cache verileri sanal adres ile cache’ler, ancak ana bellek erişimi için fiziksel adres gerekir
- ITLB, sanal adresi fiziksel adrese çevirmek için yakın zamanda çevrilmiş sanal adresleri tutar
- SMT destekli işlemcilerde her mantıksal işlemcinin kendi ITLB cache’i vardır
- Ana bellekten komut getiren mantık first come first served çalışır; ancak iki mantıksal işlemcinin de ilerleyebilmesi için her mantıksal işlemciye en az bir istek slot’u ayrılır
- Ana bellekten gelen komutlar decode edilmeden önce küçük bir streaming buffer’da saklanır; SMT destekli işlemcilerde bu buffer da mantıksal işlemci başına çoğaltılır
- Komutlar getirildikten sonra daha küçük ve basit uop’lara decode edilir
- uop’lar, CPU ön ucu ile arka ucu arasındaki sınır işlevi gören uop queue’ya girer
- uop queue iki mantıksal işlemci arasında eşit olarak paylaşılır; bu statik bölme, iki mantıksal işlemcinin bağımsız ilerlemesini sağlar
Arka uçta SMT
- Arka uç, uop queue’dan mikro komutları alıp yürütür; ancak yalnızca özgün program sırasına bağlı kalmaz, out-of-order execution gerçekleştirir
- Birbirine yakın program komutları çoğu zaman birbirine bağımlıdır; ana bellek okuma gibi uzun gecikmeli bir iş varsa bağımlı komutlar da beklemek zorunda kalır
- Out-of-order execution motoru, arkadaki komutları özgün sıradan önce çalıştırarak kaynak israfını azaltır
- Allocator, mikro komutların ihtiyaç duyduğu kaynakları belirler ve uygunluğa göre atar
- Bir döngüde bir mantıksal işlemcinin mikro komutlarına kaynak atar, sonraki döngüde diğer mantıksal işlemciye geçer
- uop queue’da yalnızca bir mantıksal işlemcinin mikro komutları varsa veya bir mantıksal işlemci kendi kaynak payının tamamını tüketmişse, allocator tüm döngüleri diğer mantıksal işlemci için kullanır
- Arka ucun başlıca kaynakları çoğaltma, paylaşma ve bölme yöntemlerinin karışımıyla yönetilir
- ISA düzeyindeki X86-64 yalnızca 16 genel amaçlı integer register’a sahip olsa da mikro mimari düzeyinde yüzlerce fiziksel integer register ve benzer sayıda floating-point register vardır
- SMT destekli işlemcilerde fiziksel register’lar iki mantıksal işlemciye eşit bölünür
- Bellek okuma/yazma işlemlerinde kullanılan load buffer ve store buffer da iki mantıksal işlemciye eşit bölünür
Register renaming, zamanlama ve commit
- Out-of-order execution için arka uç register renaming yapar
- ISA düzeyinde az sayıda mimari register bulunduğu için program komutları aynı register’ı birden fazla bağımsız komutta yeniden kullanır
- Out-of-order execution motoru, özgün mantıksal register’ı fiziksel register’lardan biriyle değiştirerek daha önceki yürütmeyle paralel yürütmeyi mümkün kılar
- Bu eşleme register alias table, yani RAT içinde tutulur
- İki mantıksal işlemcinin kendi mimari register setleri olduğundan RAT’in de her biri için bir kopyası vardır
- Register renaming ve allocator aşamalarından geçen komutlar ready queue’ya girer
- Biri bellek okuma/yazma komutları için, diğeri genel komutlar için olan iki queue vardır
- SMT destekli çekirdekte bu queue’lar iki mantıksal işlemciye eşit bölünür
- İşlemcide paralel çalışan birden fazla instruction scheduler bulunur
- Her CPU döngüsünde ready queue’daki bazı komutlar scheduler’a iletilir
- Queue, bir döngüde bir mantıksal işlemcinin komutlarını gönderir; sonraki döngüde diğer mantıksal işlemciye geçer
- Scheduler mantıksal işlemciyi önemsemez; gerekli operand’ları ve execution unit’i hazır olan mikro komutu hemen yürütmeye gönderir
- Adalet için scheduler queue içinde bir mantıksal işlemcinin sahip olabileceği active entry sayısına sınırlama getirilir
- Yürütmesi biten komut sonuçları reorder buffer’a girer
- Komutlar out-of-order yürütülse bile işlemcinin mimari durumuna özgün program sırasıyla commit edilmelidir
- SMT destekli çekirdekte reorder buffer iki mantıksal işlemciye eşit bölünür
- Retirement unit, komutların mimari duruma commit edilmeye hazır olup olmadığını izler ve doğru program sırasıyla retire eder
- SMT destekli çekirdekte her mantıksal işlemcinin mikro komutları arasında dönüşümlü işlem yapar
- Bir mantıksal işlemcide retire edilecek mikro komut yoksa tüm bant genişliğini diğer mantıksal işlemci için kullanır
- Komut retire edildikten sonra L1 cache’e yazılması gerekebilir; bu yazma seçim mantığı da her döngüde iki mantıksal işlemci arasında dönüşümlü çalışır
Bellek alt sistemi ve cache etkisi
- Veri isteklerinin sanal adresini fiziksel adrese çeviren TLB, iki mantıksal işlemci tarafından ihtiyaçlarına göre dinamik olarak paylaşılır
- TLB entry’leri, iki mantıksal işlemcinin girdilerini ayırt etmek için logical processor id ile tag’lenir
- Her CPU çekirdeğinin kendine ait private L1 cache’i vardır
- L2 cache, mikro mimariye bağlı olarak private olabilir veya çekirdekler arasında paylaşılabilir
- L3 cache varsa çekirdekler arasında paylaşılır
- Cache’ler mantıksal işlemcilerin varlığından haberdar değildir
- L1 cache ve duruma göre L2 cache çekirdeğe private olduğundan, iki mantıksal işlemcinin verilerini ihtiyaç halinde birlikte barındırır
- İki iş parçacığı cache’i agresif biçimde kullanırsa veri çakışmaları ve eviction oluşarak performans düşebilir
- İki iş parçacığı aynı veri kümesi üzerinde çalışırsa paylaşılan cache performansı artırabilir
Performans ve güvenlikte seçim ölçütleri
- SMT destekli bir çekirdekte yalnızca tek bir iş parçacığı çalışsa bile birçok buffer ve yürütme kaynağı iki mantıksal işlemci arasında paylaşılmış veya bölünmüş durumda kalır; bu, tek iş parçacığının potansiyel performansını düşürebilir
- Kullanılmayan mantıksal işlemcide işletim sistemi idle loop çalıştırır; bu döngü de diğer mantıksal işlemcinin maksimum performans için kullanabileceği kaynakları tüketebilir
- Intel Core işlemcilerde, çekirdekte yalnızca tek iş parçacığı çalıştığında kaynak paylaşımı veya bölünmesi yok gibi görünür; Intel bunu o nesilde getirilen bir iyileştirme olarak ele alır
- İki iş parçacığı SMT destekli bir çekirdeğin iki mantıksal işlemcisinde çalıştığında performansı cache erişim kalıpları belirler
- İki iş parçacığı cache için rekabet ederse birbirlerinin verilerini evict ederek performansı düşürür
- Bir iş parçacığının ürettiği veriyi diğerinin tüketmesi gibi işbirlikçi durumlarda cache verisi paylaşımı performansı artırır
- İki iş parçacığı cache’i rekabetçi biçimde kullanmıyorsa birbirlerinin performansını olumsuz etkilemeden CPU çekirdeği kaynak kullanımını artırabilir
- Mutlak en yüksek performans gerektiren programlarda, tek iş parçacığının tüm kaynakları kullanabilmesi için SMT’yi kapatmanın daha iyi olduğunu düşünen birçok uzman vardır
- SMT’nin güvenlik sorunları da vardır
- Paylaşılan kaynaklar ve spekülatif yürütme nedeniyle hassas verilerin saldırgana sızması ihtimali doğabilir
- Oracle Linux ve Red Hat belgeleri SMT ile ilgili güvenlik sorunu örneklerine bağlanır
- Genel tavsiye, sistemde SMT’yi devre dışı bırakma yönündedir
- Intel’in bir sonraki nesil işlemcisi Arrow Lake’te Hyper-Threading’i kaldırabileceğine dair söylentiler de vardır
1 yorum
Hacker News yorumları
SMT’yi çok basitleştirerek anladığınızda, bir iş parçacığı cache miss yüzünden dururken değerli ALU’ları meşgul tutmaya devam edebilmesi akla yatıyor
Eski dizüstülerdeki LPDDR daha yavaştı ve çekirdek sayısı da azdı; bu yüzden muhtemelen daha değerliydi. Ama bugünlerde ölçeklenebilir işlerden daha fazla çekirdeğe sahip olmak da sık görülüyor, bu yüzden değeri daha az hissediliyor
Önemli bir iş parçacığıyla aynı çekirdeğe iş yerleştirmeyerek önbellek çekişmesini önlemeye de çalışılıyor; çünkü darboğazın tek iş parçacığı performansı olduğu biliniyor
Eskiden DirectX 12’nin çok iş parçacıklı render işleminde Efficient/Performance çekirdekleri ve SMT çekirdeklerini test etmiştim; i7-12700K’de yalnızca P-core kullanılan durumla P+SMT ve P+E+SMT, karmaşık sahne render sürelerinde neredeyse aynıydı. Ancak Xbox Series X’te aynı test, işler SMT’ye de yerleştirildiğinde biraz daha hızlıydı
SMT, giriş/çıkış beklerken veya basit tamsayı işleri yaparken parlar. İki iş parçacığının ikisi de FPU’yu doyurabiliyorsa, CPU içi verilerde sahipliği belirtmek için gereken ek etiketleme nedeniyle SMT genelde daha yavaş olur
Esas mesele cache miss’ten çok, yazma işlemi tamamlanırken çekirdeğin başka işler yürütmesine izin vermesidir
Bu yüzden bazı kodlar iyi ölçeklenmezken bazı kodlar neredeyse doğrusal hızlanma elde eder
Belki de bu işlemcilerin arada kısa şekerlemeler yapmasına izin vermek daha iyi olabilir
Veri yolu genişliği, saniye başına aktarım sayısı, kuyruklama ve bit aktarımı/depolaması başına güç iyileşti; ama program önbellekte olmayan veriye ihtiyaç duyuyorsa ve tahmin de boşa çıktıysa, sonunda sorun RAM gecikmesi oluyor
Intel’in yeni nesil Arrow Lake CPU’larının Hyper-Threading’i, yani SMT’yi tamamen kaldıracağı söyleniyor
Performans kazancı her zaman uygulamaya çok bağımlıydı; bu yüzden sadeleştirmek daha iyi olabilir
Nerede ve ne zaman anlamlı olduğuna dair güncel bir tartışma burada: https://news.ycombinator.com/item?id=39097124
Henüz kesin olarak o noktaya gelindiğinden emin değilim; ama Intel’in P/E çekirdekleri benzer bir hedefe yönelik bir alternatif ve tek iş parçacıklı/az iş parçacıklı işlerin çok olduğu masaüstlerinde oldukça mantıklı. Uygulama optimizasyonunda SMT ile E-core ayrımını ele almak zorunda olmamanın da bir değeri var gibi görünüyor
Buna karşılık AMD, yakın vadede büyük ölçüde homojen çekirdekleri koruyup SMT kullanmaya devam etmeyi planlıyor. Hangi stratejinin gerçekten daha iyi olduğu uygulamadan uygulamaya çok değişeceğinden, basitçe hüküm vermek zor görünüyor
Bu yüzden iş parçacığı sayısını
std::thread::hardware_concurrency() / 2 - 1, yani çekirdek sayısı - 1 ile sınırlamaya karar verdim.std::vectorile çalışıyorumİyi çalıştığında bile iyileşme ancak iki haneli yüzdeler düzeyindeydi; art arda nesillerde daha kötü olduğu dönemler de vardı. Neden denemeye devam ettiklerini bilmiyorum
Bu tür düşük seviyeli CPU özelliklerinin nasıl çalıştığını her okuduğumda şaşırıyorum
Üniversitede “bilgisayar donanımına giriş” gibi bir ders almıştım; aslında “CPU tasarımına giriş” denmeliydi. Mantık kapılarıyla toplayıcı, latch, flip-flop vb. yapıyorduk ve dönem sonunda kapı düzeyinde çok temel bir işlemci tasarlayabiliyorduk
Ama register renaming veya out-of-order execution gibi şeyleri düşünüp ortaya çıkarmayı pek hayal edemiyorum. Bunlar da kapı düzeyinde mi tasarlanıyor? Yoksa kullanılan bir dil ve kapıları/transistörleri yerleştiren bir “derleyici” mi var?
Ödevlerin hepsi Verilog adlı donanım tanımlama diliyle yapılıyordu; bu sayede birçok öğeyi soyutlayarak yazabiliyorduk
Kullanıcıların SMT hakkında sık sahip olduğu büyük yanlış anlamalardan biri, bir “gerçek çekirdek” ve ondan daha aşağı bir çekirdek olduğunu hayal eden zihinsel modeldir
Gözlemlenebilir tüm yönleriyle iki iş parçacığı eşittir
Sonuçta yalnızca performansa bakarsak kavramsal olarak tek iş parçacıklı 1,25 çekirdek ya da uygulamaya bağlı olarak o oranda bir şey varmış gibi düşünmek daha yakındır
E-core’ların getirilmesinin başlıca nedeninin güç kullanımı ya da performanstan çok ısı ve yonga alanı olduğunu düşünüyorum. Bu yüzden her zaman E-core olmayan çipleri satın alıyorum; onların daha iyi olduğunu düşünüyorum
Bu tür ayrıntılı teknik yazıları nasıl aramak gerektiğini merak ediyorum
Tam bu konuyla arama yaptım ama beklendiği gibi son kullanıcıya yönelik bir teknoloji olduğu için arama sonuçlarında hiçbir şeyi doğru düzgün açıklamayan kullanıcı yazılarından başka bir şey yoktu
Ancak verdikleri URL’lerin çoğu halüsinasyon
Bunu başka bir cihazda yeni bir Firefox gizli sekmesinde kontrol ettim; izlemeyi ya da önbelleğe almayı tamamen engellemiş sayılmaz ama oldukça makul bir yaklaşık değer olduğunu düşünüyorum
“SMT açık bir CPU çekirdeğinde birçok tampon ve yürütme kaynağı iki mantıksal işlemci tarafından paylaşılmak zorunda olduğundan, SMT çekirdeğinde yalnızca tek bir iş parçacığı çalışıyor olsa bile bu kaynaklar o iş parçacığı tarafından kullanılamaz ve potansiyel performans azalır” açıklaması artık doğru değil
SMT modunda ROB, fetch/decode bant genişliği vb. bölünüyor; ancak SMT dışı durumda tamamının kullanılmasına izin veren çeşitli SMT çekirdekleri gördüm
SMT’nin temel amacı süperskaler yürütme motorunun kullanım oranını en üst düzeye çıkarmak
Bu gidişatın, insanların süperskalerin artık eskisi kadar önemli olmadığını düşündüğü anlamına gelip gelmediğini merak ediyorum
Genel olarak iyi bir özet, ama yer yer biraz birbirine karışmış gibi geldi
Güvenlikle ilgisi olmayan kapsamda bile içeridekilerin kullandığı pratik iş sırlarını daha fazla bilmek isterdim
Zavallı AMD Bulldozer mimarisi SMT olmadığı için o kadar eleştirilmişti; şimdi ise herkes SMT’den uzaklaşıyor
Elbette Bulldozer’ın SMT yokluğu dışında çok daha fazla sorunu olduğunu biliyorum. Aslında birden çok çekirdeğin aynı ALU gibi şeyleri paylaştığı, neredeyse tam tersi bir yapıya sahipti. Yine de performansı biraz daha yukarı çekebilseydi, bir şeyleri önceden görmüş sayılabilirdi
Power10 şu anda çekirdek başına 8 iş parçacıklı SMT8’i etkili biçimde destekliyor ve yıllardır SMT odaklı tasarımı geliştirmeyi sürdürdükleri düşünülürse, bunu bırakacaklarını sanmıyorum
Bilinmesinde fayda olan bir nokta, GPU’lardaki hesaplama birimlerinin de genellikle CU başına 7~10 iş parçacığı düzeyinde SMT kullanmasıdır
Bu yöntem gecikmeyi gizlemeye yardımcı olur
Her saat çevriminde, kullanılabilir birden çok iş parçacığı arasından meşgul olmayan kaynaklara ihtiyaç duyan bir iş parçacığının komutu seçilip başlatılır. Çoğu GPU saat başına birden çok komut başlatmaz; birden çok komut başlatıldıktan sonra aynı anda ilerleyebilir. Saat başına birden çok komut başlatılsa bile bunların skaler komutlar ve vektör komutlar gibi farklı yürütme kaynakları kullanan ayrı komut sınıflarına ait olması gerekebilir
SMT, yani eşzamanlı çoklu iş parçacığı, her saat çevriminde tüm iş parçacıklarından çok sayıda komutun aynı anda başlatıldığı ve bu komutların süperskaler CPU’nun çeşitli yürütme birimleri için rekabet ederek mümkün olduğunca çok yürütme birimini meşgul tutmaya çalıştığı bir yöntemdir. Modern CPU’lardaki 6 tamsayı toplayıcının her biri gibi her paralel yürütme birimi için, tüm eşzamanlı iş parçacıklarının komutlarını içeren kuyruktan hangi komutun yürütüleceğine ayrı ayrı karar verilir