Önbellek tutarlılığı
Önbellek tutarlılığı (İngilizcesi: cache coherence), aynı bellek konumunun birden çok önbellekte tutulan kopyalarının birbiriyle uyumlu kalmasını sağlayan donanım düzeneğidir. Ortak bir adres uzayını paylaşan çok çekirdekli ve çok işlemcili sistemlerde her çekirdek kendi önbelleğine yazdığı için, aynı adresin farklı çekirdeklerde farklı değerleri bulunabilir; tutarlılık düzeneği bu kopyaları izleyerek bütün çekirdeklerin belleğe ilişkin aynı görünümü paylaşmasını sağlar.[1]
Sorun önbelleğin varlığından doğar. Önbellek tek çekirdekli bir sistemde yazılıma görünmeyen bir başarım düzeneğidir; çekirdek sayısı birden çok olduğunda ise aynı düzenek, paylaşılan verinin birbirinden habersiz kopyalarını üretir. Tutarlılık protokolü bu kopyaları donanımda izleyip gerektiğinde geçersiz kılarak, paylaşımlı bellek soyutlamasını programcı için ayakta tutar. Protokolün yaptığı iş yazılıma görünmez, ancak ürettiği veri aktarımı ve gecikme çok çekirdekli başarımın belirleyicilerinden biridir.[2]
Önbellek tutarlılığı, bellek erişim sıralaması (memory consistency) ile karıştırılmamalıdır. Tutarlılık tek bir adresle ilgilenir ve o adrese yapılan bir okumanın hangi değeri döndürebileceğini belirler; erişim sıralaması ise ayrı adreslere yapılan işlemlerin birbirine göre hangi sırada görüneceğini belirler. Biri değer, öteki sıra sorusudur.[2]
Sorun
[değiştir | kaynağı değiştir]
Paylaşılan bir x değişkeninin başlangıç değerinin 0 olduğu iki çekirdekli bir sistem ele alınsın. Her iki çekirdek de x'i okur ve kendi önbelleğine bir kopyasını alır. Ardından birinci çekirdek x'e 1 yazar; yazma kendi önbelleğinde kaldığı sürece ikinci çekirdeğin önbelleğindeki kopya 0 olarak kalır. İkinci çekirdek x'i yeniden okuduğunda önbelleğinde bir kopya bulduğu için ana belleğe hiç gitmez ve eskimiş değeri kullanır.[1]
Sorunun kaynağı, önbelleğin yazılıma görünmeyecek biçimde tasarlanmış olmasıdır. Çekirdek bir okumanın önbellekten mi ana bellekten mi karşılandığını bilmez ve bilmek zorunda da değildir; bu saydamlık tek çekirdekte doğru sonucu verirken, kopyalar çoğaldığında kendiliğinden bozulur. Sorunu yazılıma bırakmak, paylaşılan her veri için programcının açıkça geçersiz kılma ve geri yazma yapmasını gerektirirdi; bu yüzden genel amaçlı sistemlerde tutarlılık donanımda ele alınır.[3]
Aynı sorun, yazma ilkesi doğrudan yazma olduğunda da ortadan kalkmaz. Doğrudan yazmada değer ana belleğe hemen işlenir, ancak öteki çekirdeklerin önbelleklerindeki eski kopyalar yerinde durmayı sürdürür; onların da geçersiz kılınması gerekir. Geri yazmada ise değişiklik uzun süre tek bir önbellekte kalabildiği için sorun daha da belirginleşir.[4]
Tutarlılığın koşulları
[değiştir | kaynağı değiştir]Bir bellek düzeninin tutarlı sayılması için iki özelliği sağlaması gerekir.[1]
Yazma yayılımı (write propagation), bir çekirdeğin yaptığı yazmanın sonunda öteki çekirdeklerce de görülebilir duruma gelmesidir. Bir yazmanın yalnızca yazan çekirdeğin önbelleğinde kalması ve orada süresiz durması tutarlılığı bozar.
Yazma serileştirmesi (write serialization), aynı adrese yapılan yazmaların bütün çekirdeklerce aynı sırada görülmesidir. İki çekirdek x'e sırasıyla 1 ve 2 yazarsa, hiçbir çekirdek önce 2'yi sonra 1'i görmemelidir. Bu koşul olmadan çekirdekler aynı adresin geçmişi konusunda birbiriyle çelişen bir görünüme sahip olur.
Bu iki koşul birlikte, her bellek adresinin bütün çekirdekler için tek bir değer dizisi taşıyormuş gibi davranmasını sağlar. Koşullar yalnızca tek bir adres için tanımlıdır; ayrı adreslere yapılan işlemlerin göreli sırası konusunda hiçbir şey söylemezler.[2]
Erişim sıralamasından farkı
[değiştir | kaynağı değiştir]İki kavram sık karıştırılır, çünkü İngilizcedeki coherence ve consistency sözcükleri de birbirine yakındır. Ayrımı gösteren tipik örnek şudur: bir çekirdek veri değişkenine yazıp ardından bayrak değişkenini 1 yapar; öteki çekirdek bayrak'ın 1 olmasını bekleyip veri'yi okur. Tutarlılık her iki adres için de en güncel değerin sonunda görüleceğini güvence altına alır, ancak bayrak'ın veri'den önce görünür olmayacağını güvence altına almaz. Bunu belirleyen şey erişim sıralama modelidir; gevşek modellerde programcının araya bir bellek engeli koyması gerekir.[2]
Tutarlılık bu anlamda erişim sıralamasının altında duran bir yapı taşıdır. Erişim sıralama modelleri tutarlılığı varsayar ve onun üzerine kurulur; tutarlılık ise tek başına bir programlama modeli oluşturmaz.[3]
Protokoller
[değiştir | kaynağı değiştir]Tutarlılık, önbellek satırlarına durum bilgisi ekleyen ve çekirdekler arasında ileti alışverişi yapan bir protokolle sağlanır. Protokoller iki eksende sınıflandırılır: bir yazmanın öteki kopyalara ne yaptığı ve kopyaların nerede izlendiği.[2]
Geçersizleştirme ve güncelleme
[değiştir | kaynağı değiştir]Yazma geçersizleştirme (write-invalidate) yaklaşımında, bir çekirdek yazmadan önce öteki bütün kopyaları geçersiz kılar ve satırın tek sahibi durumuna geçer. Sonraki yazmaları için başka ileti göndermesi gerekmez. Bir başka çekirdek o satırı yeniden isterse yeni bir aktarım başlar.
Yazma güncelleme (write-update) yaklaşımında ise yazılan değer kopyası bulunan bütün önbelleklere yayılır ve kopyalar yerinde kalır. Bu yaklaşım paylaşılan veriyi okuyan çekirdeklerin bekleme süresini kısaltır, ancak her yazma için veri aktarımı gerektirir; art arda yazılıp yalnızca sonunda okunan verilerde harcanan bant genişliği büyüktür.
Çağdaş sistemlerin neredeyse tamamı geçersizleştirmeyi kullanır. Bunun nedeni tipik paylaşım deseninin bir çekirdeğin bir veriyi bir süre kendine ayırıp üzerinde çalışması, sonra bırakması biçiminde olmasıdır; bu desende güncelleme yaklaşımı gereksiz aktarım üretir.[1]
Gözetleme tabanlı protokoller
[değiştir | kaynağı değiştir]
Gözetleme tabanlı (snooping) protokollerde bütün önbellekler ortak bir yayın ortamını, çoğunlukla paylaşılan bir yolu dinler. Bir çekirdek bir satırı isteyince isteğini bu ortama koyar; her önbellek isteği görür, kendi etiketlerine bakar ve o satırın kopyasına sahipse gereken tepkiyi verir. Sıralamayı yayın ortamının kendisi sağlar: yola çıkan istekler bütün önbelleklerce aynı sırada görüldüğü için yazma serileştirmesi kendiliğinden gerçekleşir.[4]
Yaklaşımın üstünlüğü basitliği ve düşük gecikmesidir; ayrı bir dizin yapısı tutulmadığından depolama maliyeti yoktur. Sınırı ise yayın ortamının kendisidir. Her istek bütün önbelleklere ulaştığından, çekirdek sayısı arttıkça hem ortamın bant genişliği hem de her önbelleğin etiket arama yükü doğrusal büyür. Bu yüzden gözetleme küçük ve orta ölçekli sistemlerde kullanılır.[2]
Dizin tabanlı protokoller
[değiştir | kaynağı değiştir]Dizin tabanlı protokollerde her bellek bloğu için, o bloğun hangi önbelleklerde bulunduğunu ve hangi durumda olduğunu tutan bir kayıt saklanır. Yazmak isteyen çekirdek isteğini dizine gönderir; dizin yalnızca kopyayı taşıyan önbelleklere geçersizleştirme iletisi yollar ve onların yanıtını bekler. Yayın olmadığından ileti sayısı çekirdek sayısıyla değil, o bloğu gerçekten paylaşan çekirdek sayısıyla orantılıdır.[5]
Bedeli dizinin kendi depolama maliyetidir. En yalın biçimde her blok için sistemdeki her çekirdeğe bir bit ayrılır; bu düzenin maliyeti çekirdek sayısıyla doğrusal, bellek boyutuyla da doğrusal büyür. Maliyeti düşürmek için sınırlı sayıda gösterge tutan, paylaşan kümesini yaklaşık olarak kodlayan ya da dizini yalnızca önbellekte bulunan bloklar için saklayan seyrek düzenler geliştirilmiştir. Yaklaşık kodlamalarda dizin kopyası olmayan önbelleklere de ileti gönderebilir; bu doğruluğu bozmaz, yalnızca gereksiz aktarım üretir.[2]
Çekirdek sayısı arttıkça dizin tabanlı düzen kaçınılmaz olur. Çok çekirdekli yongalarda iki yaklaşım sıkça birleştirilir: bir yonga içindeki çekirdek öbeği kendi arasında gözetlemeyle, öbekler ve yongalar arası ise dizinle tutarlı tutulur.[3]
Durum makineleri
[değiştir | kaynağı değiştir]
Protokoller her önbellek satırına bir durum atar ve gelen isteklere göre bu durumu değiştirir. Durum kümesi büyüdükçe protokol karmaşıklaşır, buna karşılık gereksiz aktarım azalır.[2]
En yalın kullanışlı küme MSIdir: satır ya Değiştirilmiş (Modified), ya Paylaşılan (Shared) ya da Geçersiz (Invalid) olur. Bu kümenin eksiği, tek başına okunan bir satırın yazılmak istendiğinde yeniden ileti gerektirmesidir; satır başka hiçbir önbellekte olmasa bile protokol bunu bilmez.
MESI bu eksiği Dışlayan (Exclusive) durumuyla kapatır. Bir satır yalnızca tek bir önbellekte bulunuyor ve değiştirilmemişse Dışlayan durumdadır; o çekirdek satıra yazmak istediğinde hiçbir ileti göndermeden Değiştirilmiş duruma geçebilir. Tek iş parçacıklı kodun paylaşılmayan verisi bu durumda kaldığından kazanç büyüktür. Protokol 1984'te Illinois Üniversitesi'nde geliştirildiği için Illinois protokolü olarak da anılır.[6]
MOESI, Sahiplenilmiş (Owned) durumunu ekler. Değiştirilmiş bir satır başka bir çekirdekçe istendiğinde MESI'de ana belleğe geri yazılması gerekir; MOESI'de satırı elinde tutan çekirdek sahiplik alarak veriyi doğrudan isteyene verir ve geri yazmayı erteler. Bu, çekirdekler arası paylaşımın yoğun olduğu iş yüklerinde bellek trafiğini azaltır. Durum sınıflandırması 1986'da Sweazey ve Smith tarafından derli toplu bir çerçeveye oturtulmuştur.[7]
MESIF, İletici (Forward) durumunu ekler. Bir satırın paylaşılan kopyaları birden çok önbellekte bulunduğunda, isteğe hangisinin yanıt vereceği belirsizdir ve hepsi birden yanıt verirse gereksiz aktarım olur. İletici durumu bu kopyalardan tam olarak birini yanıt vermekle görevlendirir.
| Durum | Geçerli mi? | Bellekle aynı mı? | Başka önbellekte var mı? | Bulunduğu kümeler |
|---|---|---|---|---|
| Değiştirilmiş (M) | evet | hayır | hayır | MSI, MESI, MOESI, MESIF |
| Sahiplenilmiş (O) | evet | hayır | olabilir | MOESI |
| Dışlayan (E) | evet | evet | hayır | MESI, MOESI, MESIF |
| Paylaşılan (S) | evet | evet (ya da sahibi var) | olabilir | hepsi |
| İletici (F) | evet | evet | olabilir | MESIF |
| Geçersiz (I) | hayır | hepsi |
Başarıma etkisi
[değiştir | kaynağı değiştir]Tutarlılık protokolü, tek çekirdekli bir sistemde bulunmayan yeni bir bulamama türü üretir. Tutarlılık bulamaması (coherence miss), satır önbellekte yer bulamadığı için değil, protokol onu geçersiz kıldığı için oluşur. Bu tür bulamamalar üç C modelinin dışında kaldığından sınıflandırmaya dördüncü bir C olarak eklenir.[1]
Tutarlılık bulamamaları iki kaynaktan doğar. Gerçek paylaşımda çekirdekler aynı veriyi kullanır ve aktarım gerçekten gereklidir. Yanlış paylaşımda (false sharing) ise çekirdekler ayrı değişkenlere erişir, ancak bu değişkenler aynı önbellek satırına düştüğü için protokol onları tek bir birim gibi görür. 64 baytlık bir satırın başındaki sayaca bir çekirdek, ortasındaki başka bir sayaca ikinci çekirdek yazarsa, satır iki önbellek arasında sürekli gidip gelir; program mantığında hiçbir paylaşım olmadığı hâlde her yazma bir aktarım doğurur.[8]

