Bellek hizalamanın amacı


197

Kuşkusuz anlamıyorum. Diyelim ki 1 bayt uzunluğunda bir hafıza kelimesi olan bir hafızanız var. Hizalanmamış adreslerde olduğu gibi, tek bir bellek erişiminde tek bir bellek erişiminde (yani 4'e bölünemez) neden 4 bayt uzunluğunda bir değişkene erişemiyorsunuz?


17
Ek Googling yaptıktan sonra sorunu gerçekten iyi açıklayan bu harika bağlantıyı buldum .
ark

Bunu öğrenmeye başlayan insanlar için bu küçük makaleye göz atın
darkgaze

3
@ark bağlantısı bozuk
John Jiang

2
@JohnJiang Yeni bağlantıyı burada bulduğumu düşünüyorum: developer.ibm.com/technologies/systems/articles/pa-dalign
ejohnso49

Yanıtlar:


63

Temeldeki birçok işlemcinin bir sınırlamasıdır. Genellikle tek bir etkin kelime getirme yerine 4 verimsiz tek bayt getirme ile çözülebilir, ancak birçok dil belirleyici onları yasadışı bırakmanın ve her şeyin hizalanmasını zorlamanın daha kolay olacağına karar verdi.

Bu bağlantıda OP'nin keşfettiği çok daha fazla bilgi var .


311

Modern bir işlemcideki bellek alt sistemi, belleğe, kelime boyutunun ayrıntı düzeyinde ve hizasında erişmesi ile sınırlıdır; bu birkaç nedenden ötürü böyledir.

hız

Modern işlemciler, verilerin alınması gereken çok sayıda önbellek düzeyine sahiptir; tek baytlık okumaların desteklenmesi, bellek alt sistemi çıktısını yürütme birimi çıktısına sıkıca bağlı hale getirir (cpu-bağlı olarak da bilinir); tüm bunlar, PIO modunun sabit sürücülerdeki aynı nedenlerden ötürü DMA tarafından nasıl aşıldığını anımsatıyor .

CPU her zaman kelime boyutunda (32 bit işlemcide 4 bayt) okur, bu nedenle hizalanmamış bir adres erişimi yaptığınızda - bunu destekleyen bir işlemcide - işlemci birden çok kelime okuyacaktır. CPU, istediğiniz adresin katlandığı her bellek sözcüğünü okuyacaktır. Bu, istenen verilere erişmek için gereken bellek işlemi sayısının 2 katına kadar yükselmesine neden olur.

Bu nedenle, dört bayttan iki baytı okumak çok daha yavaş olabilir. Örneğin, bellekte şöyle görünen bir yapınız olduğunu varsayalım:

struct mystruct {
    char c;  // one byte
    int i;   // four bytes
    short s; // two bytes
}

32 bit işlemcide büyük olasılıkla burada gösterildiği gibi hizalanacaktır:

Yapı Düzeni

İşlemci bu üyelerin her birini tek bir işlemde okuyabilir.

Diyelim ki yapının paketlenmiş bir versiyonuna sahipsiniz, belki de iletim verimliliği için paketlendiği ağdan; şöyle görünebilir:

Paket Yapısı

İlk baytı okumak aynı olacak.

İşlemciden 0x0005'ten 16 bit vermesini istediğinizde 0x0004'ten bir kelime okumalı ve 16 bitlik bir kayıt defterine yerleştirmek için 1 bayt sola kaydırmalısınız; bazı ekstra işler, ancak çoğu bunu bir döngüde halledebilir.

0x0001'den 32 bit istediğinde 2X amplifikasyon elde edersiniz. İşlemci, 0x0000'den sonuç yazmacına okuyacak ve 1 bayt sola kaydıracak, daha sonra 0x0004'ten geçici bir sicile tekrar okuyacak, 3 bayt sağa kaydıracak, daha sonra ORsonuç yazmacı ile olacaktır.

Aralık

Herhangi bir adres alanı için, mimari 2 LSB'nin her zaman 0 olduğunu varsayabilirse (örn. 32 bit makineler) 4 kat daha fazla belleğe erişebilir (kaydedilen 2 bit 4 farklı durumu temsil edebilir) veya aynı miktar bayrak gibi bir şey için 2 bit bellek. 2 LSB'yi bir adresten çıkarmak size 4 baytlık bir hizalama sağlar; 4 baytlık bir adım olarak da adlandırılır . Bir adres her artırıldığında, 0 biti değil de bit 2'yi etkili bir şekilde arttırır, yani son 2 bit her zaman olmaya devam edecektir 00.

Bu, sistemin fiziksel tasarımını bile etkileyebilir. Adres veri yolunun 2 daha az bite ihtiyacı varsa, CPU'da 2 daha az pin ve devre kartında 2 daha az iz olabilir.

Atomsallık

CPU, hizalanmış bir bellek sözcüğü üzerinde atomik olarak çalışabilir, yani başka hiçbir talimat bu işlemi kesintiye uğratamaz. Bu, birçok kilitsiz veri yapısının ve diğer eşzamanlılık paradigmalarının doğru çalışması için kritiktir .

Sonuç

Bir işlemcinin bellek sistemi burada tarif edilenden biraz daha karmaşıktır ve dahil edilmiştir; bir x86 işlemcinin gerçekte belleği nasıl ele aldığını tartışmak yardımcı olabilir (birçok işlemci benzer şekilde çalışır).

Bu IBM makalesinde okuyabileceğiniz bellek hizalamasına bağlı kalmanın daha birçok avantajı vardır .

Bilgisayarın birincil kullanımı verileri dönüştürmektir. Modern bellek mimarileri ve teknolojileri, daha güvenilir, daha fazla veri girişi, çıkışı ve arasında daha fazla ve daha hızlı yürütme birimleri elde etmek için on yıllar boyunca optimize edilmiştir.

Bonus: Önbellekler

Daha önce bahsettiğim performans için başka bir hizalama (örneğin, bazı CPU'larda) önbellek hatlarında hizalamadır (örneğin, bazı CPU'larda).

Önbelleklerden yararlanarak ne kadar performans elde edilebileceği hakkında daha fazla bilgi için İşlemci Önbellek Efektleri Galerisi'ne bakın ; Bundan önbellek satırı boyutlarına soru

Önbellek satırlarını anlamak, belirli program optimizasyonu türleri için önemli olabilir. Örneğin, verilerin hizalanması, bir işlemin bir veya iki önbellek satırına dokunup dokunmadığını belirleyebilir. Yukarıdaki örnekte gördüğümüz gibi, bu, yanlış hizalanmış durumda, işlemin iki kat daha yavaş olacağı anlamına gelebilir.


Aşağıdaki xyz yapıları farklı boyutlara sahiptir, çünkü her üyenin kuralı, boyutunun katları olan adresle başlamalıdır ve strüktür, yapı elemanının en büyük boyutunun katları olan adresle bitmelidir. yapı x {kısa s; // 2 bayt ve 2 dolgu tytes int i; // 4 bayt karakter c; // 1 bayt ve 3 dolgu bayt uzunluğunda uzun l; }; yapı y {int i; // 4 bayt karakter c; // 1 bayt ve 1 dolgu bayt kısaları; // 2 bayt}; yapı z {int i; // 4 bayt kısa s; // 2 bayt karakter c; // 1 bayt ve 1 dolgu baytı};
Gavin

1
Doğru anlarsam, bir bilgisayarın neden bir adımda hizalanmamış bir kelimeyi okuyamamasının nedeni, addesslerin 32 bit değil 30 bit kullanmasıdır.
GetFree

1
@chux Evet, doğru, mutlaklar asla tutmaz. 8088, hız ve maliyet arasındaki ödünleşmelerin ilginç bir çalışmasıdır, temel olarak 16 bitlik 8086'ydı (tam 16 bitlik harici bir veriyoluna sahipti), ancak üretim maliyetlerinden tasarruf etmek için otobüs hatlarının sadece yarısı vardı. Bu nedenle 8088, belleğe erişmek için 8086'dan iki kez saat döngüsüne ihtiyaç duyuyordu, çünkü tam 16 bitlik kelimeyi elde etmek için iki okuma yapmak zorundaydı. İlginç kısmı, 8086 tek bir döngüde 16-bit okuma hizalı bir kelime yapabilir , hizalanmamış okumalar 2 alır. 8088'in yarım kelimelik bir veriyolu olması bu yavaşlamayı maskeledi.
joshperry

2
@joshperry: Hafif düzeltme: 8086, dört döngüde kelime hizalamalı 16 bit okuma yapabilirken , hizalanmamış okuma sekiz alır . Yavaş bellek arabirimi nedeniyle, 8088 tabanlı makinelerde yürütme süresine genellikle talimat getirme baskın olur. "MOV AX, BX" gibi bir komut, nominal olarak "XCHG AX, BX" den bir döngü daha hızlıdır, ancak öncesinde veya yürütmesi kod baytı başına dörtten fazla döngü alan bir talimat gelmezse, dört döngü daha uzun sürer yürütün. 8086'da, kod getirme bazen yürütmeye ayak uydurabilir, ancak
8088'de

1
Çok doğru, @martin. Bu dolgu baytlarını tartışma içi yapılandırmaya odaklamak için kullandım, ancak belki de onları dahil etmek daha iyi olurdu.
joshperry

22

bazı işlemcilerle yapabilirsiniz ( nehalem bunu yapabilir ), ancak daha önce tüm bellek erişimi 64 bit (veya 32 bit) bir çizgide hizalanmıştı, çünkü veri yolu 64 bit genişliğinde, bir seferde 64 bit getirmeniz gerekiyordu ve bunları 64 bitlik hizalanmış 'parçalar' olarak getirmek çok daha kolaydı.

Yani, tek bir bayt almak istiyorsanız, 64 bitlik belleği aldınız ve daha sonra istemediğiniz bitleri maskelediniz. Baytınız doğru uçtaysa kolay ve hızlı, ancak bu 64 bitlik yığının ortasındaysa, istenmeyen bitleri maskelemeniz ve ardından verileri doğru yere kaydırmanız gerekir. Daha da kötüsü, 2 baytlık bir değişken istiyorsanız, ancak bu 2 parçaya bölünmüşse, bu gerekli bellek erişiminin iki katını gerektirir.

Yani, herkes belleğin ucuz olduğunu düşündüğü için, derleyiciyi verileri işlemcinin yığın boyutlarına göre hizaladılar, böylece kodunuz boşa harcanan maliyetle daha hızlı ve daha verimli çalışıyor.


5

Temel olarak, bunun nedeni, bellek veri yolunun, bellek boyutundan çok, çok daha küçük belirli bir uzunluğa sahip olmasıdır.

Bu nedenle, CPU günümüzde genellikle 32KB olan yonga üstü L1 önbelleğinden okuyor. Ancak L1 önbelleğini CPU'ya bağlayan bellek veri yolu, önbellek hattı boyutunun çok daha küçük genişliğine sahip olacaktır. Bu 128 bit civarında olacaktır .

Yani:

262,144 bits - size of memory
    128 bits - size of bus

Yanlış hizalanmış erişimler zaman zaman iki önbellek satırıyla çakışır ve bu, verileri elde etmek için tamamen yeni bir önbellek okunmasını gerektirir. DRAM'a kadar tüm yolu bile kaçırabilir.

Ayrıca, CPU'nun bir kısmı, her biri bir parça veriye sahip olan bu iki farklı önbellek satırından tek bir nesneyi bir araya getirmek için başının üstünde durmak zorunda kalacaktır. Bir satırda çok yüksek dereceli bitlerde, diğer satırda çok düşük dereceli bitlerde olacaktır.

CPU veri yolunun gerekli bitleri üzerine hizalanmış nesneleri hareket ettiren boru hattına tam olarak entegre edilmiş özel bir donanım olacaktır, ancak bu tür bir donanım yanlış hizalanmış nesneler için eksik olabilir, çünkü muhtemelen doğru şekilde optimize edilmiş hızlandırmak için bu transistörleri kullanmak daha mantıklıdır. programları.

Her durumda, bazen gerekli olan ikinci bellek okuması, yanlış hizalanmış bellek işlemlerini yamalamak için ne kadar özel amaçlı donanım (varsayımsal ve aptalca) olursa olsun boru hattını yavaşlatacaktır.


5

@joshperry bu soruya mükemmel bir cevap verdi. Cevabına ek olarak, açıklanan efektleri, özellikle 2X amplifikasyonunu grafik olarak gösteren bazı sayılar var. Farklı kelime hizalamalarının etkisinin nasıl göründüğünü gösteren bir Google e-tablosuna bağlantı . Ek olarak, test kodunu içeren bir Github özetine bir bağlantı . Test kodu Jonathan Rentzsch tarafından yazılan ve @joshperry'nin referans aldığı makaleden uyarlanmıştır . Testler dört çekirdekli 2.8 GHz Intel Core i7 64 bit işlemci ve 16 GB RAM ile bir Macbook Pro'da gerçekleştirildi.

resim açıklamasını buraya girin


4
Ne xve ykoordine demek?
shuva

1
Hangi nesil core i7? (Kod bağlantılarını gönderdiğiniz için teşekkürler!)
Nick Desaulniers

2

Bayt adresli belleğe sahip bir sistemde 32 bit genişliğinde bir bellek veri yolu varsa, bu, hepsi aynı adresi okumak veya yazmak için kablolu dört bayt genişliğinde bellek sistemi olduğu anlamına gelir. Hizalanmış 32 bit okuma, dört bellek sisteminin hepsinde aynı adreste depolanan bilgileri gerektirir, böylece tüm sistemler aynı anda veri sağlayabilir. Ayarlanmamış bir 32 bit okuma, bazı bellek sistemlerinin bir adresten veri döndürmesini ve bazılarının bir sonraki daha yüksek adresten veri döndürmesini gerektirir. Her ne kadar bu tür istekleri yerine getirmek için optimize edilmiş bazı bellek sistemleri olsa da (adreslerine ek olarak, etkili bir şekilde "artı bir" sinyale sahip olduklarından, belirtilenden daha yüksek bir adres kullanmalarına neden olur) ve bir bellek sisteminin karmaşıklığı;


2

32bit veri yolunuz varsa, belleğe bağlı adres veri yolu adres hatları A 2'den başlayacaktır. , bu nedenle tek bir veri yolu döngüsünde yalnızca 32 bit hizalanmış adreslere erişilebilir.

Yani bir kelime adres hizalama sınırını kapsarsa - 16/32 bit veri için A 0 veya A 1 32 bit veri için sıfır değilse, verileri elde etmek için iki veri yolu döngüsü gerekir.

Bazı mimariler / talimat setleri hizalanmamış erişimi desteklemez ve bu tür girişimlerde bir istisna oluşturur, bu nedenle derleyici tarafından oluşturulan hizalanmamış erişim kodu yalnızca ek veri yolu döngüleri değil, aynı zamanda daha az verimli hale getirmek için ek talimatlar gerektirir.


0

PowerPC'de tek bir adresten sorunsuz bir tam sayı yükleyebilirsiniz.

Sparc ve I86 ve (sanırım) Itatnium bunu denediğinizde donanım istisnaları ortaya çıkarıyor.

Bir 32 bit yük vs dört 8 bit yük, çoğu modern işlemcide çok fazla fark yaratmayacak. Verilerin zaten önbellekte olup olmadığı çok daha büyük bir etkiye sahip olacaktır.


Sparc, bu bir "Otobüs hatası", bu nedenle Peter Van der Linden'in "Uzman C Programlama: Derin C Sırları"
jjg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.