Bölüm 5: Modern İşlemci Teknikleri
CPU'ya“Sen”iKatmak yazısının parçası: bilgisayarının programları nasıl çalıştırdığına doğru inen uzun bir teknik tavşan deliği.
Şimdiye kadar CPU’yu basit bir “talimat oku, yürüt, tekrar et” makinesi olarak gördük. Gerçek hayatta modern işlemciler çok daha karmaşık ve akıllıdır. Bir talimat bitmeden diğerine başlayabilirler, gelecekteki kararları tahmin edebilirler ve tek bir çipin içinde birden fazla çekirdek barındırırlar. Bu bölümde, CPU’nun gerçek dünyadaki hız sırlarını keşfedeceğiz.
Bu bölümde neyi çözüyoruz?
- CPU’nun aynı anda birden fazla talimatı nasıl yürüttüğünü (pipeline, superscalar) göreceğiz.
- Branch prediction ve spekülatif yürütme kavramlarını anlayacağız.
- Çok çekirdekli işlemcilerin ve hyper-threading’in nasıl çalıştığını öğreneceğiz.
- Bu tekniklerin neden Spectre ve Meltdown gibi güvenlik açıklarına yol açtığını bağlayacağız.
Pipeline: Fabrika Bandı Gibi Çalışmak
İlk CPU’lar bir talimatı tamamen bitirmeden diğerine geçmezdi. Fetch, decode, execute, write-back adımları tek tek yapılırdı. Modern CPU’lar ise pipeline (boru hattı) kullanır. Fabrika bandı gibi, her aşamada farklı bir talimat bulunur.
| Aşama | Ne Yapar? |
|---|---|
| Fetch | Bellekten bir sonraki talimatı getir |
| Decode | Talimatı çözümle (ne yapacağını anla) |
| Execute | İşlemi gerçekleştir (toplama, çarpma vb.) |
| Memory | Gerekirse belleğe oku/yaz |
| Write-back | Sonucu register’a geri yaz |
Basit bir örnek: 5 aşamalı bir pipelineda, 5. saat çevriminde 5 farklı talimat aynı anda farklı aşamalarda ilerler. Teorik olarak her saat çevriminde bir talimat bitirilebilir.
Pipeline Hazardları
Pipeline’ın verimli çalışması için talimatlar sürekli akmalıdır. Ama bazı durumlarda bir sonraki aşamaya geçiş engellenir; buna hazard denir. Üç temel türü vardır:
- Yapısal Hazard (Structural): İki talimat aynı anda aynı donanım birimini kullanmaya çalışır. Örneğin tek bir bellek portu hem fetch hem memory aşamasında kullanılmak istenirse biri beklemek zorundadır.
- Veri Hazardı (Data): Bir talimatın çalışması için önceki talimatın sonucuna ihtiyaç duyulur ama o sonuç henüz yazılmamıştır.
- Kontrol Hazardı (Control): Koşullu dallanma (
if,jmp) sonrası hangi talimatın geleceği bilinmez; pipeline’ın doğru yoldan devam etmesi için beklenir veya tahmin edilir.
Veri hazardlarından en yaygın olanı Read-After-Write (RAW) bağımlılığıdır:
add eax, ebx
mov ecx, eax ; Needs result from previous instruction — causes stall
mov ecx, eax talimatı eax‘in güncellenmiş değerine ihtiyaç duyar. Eğer add talimatının write-back aşaması henüz tamamlanmadıysa, CPU bir veya daha fazla saat çevrimi stall (duraklama) ekler veya bypassing/forwarding ile sonucu doğrudan execute birimine yönlendirir.
Superscalar: Birden Fazla Fabrika Bandı
Pipeline tek bir fabrika bandıdır. Superscalar işlemciler ise aynı anda birden fazla talimatı farklı birimlerde yürütebilir. Örneğin bir toplama birimi ve bir çarpma birimi aynı anda çalışabilir.
- IPC (Instructions Per Cycle): Bir saat çevriminde kaç talimat yürütülür? Basit pipelineda ~1, superscalarda >1 olabilir.
- Out-of-Order Execution: İşlemci, talimatların bağımsız olanlarını önce yürütüp bağımlı olanları bekletebilir. Bu, pipeline’ın boş kalmamasını sağlar.
Branch Prediction: Geleceği Tahmin Etmek
Programlar sık sık koşullu dallanmalar kullanır (if, while, for). Pipeline’ın verimli çalışması için CPU bir sonraki talimatı önceden getirmelidir. Ama dalın nereye gideceğini bilmeden ne getireceksin?
Branch prediction (dal tahmini) devreye girer. CPU, geçmişteki dallanma davranışlarına bakarak “bu dal muhtemelen atlayacak” veya “atlamayacak” diye tahminde bulunur.
- Static prediction: Basit kurallar (örneğin “geriye dönen dallar atlar, ileriye dönenler atlamaz”).
- Dynamic prediction: Geçmiş davranışları takip eden donanım tabloları (Branch Target Buffer, BTB). 2-bit saturating counter gibi mekanizmalar kullanılır.
Modern CPU’ların branch predictor’ları %95+ isabet oranına ulaşabilir. Yanlış tahmin edilirse pipeline boşaltılır (flush) ve doğru yoldan devam edilir; bu ceza onlarca saat çevrimi sürebilir.
Derinleşme: 2-bit Saturating Counter
Dinamik branch prediction’da en yaygın mekanizmalardan biri 2-bit saturating counter‘dır. Bu sayaç, bir dalın geçmişteki davranışına göre dört durumdan birinde bulunur:
- Strongly Not Taken — Kesin atlamaz
- Weakly Not Taken — Büyük ihtimalle atlamaz
- Weakly Taken — Büyük ihtimalle atlar
- Strongly Taken — Kesin atlar
Dal atlanırsa sayaç bir artar, atlanmazsa bir azalır. Sınır değerlerde “sıkışır” (saturates); bu yüzden tek bir yanlış tahmin hemen yön değiştirmez. Bu, kısa döngülerdeki dal davranışındaki gürültüye karşı dayanıklılık sağlar.
+1 (taken)
+---------------------------+
| |
v |
+---------+ +---------+
| Weakly | | Weakly |
| Not | +1 (taken) | Taken |
| Taken +--------------> | |
+----+----+ +----+----+
^ |
| -1 (not taken) | -1 (not taken)
| v
+----+----+ +---------+
| Strongly| | Strongly|
| Not |<---------------+ Taken |
| Taken | -1 (not taken) |
+---------+ +---------+
Spekülatif Yürütme ve Güvenlik
Tahmin edilen dalın talimatlarını spekülatif olarak yürütme (speculative execution), tahmin doğru çıkana kadar mimari sonuçları geçici tutmak demektir. Tahmin doğruysa sonuçlar görünür hâle gelir, yanlışsa mimari durum geri alınır. Sorun şu: geri alınan spekülatif yürütme bile cache gibi mikro-mimari yapılarda ölçülebilir iz bırakabilir.
2018’de duyurulan Spectre ve Meltdown ailesi açıklar bu farkı görünür yaptı:
- Spectre: Branch prediction ve spekülatif yürütme, normalde okunmaması gereken veriye bağlı cache izleri oluşturabilir. Saldırgan bu izleri zamanlama ölçümleriyle okuyarak gizli veriyi dolaylı çıkarabilir.
- Meltdown: Bazı işlemcilerde user-space kodunun, izin kontrolü mimari olarak erişimi engellese bile spekülatif pencerede kernel verisine dokunup cache yan kanalına iz bırakabilmesiyle ilgilidir.
Bu açıkların ardından işlemci üreticileri ve işletim sistemleri mikrokod güncellemeleri, KPTI/site isolation, retpoline ve speculative execution kısıtları gibi savunmalar geliştirdi. Detaylar işlemci ailesine ve işletim sistemi sürümüne göre değişir.
Çok Çekirdekli İşlemciler
Pipeline ve superscalar tek bir çekirdek (core) içinde paralellik sağlar. Ama fiziksel sınırlar (ısı, güç tüketimi) tek bir çekirdeği sınırsız hızlandıramaz. Çözüm: Aynı çip üzerinde birden fazla bağımsız çekirdek.
- Multi-core: 2, 4, 8, 16, 64… çekirdek aynı CPU çipinde.
- Her çekirdek kendi L1/L2 cache’ine ve register setine sahiptir.
- L3 cache genelde tüm çekirdekler arasında paylaşılır.
Programlama dillerinde
std::thread(C++),Thread(Java),threading(Python) gibi yapılar bu çok çekirdekli yapıyı kullanmak içindir. Ama birden fazla çekirdek kullanmak, programın paralel çalışacak şekilde yazılmasını gerektirir.
Simultaneous Multithreading (SMT / Hyper-Threading)
Intel’in Hyper-Threading teknolojisi (genel adıyla SMT), tek bir fiziksel çekirdeğin içinde iki (veya daha fazla) mantıksal yürütme akışı çalıştırmasına olanak tanır.
- Fiziksel kaynaklar (ALU, FPU, cache) aynıdır.
- Register seti ve instruction pointer gibi durum bilgileri iki kopya tutulur.
- Bir akış bellekten veri beklerken (cache miss), diğer akış çalışmaya devam eder; böylece çekirdek boş kalmaz.
SMT, tek thread’in performansını ikiye katlamaz ama genel verimliliği %10-30 artırabilir. Güvenlik açısından bazı bulut sağlayıcıları SMT’yi devre dışı bırakır (yan yana thread’ler arası bilgi sızıntısı riski).
SIMD: Tek Talimat, Çok Veri
SIMD (Single Instruction, Multiple Data), bir talimatın aynı anda birden fazla veri parçası üzerinde çalışmasını sağlar. Örneğin bir vektörün tüm elemanlarını tek seferde toplayabilirsiniz.
- SSE (Streaming SIMD Extensions): 128-bit register’lar.
- AVX (Advanced Vector Extensions): 256-bit register’lar.
- AVX-512: 512-bit register’lar.
Video işleme, yapay zeka, bilimsel hesaplama gibi alanlarda SIMD kritik öneme sahiptir. Derleyiciler otomatik vektörize etme (auto-vectorization) yapabilir ama en verimli kullanım için elle intrinsic fonksiyonları kullanılır.
Bir yana: Neden AVX-512 Tartışmalı?
AVX-512 daha geniş register’lar ve daha fazla paralellik vaat eder, ama bu verimlilik bedelsiz değildir. 512-bit işlemler çekirdek içindeki vektör birimlerini çok daha yoğun kullanır ve bu doğrudan ısı artışına yol açar.
Sonuç: CPU, termal sınırlara ulaştığında termal throttling devreye girer; saat hızı (frequency) düşer. Bazı işlemciler AVX-512 talimatları gördüğünde tüm çekirdekleri daha düşük frekansa çeker. Bu yüzden AWS, GCP gibi bazı bulut sağlayıcıları AVX-512’yi varsayılan olarak devre dışı bırakır veya özel instance tiplerinde sınırlar. “Daha fazla SIMD” her zaman “daha hızlı” anlamına gelmez; iş yüküne, soğutmaya ve güç bütçesine bağlıdır.
CPU’yu Gözlemlemek
Bu teknikler sadece teoride kalmaz. İşletim sistemi üzerinde çalışan araçlarla CPU’nun özelliklerini ve programların pipeline verimliliğini doğrudan gözlemleyebilirsiniz.
İşlemci modeli, çekirdek ve thread sayısını hızlıca öğrenmek için:
lscpu | grep -E "Model name|Thread|Core"
Beklenen çıktı örneği:
Model name: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
Thread(s) per core: 2
Core(s) per socket: 6
İşlemcinin desteklediği instruction set’lerini görmek için:
cat /proc/cpuinfo | grep -m1 flags
Beklenen çıktı formatı (kısaltılmış):
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid xsaveopt arat
Bir programın pipeline verimliliğini ölçmek için Linux perf aracını kullanabilirsiniz:
perf stat ./your_program
Çıktıda dikkat edilmesi gereken en kritik metrik IPC (Instructions Per Cycle) veya tersi CPI (Cycles Per Instruction) olacaktır:
Performance counter stats for './your_program':
1,234,567 cycles
2,987,654 instructions # 2.42 insn per cycle
IPC > 1 demek, işlemciniz superscalar yeteneklerini kullanarak bir saat çevriminde birden fazla talimat bitiriyor. IPC < 1 ise pipeline’ın stall, cache miss veya yanlış branch tahmini nedeniyle verimsiz çalıştığına işaret eder.
Özet
- Pipeline: Talimatları aşamalara bölüp aynı anda çok sayıda talimatı ilerletir.
- Superscalar / Out-of-Order: Birden fazla birim ve bağımsız talimatları yeniden sıralayarak verimlilik artırır.
- Branch Prediction: Dallanmaları tahmin ederek pipeline’ın boş kalmasını engeller.
- Spekülatif Yürütme: Tahmin edilen yolu önceden yürütür ama Spectre/Meltdown gibi güvenlik riskleri taşır.
- Multi-core: Aynı çip üzerinde birden fazla bağımsız çekirdek.
- SMT / Hyper-Threading: Tek çekirdekte birden fazla mantıksal akış.
- SIMD: Bir talimatla çok veri üzerinde paralel işlem.
Bu teknikler birbirine sıkı sıkıya bağlıdır. Pipeline’ın verimli çalışması için branch prediction gerekir; branch prediction’ın isabet oranını düşüren şeylerden biri bellek hiyerarşisindeki gecikmelerdir. Bölüm 3’te gördüğümüz cache miss’ler, pipeline’ın veri hazardlarına benzer şekilde stall’ere yol açar. Multitasking ve context switch kavramlarında ise pipeline’ın tamamen boşaltılması (flush) performans maliyeti demektir; bu konuyu Zamanı Dilimle bölümünde ele alıyoruz.
Artık CPU’nun sadece “talimatları sırayla yürüten” bir motor değil, son derece optimize edilmiş, tahminler yapan ve paralel çalışan karmaşık bir sistem olduğunu biliyoruz. Bir sonraki bölümde, bu işlemciye bir programın nasıl yüklendiğini ve işletim sisteminin bunu nasıl yönettiğini göreceğiz. Bu tekniklerin neden Spectre/Meltdown gibi güvenlik açıklarına yol açtığını da bağlamış olduk.
Sonraki Bölüm: Bölüm 6 — Bir Program Nasıl Çalıştırılır?
6. bölüme devam et: Bir Program Nasıl Çalıştırılır?