Ana içeriğe geç

Bölüm 5:Bellek Hiyerarşisi

10 dakikalık okumaGüncelleme:

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 arasındaki farkın nereden geldiğini göreceğiz.
  • “Hızlı bellek neden büyük olamıyor?” sorusunu cevaplayacağız.

Üç Soru: Ne Kadar, Ne Kadar Hızlı, Ne Kadar Pahalı?

Bir bilgisayarın belleğini tasarlarken cevaplaman gereken üç soru vardır ve üçünü aynı anda memnun etmek mümkün değildir:

Aralarındaki ilişki inatçı ve neredeyse yasa gibidir:

Son maddeyi atlamak kolay ama en önemlisi o. Büyük bellek yalnızca pahalı olduğu için değil, fiziksel olarak da yavaştır: kapasite arttıkça adres çözme devresi büyür, sinyalin kat etmesi gereken mesafe uzar. Bir cache’i iki katına çıkarmak, içinde arama yapmayı da yavaşlatır.

Yani “hem çok büyük hem çok hızlı bir bellek yapalım” diye bir seçenek yok. Tasarımcının önünde iki kötü seçenek var: az ve hızlı, ya da çok ve yavaş.

Çözüm ikisinden birini seçmek değil, ikisini birden kullanmak oldu. Küçük ve hızlı belleği CPU’nun yanına, büyük ve yavaş belleği uzağa koy; sık kullanılanı yukarıda tut. Ortaya çıkan katmanlı yapıya bellek hiyerarşisi denir ve bu bölümün konusu o.

Peki Bu Neden İşe Yarıyor?

Buradaki numarayı bir kere görünce her şey yerine oturuyor, o yüzden sayılarla gösterelim.

Diyelim ki hızlı katman 1 nanosaniyede, yavaş katman 100 nanosaniyede cevap veriyor. İstenen verinin hızlı katmanda bulunma oranına hit oranı diyelim. Ortalama erişim süresi şu basit hesapla çıkar:

ortalama = hit oranı × hızlı süre + (1 − hit oranı) × yavaş süre

Hit oranı %50 ise ortalama 50,5 ns. Hâlâ kötü. Ama gerçek programlarda bu oran %50 değil; %95’in üzerinde. %95 ile hesap 5,95 ns’ye iner — yani yalnızca küçük ve pahalı katmanı ekleyerek, tamamı yavaş bellekten oluşan bir sistemi on yedi kat hızlandırmış olursun.

Hiyerarşinin bütün varlık sebebi o hit oranıdır. Peki neden bu kadar yüksek çıkıyor? Cevabın adı locality: programlar belleğe rastgele dağılmış biçimde erişmez, kümeler hâlinde erişir. Bir sonraki bölümde bunu ayrıntısıyla açacağız; şimdilik hiyerarşinin ayakta durmasını sağlayan tek varsayımın bu olduğunu bilmek yeterli.

Bu hesabın ters yönü de öğretici. Hit oranı %95’ten %90’a düştüğünde ortalama süre 5,95 ns’den 10,9 ns’ye, yani neredeyse iki katına çıkar. Kaçırılan her yüzde puanı orantısız biçimde pahalıya patlar; performans yazılarında cache miss oranının bu kadar takıntılı biçimde konuşulmasının sebebi budur.

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. Register erişimi çoğu modern işlemcide bir veya birkaç saat çevrimi mertebesindedir; yani aşağıdaki sayıları kesin ölçüm değil, katmanlar arasındaki büyüklük farkını göstermek için tipik mertebeler olarak oku.

Birinci Kademe: L1 Cache

Register’lar tek başına yetmez. Bir düşün: elinin altında toplam birkaç yüz baytlık bir çalışma alanı var, işlediğin veri ise gigabaytlarca. Eksik olan her şeyi RAM’den istemen gerekiyor — ve RAM’den bir değer gelene kadar CPU yüzlerce saat çevrimi boyunca boş oturuyor.

İşte bu bekleyişi kısaltmak için CPU ile RAM’in arasına küçük ama çok hızlı bir ara depo koyuyoruz: cache (önbellek). L1 cache bu ara depoların CPU’ya en yakın olanı; çekirdeğin tam içinde durur ve register’lardan sonraki en hızlı bellektir.

SRAM vs DRAM

SRAM, tipik hücrelerde her bit için birden fazla transistör kullanır; bu yüzden hızlı ama pahalıdır. “Static” demek elektriksiz kalınca veriyi tutar demek değildir; sadece DRAM gibi sürekli refresh gerektirmediği anlamına gelir. SRAM de uçucudur (volatile): güç kesilirse veri gider. DRAM ise her biti transistör + kapasitör hücresiyle temsil eder; daha ucuz ve yoğundur ama kapasitörler düzenli tazelenmelidir. Bu yüzden ana RAM dediğimiz şey çoğunlukla DRAM’dir.

İkinci Kademe: L2 Cache

