Tujuan penyelarasan memori

195

Memang saya tidak mengerti. Katakanlah Anda memiliki memori dengan kata memori yang panjangnya 1 byte. Mengapa Anda tidak dapat mengakses variabel panjang 4 byte dalam akses memori tunggal pada alamat yang tidak selaras (yaitu tidak dapat dibagi dengan 4), karena ini adalah kasus dengan alamat yang disejajarkan?

tabut
sumber
17
Setelah melakukan beberapa Googling tambahan, saya menemukan tautan bagus ini , yang menjelaskan masalahnya dengan sangat baik.
bahtera
Lihatlah artikel kecil ini untuk orang-orang yang mulai belajar ini: blog.virtualmethodstudio.com/2017/03/memory-alignment-run-fools
darkgaze
3
@ark link broken
John Jiang
2
@JohnJiang Saya pikir saya menemukan tautan baru di sini: developer.ibm.com/technologies/systems/articles/pa-dalign
ejohnso49

Jawaban:

62

Ini adalah batasan dari banyak prosesor yang mendasarinya. Biasanya dapat dikerjakan dengan melakukan 4 pengambilan byte yang tidak efisien daripada mengambil kata yang efisien, tetapi banyak penspesifikasi bahasa memutuskan akan lebih mudah hanya untuk melarang mereka dan memaksa segala sesuatu untuk disejajarkan.

Ada lebih banyak informasi dalam tautan ini yang ditemukan OP.

Paul Tomblin
sumber
310

Subsistem memori pada prosesor modern dibatasi untuk mengakses memori pada rincian dan keselarasan ukuran kata-katanya; hal ini terjadi karena sejumlah alasan.

Mempercepat

Prosesor modern memiliki beberapa tingkat memori cache yang harus ditarik data; mendukung pembacaan byte tunggal akan membuat throughput subsistem memori terikat erat dengan throughput unit eksekusi (alias cpu-terikat); ini semua mengingatkan bagaimana mode PIO dilampaui oleh DMA karena banyak alasan yang sama pada hard drive.

CPU selalu membaca pada ukuran kata (4 byte pada prosesor 32-bit), jadi ketika Anda melakukan akses alamat yang tidak selaras - pada prosesor yang mendukungnya - prosesor akan membaca beberapa kata. CPU akan membaca setiap kata dari memori yang dialamatkan oleh alamat yang Anda minta. Ini menyebabkan amplifikasi hingga 2X jumlah transaksi memori yang diperlukan untuk mengakses data yang diminta.

Karena itu, dapat dengan mudah menjadi lebih lambat untuk membaca dua byte daripada empat. Misalnya, Anda memiliki struct dalam memori yang terlihat seperti ini:

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

Pada prosesor 32-bit kemungkinan besar akan diselaraskan seperti yang ditunjukkan di sini:

Tata Letak Struktur

Prosesor dapat membaca masing-masing anggota ini dalam satu transaksi.

Katakanlah Anda memiliki versi struct yang dikemas, mungkin dari jaringan di mana ia dikemas untuk efisiensi transmisi; mungkin terlihat seperti ini:

Packed Struct

Membaca byte pertama akan sama.

Ketika Anda meminta prosesor untuk memberi Anda 16 bit dari 0x0005 itu harus membaca kata dari dari 0x0004 dan bergeser ke kiri 1 byte untuk menempatkannya dalam register 16-bit; beberapa pekerjaan tambahan, tetapi sebagian besar dapat mengatasinya dalam satu siklus.

Ketika Anda meminta 32 bit dari 0x0001 Anda akan mendapatkan amplifikasi 2X. Prosesor akan membaca dari 0x0000 ke dalam register hasil dan bergeser ke kiri 1 byte, kemudian membaca lagi dari 0x0004 ke dalam register sementara, menggeser ke kanan 3 byte, kemudian ORdengan register hasil.

Jarak

