Thanks to visit codestin.com
Credit goes to cpu.emircandemir.com

Ana içeriğe geç

Bölüm 3: Bellek Hiyerarşisi

Bir önceki bölümde CPU’nun talimatları nasıl yürüttüğünü, RAM’in çalışma masası olduğunu ve diskin kalıcı depo olduğunu gördük. Ama bu üçlü arasında aslında çok daha fazla katman var. Bilgisayarın belleği tek düzeyli değil; bir piramit gibi katman katman düzenlenmiş. Neden? Çünkü hızlı bellek pahalıdır, ucuz bellek yavaştır. Piramidin tepesi hızlı ve küçük, tabanı büyük ve yavaş.

Bu bölümde neyi çözüyoruz?

  • CPU’dan diske kadar olan bellek piramidini adım adım çıkacağız.
  • Register, cache, RAM ve disk arasındaki hız ve maliyet farkını anlayacağız.
  • SRAM ile DRAM farkını, cache line kavramını ve locality prensibini öğreneceğiz.

Piramidin Tepesi: Register’lar

CPU’nun içindeki register’lar, daha önce gördüğümüz gibi, işlemcinin doğrudan erişebildiği küçük depolama alanlarıdır. Bir register’ın içeriğine ulaşmak CPU için birkaç nanosaniye sürer. Bu, ışığın birkaç santimetre yol alması kadar kısa bir süredir.

Birinci Kademe: L1 Cache

Register’lar yeterli değil. CPU, RAM’den veri almak için yüzlerce saat çevrimi beklemek zorunda kalıyordu. Bu boşluğu doldurmak için cache‘ler (önbellekler) icat edildi. L1 cache, CPU çekirdeğinin içindedir ve register’lardan sonraki en hızlı bellektir.

SRAM vs DRAM

SRAM, her biti için 6 transistör kullanır; bu yüzden hızlı ama pahalıdır. Elektrik kesilse bile veriyi tutar (static = statik). DRAM ise her biti için 1 transistör + 1 kapasitör kullanır; daha ucuz ama kapasitör sürekli tazelenmelidir (dynamic = dinamik). Bu yüzden DRAM daha yavaştır. RAM dediğimiz şey aslında DRAM’dir.

İkinci Kademe: L2 Cache

L2 cache, L1’den biraz daha yavaş ama daha büyüktür. Eskiden anakart üzerindeyken günümüzde CPU çipinin içine alınmıştır.

Üçüncü Kademe: L3 Cache

L3 cache, tüm çekirdekler arasında paylaşılan daha büyük bir önbellektir.

Ana Bellek: RAM (DRAM)

RAM, çalışan programların verilerinin ve kodunun tutulduğu yerdir. DRAM teknolojisi kullanır.

DDR nedir? Double Data Rate; her saat çevriminde iki kez veri aktarımı yapar. DDR5, DDR4’e göre daha yüksek bant genişliği sunar.

RAM’in fiziksel yapısı: Bellek modülleri (DIMM’ler), üzerinde bellek çipleri bulunan kartlardır. Anakart üzerindeki bellek denetleyicisi (memory controller), CPU ile RAM arasındaki trafiği yönetir. Modern işlemcilerde bellek denetleyicisi CPU çipinin içindedir.

En Alt Kademe: Disk / SSD

Disk ve SSD, programların kapalıyken saklandığı kalıcı depolardır.

SSD, HDD’ye göre 10-100 kat daha hızlıdır ama yine de RAM’e göre 1000 kat yavaştır. Bu yüzden çalışan programlar diskten değil, RAM’den okunur.

Hız ve Boyut Karşılaştırması

KatmanTipik GecikmeTipik BoyutTeknoloji
Register~0.5 ns~1 KiB toplamCPU transistörü
L1 Cache~1-5 ns32-128 KiBSRAM
L2 Cache~5-15 ns256 KiB - 1 MiBSRAM
L3 Cache~15-40 ns8-128 MiBSRAM
RAM~80-120 ns8-128 GiBDRAM
SSD~10-100 µs256 GiB - 8 TiBNAND Flash
HDD~1-10 ms1-20 TiBManyetik

Fark dikkat çekici: Register ile HDD arasında milyonlarca kat hız farkı var.

Cache Line: Cache’in Çalışma Birimi

Cache’ler tek tek byte’ları değil, cache line denen bloklar hâlinde veri taşır. x86-64’te tipik cache line boyutu 64 byte‘tır.

Neden? Çünkü programlar genelde komşu verilere sırayla erişir. CPU bir veriyi istediğinde, cache o verinin komşusu olan 63 byte’ı da getirir. Böylece bir sonraki erişim büyük ihtimalle cache’de bulunur.

Locality: Hızın Sırrı