Akla ilk gelen çözüm L1’i büyütmek. Ama bu işe yaramaz: bir cache ne kadar büyürse içinde arama yapmak da o kadar uzun sürer, yani L1’i büyütmek onu yavaşlatır. L1’in küçük kalması bir eksiklik değil, bilinçli bir tercihtir.

Bu yüzden büyütmek yerine altına ikinci bir katman koyuyoruz. L2, L1’de bulunamayan veriye bakılan ilk yerdir: L1’den birkaç kat büyük, karşılığında birkaç kat yavaş. Eskiden ayrı bir çip olarak anakarta oturuyordu; bugün çekirdeğin hemen yanında, aynı silikonun üzerinde duruyor.

Üçüncü Kademe: L3 Cache

L3’ün diğer ikisinden yapısal bir farkı var. L1 ve L2 her çekirdeğin kendi malıdır; komşu çekirdek onlara bakamaz. L3 ise ortak alandır — sekiz çekirdek de aynı L3’e bakar.

Bu ortaklık iki yönlü çalışır. Faydası şu: bir çekirdeğin RAM’den çekip getirdiği veriyi diğeri hazır bulur, aynı uzun yolu ikinci kez yürümez. Bedeli ise bu bölümün sonunda ayrıntısıyla konuşacağımız mesele: aynı verinin birden fazla kopyası ortalıkta dolaşmaya başlayınca, hangisinin doğru olduğuna birinin karar vermesi gerekir.

Ana Bellek: RAM (DRAM)

Cache’ler bitince sıra RAM’e gelir. Üç katmanın hiçbirinde bulunamayan her veri buradan istenir; yani RAM hiyerarşinin asıl belleği, cache’ler ise onun önüne çekilmiş perdelerdir.

Buraya kadar anlattığım her şeyi tek cümlede toplayabilirim: o katmanların tamamı, RAM’e gitmek zorunda kalmamak için verilmiş bir mücadeledir. Çünkü RAM’e gitmek CPU ölçeğinde uzun bir yolculuktur — L1’den yüz kat, register’dan iki yüz kat uzak.

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.

Fiziksel tarafına bakalım. Bellek modülleri (DIMM’ler), üzerinde DRAM çipleri bulunan ve anakarttaki yuvalara takılan kartlardır. CPU ile bu çipler arasındaki trafiği bellek denetleyicisi (memory controller) yönetir: hangi satırın açılacağına, tazelemenin ne zaman yapılacağına ve biriken isteklerin hangi sırayla karşılanacağına o karar verir. Eskiden bu denetleyici anakart üzerinde ayrı bir çipte otururdu — kuzey köprüsü (northbridge) denen parçada. Modern işlemcilerde ise CPU’nun kendi silikonuna taşındı ve bu taşıma, yolun bir durağını tamamen ortadan kaldırdığı için RAM gecikmesini gözle görülür biçimde düşürdü.

DerinleşmeAynı makinede bellek de uzak olabilir: NUMA

Şimdiye kadar RAM’i tek bir havuz gibi anlattım: CPU bir adres ister, bellek denetleyicisi getirir. Tek soketli bir masaüstünde bu doğru.

Sunucularda ise resim değişiyor. Bir anakartta iki, dört ya da daha fazla fiziksel işlemci olabilir ve her birinin kendi bellek denetleyicisi, kendi RAM yuvaları vardır. İşlemciler birbirine hızlı bir bağlantıyla (Intel’de UPI, AMD’de Infinity Fabric) bağlanır.

Sonuç şu: bir çekirdek, kendi soketine takılı RAM’e doğrudan erişir; başka bir sokete takılı RAM’e ise komşu işlemcinin üzerinden gider. İkisi de “RAM” ama gecikmeleri farklıdır — uzak erişim tipik olarak %50 ile iki kat arası daha yavaştır. Bu düzene NUMA denir (Non-Uniform Memory Access): erişim süresi tek tip değildir.

Pratikte bunun iki görünen sonucu var:

  • İşletim sistemi bunu bilmek zorundadır. Linux bellek ayırırken, isteyen process’in çalıştığı sokete yakın olan bölgeden vermeye çalışır. Scheduler da bir görevi başka bir sokete taşımakta isteksizdir; taşırsa görevin bütün belleği bir anda “uzak” hâle gelir.
  • Ölçüm yaparken tuzak kurar. Aynı programın aynı makinede iki kez farklı hızda koşması, çoğu zaman ikinci koşuda başka bir sokete düşmüş olmasındandır. numactl gibi araçlar bu yüzden var: hangi soketin belleğini ve hangi çekirdekleri kullanacağını açıkça söylemene yarar.

Buradaki genel ders bu bölümün özetiyle aynı: bellekte mesafe, gecikmeye dönüşür. Piramidin katmanları arasında da böyleydi, aynı katmanın içinde de böyle.

En Alt Kademe: Disk / SSD