Yanlış paylaşım yazılım tarafında önlenebilir. İş parçacığı başına düşen değişkenleri önbellek satırı sınırına hizalamak, sık yazılan sayaçları ayrı satırlara dağıtmak ve paylaşılan bir yapıda okunan alanlarla yazılan alanları ayırmak yaygın çözümlerdir. Bu düzenlemelerin bedeli bellek kullanımının artmasıdır.[2]
Satır boyu bu dengede iki yönlü çalışır. Büyük satır alanda yerellikten daha çok yararlanır ve tek çekirdekli başarımı artırır; buna karşılık yanlış paylaşım olasılığını da büyütür. Çok çekirdekli sistemlerde satır boyunun 64 baytta yerleşmesinin gerekçelerinden biri budur.[1]
Ölçüm yaparken tutarlılık trafiğinin gecikmesi kadar dağılımı da önemlidir. Bir satırın iki çekirdek arasında art arda el değiştirmesi, her erişimin son düzeydeki önbellek ya da ana bellek gecikmesini ödemesine yol açar; kilitler ve paylaşılan sayaçlar gibi yapılar bu desene yatkındır. Kilit uygulamalarında döngüsel bekleyen iş parçacığının satırı sürekli istemesini önlemek için önce yalnızca okuma yapıp değer değiştiğinde yazmayı deneyen biçimler kullanılır.[2]
Tarihçe
[değiştir | kaynağı değiştir]Sorun, birden çok işlemcinin özel önbelleklerle ortak belleğe bağlandığı ilk tasarımlarla birlikte ortaya çıktı. 1978'de Lucien Censier ve Paul Feautrier, her bellek bloğu için kopyaların yerini kaydeden bir dizin öneren ilk düzenli çözümü yayımladı.[5]
1983'te James Goodman, ortak bir yolu dinleyen önbelleklere dayanan ilk gözetleme protokolünü tanıttı. Yazma ilkesi olarak ilk yazmayı doğrudan, sonrakileri geri yazma biçiminde işleyen bu tasarım, hem tutarlılığı sağlıyor hem de yol trafiğini belirgin biçimde azaltıyordu.[9] Bir yıl sonra Papamarcos ve Patel, Dışlayan durumu ekleyerek bugün MESI diye anılan protokolü ortaya koydu.[6]
Sonraki yıllarda öneriler çoğaldı ve karşılaştırılmaları güçleşti. Archibald ve Baer'in 1986 tarihli çalışması o güne dek önerilmiş protokolleri ortak bir benzetim modeliyle karşılaştırarak alanın ölçüm temelini kurdu.[10] Aynı yıl Sweazey ve Smith, dağınık duran durum kümelerini tek bir çerçevede toplayarak MOESI sınıflandırmasını verdi.[7]
Gözetlemenin ölçeklenmediği anlaşıldıkça dizin tabanlı düzenlere dönüldü. Stanford Üniversitesi'nde geliştirilen DASH, dizin tabanlı tutarlılığı bellek erişiminin tekdüze olmadığı (tekdüze olmayan bellek erişimi) bir yapıda uygulayan ilk büyük ölçekli örnektir.[11] Aynı çizgiyi ticari bir ürüne taşıyan SGI Origin, tutarlı NUMA düzeninin yaygın örneği oldu.[12]
2000'li yıllarda çok çekirdekli yongaların yaygınlaşmasıyla tartışma yön değiştirdi. Çekirdek sayısı arttıkça donanım tutarlılığının bırakılıp yerini yazılımla yönetilen düzenlere bırakacağı ileri sürüldü. 2012'de Martin, Hill ve Sorin, dizin maliyetinin ve ileti sayısının uygun tasarımlarla çekirdek sayısına göre sınırlı tutulabileceğini göstererek bu savı çürüttü; yonga içi tutarlılık kalıcı oldu.[3]
Uygulamalar
[değiştir | kaynağı değiştir]Çağdaş genel amaçlı işlemcilerin tümü tutarlılığı donanımda sağlar, ancak seçtikleri durum kümesi ve ara bağlantı ayrışır. Intel işlemcileri MESIF kümesini ve yongalar arası bağlantıda noktadan noktaya bir ara bağlantıyı kullanır; AMD işlemcileri MOESI kümesini benimser ve yonga içi ile paket içi bağlantıyı ortak bir dokuda birleştirir. ARM tarafında tutarlılık, işlemci çekirdekleriyle hızlandırıcıları aynı ara bağlantı üzerinde tutarlı tutan AMBA ACE ve CHI arayüzleriyle tanımlanır.[2]
Tutarlılık alanı işlemciyle sınırlı kalmamıştır. Compute Express Link, işlemciye takılan hızlandırıcıların ve bellek genişletme birimlerinin işlemci önbellekleriyle tutarlı biçimde çalışabilmesi için ayrı bir tutarlılık katmanı tanımlar; böylece hızlandırıcı paylaşılan veriyi kopyalamadan kullanabilir.[13]
Grafik işlemcileri farklı bir denge kurar. Bu tasarımlarda çekirdek sayısı çok yüksek olduğu için bütün önbellekler arasında donanım tutarlılığı kurmak pahalıdır; onun yerine tutarlılık belirli eşitleme noktalarında ve sınırlı kapsamda sağlanır, geri kalan zamanda önbellekler bağımsız çalışır. Gömülü sistemlerde ve sinyal işlemcilerinde ise tutarlılık çoğu zaman hiç kurulmaz; paylaşılan veri yazılım tarafından açıkça geri yazılır ve geçersiz kılınır.[3]
Sınırlar
[değiştir | kaynağı değiştir]Tutarlılık protokolleri doğrulanması güç yapılardır. Durum sayısı arttıkça, geçiş sırasında ortaya çıkan geçici durumlar ve iletilerin farklı sıralarda varması sonucu oluşan durum bileşimleri hızla çoğalır; bu bileşimlerin hepsinde doğruluğun elle gösterilmesi olanaksızdır. Bu yüzden protokoller biçimsel doğrulama ve model denetimi yöntemleriyle sınanır.[2]
Ölçeklenme sınırı depolamadan çok trafikten gelir. Dizin maliyeti seyrek düzenlerle kabul edilebilir sınırlarda tutulabilirken, çok sayıda çekirdeğin aynı satırı paylaştığı durumlarda geçersizleştirme iletilerinin sayısı ve bunların yanıtlarının beklenmesi gecikmeyi belirler. Paylaşımın az olduğu iş yüklerinde bu maliyet ortaya çıkmaz; sık paylaşılan kilitler ve sayaçlar ise darboğaz oluşturur.[3]
Bir başka sınır, tutarlılığın yalnızca veri önbelleklerini kapsamasıdır. Adres çevirilerini tutan çeviri ara belleği donanım protokolünün dışında kaldığından, sayfa çizelgesi değiştiğinde öteki çekirdeklerin çevirileri yazılım eliyle geçersiz kılınır. İşletim sistemi çekirdeklerinin bu iş için kullandığı yordam, donanım tutarlılığının kapsamadığı bir alanın yazılımla doldurulmasının tipik örneğidir.[2]
Kaynakça
[değiştir | kaynağı değiştir]- 1 2 3 4 5 6 Hennessy, John L.; Patterson, David A. (2019). Computer Architecture: A Quantitative Approach (6 bas.). Morgan Kaufmann. ISBN 978-0128119051.
- 1 2 3 4 5 6 7 8 9 10 11 12 13 Nagarajan, Vijay; Sorin, Daniel J.; Hill, Mark D.; Wood, David A. (2020). A Primer on Memory Consistency and Cache Coherence (2 bas.). Morgan & Claypool. doi:10.1007/978-3-031-01764-3. ISBN 978-1681737096.
- 1 2 3 4 5 6 Martin, Milo M. K.; Hill, Mark D.; Sorin, Daniel J. (2012). "Why on-chip cache coherence is here to stay". Communications of the ACM. 55 (7). ss. 78-89. doi:10.1145/2209249.2209269.
- 1 2 Patterson, David A.; Hennessy, John L. (2021). Computer Organization and Design RISC-V Edition: The Hardware/Software Interface (2 bas.). Morgan Kaufmann. ISBN 978-0128203316.
- 1 2 Censier, Lucien M.; Feautrier, Paul (1978). "A new solution to coherence problems in multicache systems". IEEE Transactions on Computers. C-27 (12). ss. 1112-1118. doi:10.1109/TC.1978.1675013.
- 1 2 Papamarcos, Mark S.; Patel, Janak H. (1984). A low-overhead coherence solution for multiprocessors with private cache memories. 11th Annual International Symposium on Computer Architecture (ISCA). ss. 348-354. doi:10.1145/800015.808204.
- 1 2 Sweazey, Paul; Smith, Alan Jay (1986). A class of compatible cache consistency protocols and their support by the IEEE Futurebus. 13th Annual International Symposium on Computer Architecture (ISCA). ss. 414-423. doi:10.1145/17407.17404.
- ↑ Torrellas, Josep; Lam, Monica S.; Hennessy, John L. (1994). "False sharing and spatial locality in multiprocessor caches". IEEE Transactions on Computers. 43 (6). ss. 651-663. doi:10.1109/12.286299.
- ↑ Goodman, James R. (1983). Using cache memory to reduce processor-memory traffic. 10th Annual International Symposium on Computer Architecture (ISCA). ss. 124-131. doi:10.1145/800046.801647.
- ↑ Archibald, James; Baer, Jean-Loup (1986). "Cache coherence protocols: evaluation using a multiprocessor simulation model". ACM Transactions on Computer Systems. 4 (4). ss. 273-298. doi:10.1145/6513.6514.
- ↑ Lenoski, Daniel; Laudon, James; Gharachorloo, Kourosh; Gupta, Anoop; Hennessy, John L. (1990). The directory-based cache coherence protocol for the DASH multiprocessor. 17th Annual International Symposium on Computer Architecture (ISCA). ss. 148-159. doi:10.1145/325164.325132.
- ↑ Laudon, James; Lenoski, Daniel (1997). The SGI Origin: a ccNUMA highly scalable server. 24th Annual International Symposium on Computer Architecture (ISCA). ss. 241-251. doi:10.1145/264107.264206.
- ↑ "Compute Express Link Specification". CXL Consortium. 6 Ağustos 2026 tarihinde kaynağından arşivlendi. Erişim tarihi: 6 Eylül 2026.