Untuk setiap ruang alamat yang diberikan, jika arsitektur dapat mengasumsikan bahwa 2 LSB selalu 0 (misalnya, mesin 32-bit) maka ia dapat mengakses memori 4 kali lebih banyak (2 bit yang disimpan dapat mewakili 4 keadaan berbeda), atau jumlah yang sama memori dengan 2 bit untuk sesuatu seperti bendera. Melepaskan 2 LSB dari suatu alamat akan memberi Anda keselarasan 4-byte; juga disebut sebagai langkah 4 byte. Setiap kali sebuah alamat bertambah maka secara efektif menambah bit 2, bukan bit 0, yaitu, 2 bit terakhir akan selalu terus menjadi 00.

Ini bahkan dapat mempengaruhi desain fisik sistem. Jika bus alamat membutuhkan 2 bit lebih sedikit, mungkin ada 2 pin lebih sedikit pada CPU, dan 2 jejak lebih sedikit pada papan sirkuit.

Atomicity

CPU dapat beroperasi pada kata memori yang selaras secara atom, artinya tidak ada instruksi lain yang dapat mengganggu operasi itu. Ini sangat penting untuk operasi yang benar dari banyak struktur data bebas kunci dan paradigma konkurensi lainnya .

Kesimpulan

Sistem memori prosesor agak sedikit lebih kompleks dan terlibat daripada yang dijelaskan di sini; diskusi tentang bagaimana prosesor x86 sebenarnya menangani memori dapat membantu (banyak prosesor bekerja dengan cara yang sama).

Ada banyak manfaat lainnya untuk mematuhi penyelarasan memori yang dapat Anda baca di artikel IBM ini .

Penggunaan utama komputer adalah mengubah data. Arsitektur dan teknologi memori modern telah dioptimalkan selama beberapa dekade untuk memfasilitasi mendapatkan lebih banyak data, masuk, keluar, dan antara unit eksekusi lebih banyak dan lebih cepat - dengan cara yang sangat andal.

Bonus: Tembolok

Penyelarasan-untuk-kinerja lain yang saya singgung sebelumnya adalah penyelarasan pada garis cache yang (misalnya, pada beberapa CPU) 64B.

Untuk info lebih lanjut tentang berapa banyak kinerja yang bisa diperoleh dengan memanfaatkan cache, lihat Galeri Efek Cache Prosesor ; dari pertanyaan ini tentang ukuran cache-line

Memahami garis cache bisa penting untuk beberapa jenis optimasi program. Misalnya, penyelarasan data dapat menentukan apakah suatu operasi menyentuh satu atau dua garis cache. Seperti yang kita lihat pada contoh di atas, ini dapat dengan mudah berarti bahwa dalam kasus yang tidak selaras, operasi akan dua kali lebih lambat.