Piramidin tabanında disk var ve buradaki fark artık yalnızca hız değil.

Yukarıdaki bütün katmanlar — register, cache, RAM — uçucudur: elektrik kesildiği anda içindekiler kaybolur. Disk ve SSD ise kalıcıdır; bilgisayarı kapatıp bir yıl sonra açsan da yazdığın şey yerinde durur. Bir programın “bilgisayarında yüklü olması” tam olarak bu demek: dosyaları diskte, program çalışmıyorken de orada duruyor. Çalıştırdığında bu dosyalar diskten silinmez, ihtiyaç duyulan parçaları RAM’e kopyalanı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.

SSD’nin neden hâlâ mikrosaniye mertebesinde kaldığını merak ediyorsan, sebebi hareketli parça değil: NAND flash’ın kendisi. Bir SSD veriyi sayfa birimiyle okur ve yazar (tipik olarak birkaç kilobayt), ama silmeyi sayfa sayfa yapamaz — silme yalnızca çok daha büyük bloklar hâlinde mümkündür.

Bunun tuhaf bir sonucu var: var olan bir veriyi değiştirmek istediğinde denetleyici onu yerinde güncelleyemez. Yeni hâlini boş bir sayfaya yazar, eskisini “geçersiz” diye işaretler ve o bloğu ileride, uygun bir zamanda topluca siler. Bu arka plan temizliğine çöp toplama denir ve diskin dolu olduğu durumlarda yazma hızının neden düştüğünü açıklar: temizlenecek boş blok kalmamıştır.

Bir de her flash hücresinin sınırlı sayıda silme çevrimine dayandığını ekle. Denetleyici bu yüzden yazmaları bütün hücrelere eşit dağıtmaya çalışır; buna wear leveling denir. Yani bir SSD’nin içinde, işletim sisteminden tamamen bağımsız çalışan küçük bir yönetim yazılımı var ve senin gördüğün adreslerle çipteki gerçek konumlar arasındaki eşlemeyi o tutuyor. Tanıdık geldi mi? 14. bölümde göreceğimiz sayfa tablolarının aynı fikri, bir kat aşağıda.

Neden Aradaki Fark Bu Kadar Açıldı?

Bir de tarihsel tarafı var, çünkü bu piramit hep bu kadar dik değildi.

1980’lerde bir işlemci RAM’den veri istediğinde birkaç saat çevrimi beklerdi; aradaki fark önemsizdi ve cache diye bir katmana çoğu makinede gerek bile duyulmuyordu. Sonraki yirmi yılda işlemci hızları yılda yaklaşık %50 arttı, DRAM gecikmesi ise yılda ancak %7 iyileşti. İki eğri arasındaki makas her yıl biraz daha açıldı.

Bugün geldiğimiz nokta şu: RAM’den bir değer beklerken işlemci yüzlerce talimat çalıştırabilecek zamanı boşa harcıyor. Bu soruna literatürde bellek duvarı (memory wall) deniyor.

Dikkat edilecek ayrıntı şu: DRAM’in bant genişliği bu süre boyunca çok arttı — bir DDR5 modülü saniyede on gigabaytlarca veri taşıyabiliyor. Artmayan şey gecikme oldu. Yani boruyu genişletmeyi başardık, ama borunun bir ucundan diğerine gitmenin süresini kısaltamadık. Bu ayrım pratikte şu anlama geliyor: veriyi sırayla ve büyük parçalar hâlinde okuyan bir program hızlıdır, rastgele adreslere tek tek dokunan bir program ise duvara toslar.

Bu bölümdeki bütün katmanlar ve bir sonraki bölümdeki bütün hileler, o duvarı aşmak için değil, etrafından dolaşmak için var.

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

KatmanTipik Gecikme / MertebeTipik 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.

Özet

Peki, ne öğrendik?

  • Bellek tek bir katman değil; hız ile maliyet arasında denge kuran bir piramittir.
  • Tepede register’lar var: bir saat çevrimi mertebesinde erişim, toplamda birkaç yüz bayt.
  • L1, L2 ve L3 cache’ler SRAM ile yapılır. Hızlıdır ama bir bit için altı transistör harcadıkları için pahalı ve küçüktürler.
  • RAM DRAM ile yapılır. Bir bit için bir transistör ve bir kondansatör yeter; bu yüzden ucuz ve büyüktür, ama sürekli tazelenmesi gerekir.
  • Disk ve SSD kalıcıdır, buna karşılık RAM’e göre yüz binlerce kat yavaştır.
  • Her iniş, gecikmeyi kabaca bir mertebe artırır. Bir programın hızı çoğu zaman bu piramitte nerede çalıştığıyla belirlenir.

Piramidi tanıdık. Şimdi asıl soruya geçelim: CPU istediği veriyi cache’te nasıl buluyor, o veri oraya en baştan neden gelmişti ve yerini kime bırakıyor?

6. bölüme devam et: Cache Nasıl Çalışır