Cache’lerin işe yaramasının nedeni iki locality prensibidir:

  1. Temporal Locality (Zamansal Yakınlık): Az önce kullandığın bir veriyi yakında tekrar kullanma ihtimalin yüksektir. Örneğin bir döngüdeki sayaç değişkeni.
  2. Spatial Locality (Mekânsal Yakınlık): Kullandığın verinin komşusuna da yakında erişme ihtimalin yüksektir. Örneğin bir dizinin elemanlarını sırayla okumak.

İyi yazılmış programlar bu prensipleri kullanarak cache isabet oranını (cache hit rate) yükseltir. Kötü yazılmış kodlar cache’i verimsiz kullanarak performansı düşürebilir.

Cache-Friendly ve Cache-Unfriendly Kod

Locality prensibi pratikte nasıl işler? Aşağıdaki iki C kodu aynı matrisi toplar, ama biri cache’i dostane kullanırken diğeri düşmandır.

Cache-friendly örnek (satır bazlı erişim):

for (int i = 0; i < N; i++)
  for (int j = 0; j < N; j++)
    sum += matrix[i][j];  // Sequential access = cache hit

Cache-unfriendly örnek (sütun bazlı erişim):

for (int j = 0; j < N; j++)
  for (int i = 0; i < N; i++)
    sum += matrix[i][j];  // Strided access = cache miss

Neden satır bazlı (row-major) daha hızlı? C dilinde çok boyutlu diziler satır bazlı saklanır. matrix[i][j] erişimi komşu bellek adreslerine sırayla erişir; bu spatial locality sağlar. Bir cache line (64 byte) içinde ardışık veriler gelir ve CPU bir sonraki erişimde cache’de bulur. Sütun bazlı erişimde ise her erişim farklı bir satıra atlar; bu stride büyük olduğu için her seferinde yeni cache line getirilir ve cache miss oluşur.

Bellek Kanalları ve Bant Genişliği

CPU ile RAM arasında veri, bellek kanalları (memory channels) üzerinden taşınır. Çift kanallı (dual-channel) bellek, iki kanalı paralel kullanarak teorik bant genişliğini iki katına çıkarır.

Bant genişliği, birim zamanda taşınabilen veri miktarıdır. DDR5-5600 bellek, kanal başına ~45 GB/s bant genişliği sunabilir.

TLB: Adres Çevirisinin Hızlı Sözlüğü

CPU sanal adresleri fiziksel adreslere çevirirken sayfa tablolarını (page tables) tarar. Bu tarama çok yavaştır. TLB (Translation Lookaside Buffer), en son kullanılan sanal → fiziksel adres eşleştirmelerini önbellekleyen özel bir donanım önbelleğidir. L1 cache kadar hızlıdır ve birkaç yüz giriş tutar.

Linux çekirdeği, sayfa tabloları değiştiğinde TLB’nin tutarsız hale gelmemesi için explicit TLB flush yapar:

arch/x86/include/asm/tlbflush.h
// From arch/x86/include/asm/tlbflush.h
// TLB flush after page table changes
void flush_tlb_mm_range(struct mm_struct *mm, ...);

Bir yana: Neden Cache Line 64 Byte?

Cache line boyutu tarihsel olarak evrimleşmiştir. Pentium 4 döneminde 32 byte kullanılırken, modern x86-64 işlemcilerde standart 64 byte’tır. Bazı ARM tasarımlarında ise 128 byte denenmektedir.

Daha büyük cache line = daha fazla spatial locality avantajı (komşu veriler tek seferde gelir). Ancak yanlış tahmin durumunda (cache miss) 128 byte yerine 64 byte’lık gereksiz veri getirilmiş olur; bu bant genişliği israfıdır. 64 byte, bu denge için endüstride kabul görmüş bir sweet spot’tur.

Kendi Sisteminde Cache’leri Keşfet

Linux sisteminde cache yapılandırmanı komut satırından öğrenebilirsin:

Cache line boyutu:

getconf LEVEL1_DCACHE_LINESIZE

Tüm cache hiyerarşisi:

lscpu | grep -i cache

Beklenen çıktıya örnek:

L1d cache:                       384 KiB (8 instances)
L1i cache:                       256 KiB (8 instances)
L2 cache:                        4 MiB (8 instances)
L3 cache:                        32 MiB (2 instances)

Tek satırda cache bilgisi:

cat /proc/cpuinfo | grep -m1 cache

Özet

Artık CPU’nun talimatları nasıl yürüttüğünü, register’ların ne kadar hızlı olduğunu ve neden RAM’e ihtiyaç duyduğunu daha iyi biliyoruz. Bellek hiyerarşisinin farkında olarak cache-friendly kod yazabilir ve sisteminin cache yapılandırmasını inceleyebilirsin. Bir sonraki bölümde, işletim sisteminin birden fazla programı nasıl aynı anda çalıştırdığını göreceğiz.

4. bölüme devam et: Zamanı Dilimle