Joshperry
sumber
struct berikut xyz memiliki ukuran yang berbeda, karena aturan masing-masing anggota harus mulai dengan alamat yang merupakan kelipatan dari ukurannya dan strcut harus diakhiri dengan alamat yang merupakan kelipatan dari ukuran terbesar anggota struct. struct x {short s; // 2 byte dan 2 padding tytes int i; // 4 byte char c; // 1 byte dan 3 padding byte panjang l; }; struct y {int i; // 4 byte char c; // 1 byte dan 1 padding byte pendek s; // 2 byte}; struct z {int i; // 4 byte pendek s; // 2 byte char c; // 1 byte dan 1 byte padding};
Gavin
1
Jika saya mengerti dengan benar, alasan MENGAPA komputer tidak dapat membaca kata yang tidak selaras dalam satu langkah adalah karena addesses menggunakan 30 bit dan bukan 32 bit ??
GetFree
1
@ chux Ya itu benar, absolut tidak pernah berlaku. The 8088 adalah studi yang menarik tentang pengorbanan antara kecepatan dan biaya, itu pada dasarnya adalah 8086 16-bit (yang memiliki bus eksternal 16-bit penuh) tetapi dengan hanya setengah jalur bus untuk menghemat biaya produksi. Karena itu, 8088 membutuhkan dua kali siklus jam untuk mengakses memori daripada 8086 karena harus melakukan dua kali bacaan untuk mendapatkan kata 16-bit penuh. Bagian yang menarik, 8086 dapat melakukan pembacaan 16-bit sejajar kata dalam satu siklus, bacaan tidak selaras mengambil 2. Fakta bahwa 8088 memiliki bus setengah kata menutupi perlambatan ini.
joshperry
2
@ joshperry: Koreksi ringan: 8086 dapat melakukan pembacaan 16-bit yang selaras kata dalam empat siklus, sementara pembacaan yang tidak selaras membutuhkan delapan . Karena antarmuka memori yang lambat, waktu eksekusi pada mesin berbasis 8088 biasanya didominasi oleh pengambilan instruksi. Instruksi seperti "MOV AX, BX" secara nominal satu siklus lebih cepat daripada "XCHG AX, BX", tetapi kecuali jika didahului atau diikuti oleh instruksi yang pelaksanaannya membutuhkan lebih dari empat siklus per byte kode, itu akan memakan waktu empat siklus lebih lama untuk menjalankan. Pada 8086, pengambilan kode terkadang dapat mengikuti eksekusi, tetapi pada 8088 kecuali ada yang menggunakan ...
supercat
1
Sangat benar, @martin. Saya memilih byte padding untuk memfokuskan diskusi intra-struct, tapi mungkin akan lebih baik untuk memasukkannya.
joshperry
22

Anda dapat menggunakan beberapa prosesor ( nehalem dapat melakukan ini ), tetapi sebelumnya semua akses memori diselaraskan pada jalur 64-bit (atau 32-bit), karena bus berukuran 64 bit, Anda harus mengambil 64 bit sekaligus , dan secara signifikan lebih mudah untuk mengambil ini dalam 'potongan' selaras dari 64 bit.

Jadi, jika Anda ingin mendapatkan satu byte, Anda mengambil potongan 64-bit dan kemudian menutupi bit yang tidak Anda inginkan. Mudah dan cepat jika byte Anda berada di ujung kanan, tetapi jika itu di tengah-tengah potongan 64-bit, Anda harus menutupi bit yang tidak diinginkan dan kemudian menggeser data ke tempat yang tepat. Lebih buruk lagi, jika Anda menginginkan variabel 2 byte, tetapi itu terbagi menjadi 2 chunks, maka itu diperlukan dua kali lipat dari akses memori yang diperlukan.

Jadi, karena semua orang menganggap memori itu murah, mereka hanya membuat kompilator menyelaraskan data pada ukuran chunk prosesor sehingga kode Anda berjalan lebih cepat dan lebih efisien dengan biaya memori yang terbuang.

gbjbaanb
sumber
5

Pada dasarnya, alasannya adalah karena bus memori memiliki panjang tertentu yang jauh, jauh lebih kecil dari ukuran memori.

Jadi, CPU membaca dari cache L1 on-chip, yang sering 32KB hari ini. Tetapi bus memori yang menghubungkan cache L1 ke CPU akan memiliki ukuran garis cache yang jauh lebih kecil. Ini akan berada di urutan 128 bit .

Begitu:

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

Akses yang tidak selaras kadang-kadang akan tumpang tindih dua garis cache, dan ini akan membutuhkan cache yang sepenuhnya baru dibaca untuk mendapatkan data. Bahkan mungkin ketinggalan semua jalan keluar ke DRAM.

Selain itu, beberapa bagian dari CPU harus berdiri di atas kepalanya untuk menyatukan satu objek dari dua garis cache yang berbeda yang masing-masing memiliki data. Pada satu baris, itu akan berada dalam bit urutan sangat tinggi, di lain, bit urutan sangat rendah.

Akan ada perangkat keras khusus yang terintegrasi penuh ke dalam pipeline yang menangani memindahkan objek yang diluruskan ke bit yang diperlukan dari bus data CPU, tetapi perangkat keras tersebut mungkin kurang untuk objek yang tidak selaras, karena mungkin lebih masuk akal untuk menggunakan transistor tersebut untuk mempercepat dioptimalkan dengan benar program.

Dalam kasus apa pun, pembacaan memori kedua yang kadang-kadang diperlukan akan memperlambat pipa terlepas dari seberapa banyak perangkat keras tujuan khusus (secara hipotetis dan bodoh) yang didedikasikan untuk memperbaiki operasi memori yang tidak selaras.

DigitalRoss
sumber
5

@ joshperry telah memberikan jawaban yang sangat baik untuk pertanyaan ini. Selain jawabannya, saya memiliki beberapa angka yang menunjukkan secara grafis efek yang dijelaskan, terutama amplifikasi 2X. Berikut ini tautan ke spreadsheet Google yang menunjukkan seperti apa efek dari perataan kata. Selain itu, inilah tautan ke inti Github dengan kode untuk pengujian. Kode tes diadaptasi dari artikel yang ditulis oleh Jonathan Rentzsch yang dirujuk oleh @joshperry. Pengujian dijalankan pada Macbook Pro dengan prosesor quad-core 2,8 GHz Intel Core i7 64-bit dan RAM 16GB.

masukkan deskripsi gambar di sini

adino
sumber
4
Apa xdan ykoordinat artinya?
shuva
1
Apa core i7? (Terima kasih telah mengirim tautan ke kode!)
Nick Desaulniers
2

Jika sebuah sistem dengan memori byte-addressable memiliki bus memori 32-bit-lebar, itu berarti ada efektif sistem memori empat-byte yang semuanya kabel untuk membaca atau menulis alamat yang sama. Pembacaan 32-bit yang selaras akan membutuhkan informasi yang disimpan dalam alamat yang sama di keempat sistem memori, sehingga semua sistem dapat menyediakan data secara bersamaan. Pembacaan 32-bit yang tidak selaras akan memerlukan beberapa sistem memori untuk mengembalikan data dari satu alamat, dan beberapa untuk mengembalikan data dari alamat yang lebih tinggi berikutnya. Meskipun ada beberapa sistem memori yang dioptimalkan untuk dapat memenuhi permintaan tersebut (selain alamatnya, mereka secara efektif memiliki sinyal "plus satu" yang menyebabkan mereka menggunakan alamat yang lebih tinggi dari yang ditentukan) fitur semacam itu menambah biaya yang cukup besar dan kompleksitas sistem memori;

supercat
sumber
2

Jika Anda memiliki bus data 32bit, jalur alamat bus alamat yang terhubung ke memori akan mulai dari A 2 , sehingga hanya alamat sejajar 32bit yang dapat diakses dalam siklus bus tunggal.

Jadi, jika sebuah kata merentang batas penyejajaran alamat - yaitu A 0 untuk data 16/32 bit atau A 1 untuk data 32 bit bukan nol, dua siklus bus diperlukan untuk mendapatkan data.

Beberapa arsitektur / set instruksi tidak mendukung akses yang tidak selaras dan akan menghasilkan pengecualian pada upaya-upaya tersebut, sehingga kompiler yang dihasilkan kode akses yang tidak selaras tidak hanya memerlukan siklus bus tambahan, tetapi juga instruksi tambahan, membuatnya bahkan lebih efisien.

Clifford
sumber
0

Pada PowerPC Anda dapat memuat integer dari alamat ganjil tanpa masalah.

Sparc dan I86 dan (saya pikir) Itatnium meningkatkan pengecualian perangkat keras ketika Anda mencoba ini.

Satu beban 32 bit vs empat beban 8 bit tidak akan membuat banyak perbedaan pada kebanyakan prosesor modern. Apakah data sudah dalam cache atau tidak akan memiliki efek yang jauh lebih besar.

James Anderson
sumber
Di Sparc, ini adalah "Bus error", maka bab "Bus error, Naik kereta" di Peter Van der Linden "Expert C Programming: Deep C Secrets"
jjg