Мета вирівнювання пам'яті


197

Звичайно, я не розумію. Скажіть, у вас є пам'ять зі словом пам'яті довжиною 1 байт. Чому ви не можете отримати доступ до 4-байтної змінної в одному доступі до пам’яті по нерівневій адресі (тобто не ділиться на 4), як це стосується вирівняних адрес?


17
Зробивши кілька додаткових гуглів, я знайшов це чудове посилання, яке дуже добре пояснює проблему.
ковчег

Перегляньте цю невелику статтю для людей, які починають це вивчати: blog.virtualmethodstudio.com/2017/03/memory-alignment-run-fools
darkgaze

3
Посилання порушено @ark
Джон Цзян

2
@JohnJiang Я думаю, що тут я знайшов нове посилання: developer.ibm.com/technologies/systems/articles/pa-dalign
ejohnso49

Відповіді:


63

Це обмеження багатьох базових процесорів. Зазвичай це можна обійти, виконуючи 4 неефективні однобайтові вибірки, а не один ефективний вибір слів, але багато специфікаторів мови вирішили, що простіше просто заборонити їх і змусити все вирівняти.

У цьому посиланні є набагато більше інформації, яку відкрила ОП.


311

Підсистема пам'яті на сучасному процесорі обмежена доступом до пам'яті за деталізацією та вирівнюванням її розміру слова; це відбувається з ряду причин.

Швидкість

Сучасні процесори мають кілька рівнів пам’яті кешу, через які потрібно перетягувати дані; Підтримка однобайтових зчитувань зробить пропускну здатність підсистеми пам'яті щільно пов'язаною з пропускною здатністю блоку виконання (він же пов'язаний з процесором); це все нагадує те, як режим PIO був перевершений DMA з багатьох тих же причин на жорстких дисках.

Процесор завжди читає у своєму розмірі слова (4 байти на 32-бітному процесорі), тому коли ви робите нестандартний доступ до адреси - на процесор, який його підтримує - процесор збирається прочитати кілька слів. Центральний процесор буде читати кожне слово пам'яті, яке проходить Ваша адреса. Це викликає посилення до 2X кількості транзакцій пам'яті, необхідних для доступу до запитуваних даних.

Через це читати два байти, ніж чотири, можна дуже повільно. Наприклад, скажімо, у вас є структура в пам'яті, яка виглядає так:

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

На 32-бітному процесорі він, швидше за все, вирівняється так, як показано тут:

Структурний макет

Процесор може прочитати кожного з цих членів за одну транзакцію.

Скажіть, у вас була запакована версія структури, можливо, з мережі, де вона була запакована для ефективності передачі; це може виглядати приблизно так:

Упакована структура

Читання першого байта буде таким самим.

Коли ви попросите процесор дати вам 16 біт від 0x0005, йому доведеться прочитати слово з 0x0004 і змістити лівий 1 байт, щоб помістити його в 16-бітний регістр; кілька додаткових робіт, але більшість може впоратися з цим за один цикл.

Коли ви запитаєте 32 біти від 0x0001, ви отримаєте двократне підсилення. Процесор зчитує з 0x0000 в регістр результатів і змістить лівий 1 байт, потім знову прочитає з 0x0004 у тимчасовий регістр, зсуне право на 3 байти, потім ORйого з регістром результатів.

Дальність

Якщо для будь-якого заданого адресного простору, якщо архітектура може припустити, що 2 LSB завжди є 0 (наприклад, 32-розрядні машини), він може отримати доступ до 4 разів більше пам'яті (2 збережені біти можуть представляти 4 різних стани) або стільки ж пам'яті з 2 бітами для чогось типу прапорів. Якщо зняти 2 LSB з адреси, ви отримаєте 4-байтове вирівнювання; також називається кроком у 4 байти. Кожен раз, коли адреса збільшується, вона фактично збільшує біт 2, а не біт 0, тобто останні 2 біти завжди будуть залишатися 00.

Це може вплинути навіть на фізичну конструкцію системи. Якщо шині адреси потрібні 2 менші біти, на процесорі може бути 2 менших шпильки, а на друкованій платі - 2 менші сліди.

Атомність

ЦП може працювати атомним вирівняним словом пам'яті, тобто жодна інша інструкція не може перервати цю операцію. Це дуже важливо для правильної роботи багатьох беззаблокових структур даних та інших парадигм паралельних дій .

Висновок

Система пам'яті процесора є дещо складнішою та задіяною, ніж описано тут; може допомогти дискусія про те, як процесор x86 насправді адресує пам'ять (багато процесорів працюють аналогічно).

Є ще багато переваг щодо дотримання вирівнювання пам’яті, які ви можете прочитати в цій статті IBM .

Основне використання комп'ютера - це перетворення даних. Сучасні архітектури та технології пам’яті були оптимізовані протягом десятиліть, щоб полегшити отримання більшої кількості даних, вхідних даних, та між більш швидкими і швидкими одиницями виконання - у дуже надійний спосіб.

Бонус: Кеші

Ще одне вирівнювання для продуктивності, на яке я раніше натякав, - це вирівнювання в кеш-лініях, які (наприклад, на деяких процесорах) 64B.

Для отримання додаткової інформації про те, яку ефективність можна отримати, використовуючи кеші, подивіться у Галереї ефектів кешового процесора ; з цього питання щодо розмірів рядка кеш-пам'яті

Розуміння рядків кешу може бути важливим для певних типів програмних оптимізацій. Наприклад, вирівнювання даних може визначати, чи торкається операція одна чи дві лінії кешу. Як ми бачили в прикладі вище, це може легко означати, що в несогласованном випадку операція буде вдвічі повільнішою.


Наступні структури xyz мають різний розмір, тому що правило кожного члена має починатися з адреси, кратної його розміру, і стружка повинна закінчуватися адресою, кратною найбільшого розміру члена структури. struct x {короткий s; // 2 байти і 2 padding tytes int i; // 4 байти char c; // 1 байт і 3 байти, що вкладаються, довжиною l; }; struct y {int i; // 4 байти char c; // 1 байт та 1 байт коротких s; // 2 байти}; struct z {int i; // 4 байти коротких s; // 2 байти char c; // 1 байт і 1 байт padding;
Гевін

1
Якщо я правильно розумію, причина ЧОМ комп’ютер не може прочитати нерівне слово за один крок, це тому, що адресати використовують 30 біт, а не 32 біти ??
GetFree

1
@chux Так, це правда, абсолюти ніколи не тримаються. 8088 - це цікаве дослідження компромісів між швидкістю та вартістю; він в основному був 16-бітовим 8086 (який мав повну 16-бітну зовнішню шину), але мав лише половину автобусних ліній для економії виробничих витрат. Через це 8088 було потрібно двічі циклів годин для доступу до пам'яті, ніж 8086, оскільки йому довелося зробити два читання, щоб отримати повне 16-бітове слово. Цікавою частиною є те, що 8086 може виконати вирівнювання 16-бітного слова за один цикл, а нерівне читання - 2. Факт, що в 8088 була шина півслова, замаскувала це уповільнення.
joshperry

2
@joshperry: Невелика корекція: 8086 може виконати 16-бітове зчитування у відповідність словам за чотири цикли, а нерівне читання - вісім . Через повільний інтерфейс пам'яті, час виконання на машинах, що базуються на 8088, зазвичай переважають набори інструкцій. Інструкція на кшталт "MOV AX, BX" номінально на один цикл швидша, ніж "XCHG AX, BX", але, якщо їй не передує чи не передує інструкція, виконання якої займає більше чотирьох циклів на один байт коду, на це знадобиться чотири цикли довше виконати. На сайті 8086 вилучення коду іноді може бути в курсі виконання, але на 8088, якщо хтось не використовує ...
supercat

1
Дуже правда, @martin. Я схилив ці байти, щоб зосередити дискусію на внутрішній структурі, але, можливо, було б краще включити їх.
joshperry

22

ви можете з деякими процесорами ( nehalem це може зробити ), але раніше весь доступ до пам'яті був вирівняний на 64-бітній (або 32-бітної) лінії, оскільки шина шириною 64 біт, вам довелося отримати 64 біт за один раз , і було значно простіше отримати їх у вирівняні "шматки" 64 біт.

Отже, якщо ви хотіли отримати один байт, ви дістали 64-бітний шматок, а потім замаскували біти, які ви не хотіли. Легко і швидко, якщо ваш байт знаходився в потрібному кінці, але якби він був посередині цього 64-бітного фрагмента, вам доведеться замаскувати небажані біти, а потім перенести дані в потрібне місце. Гірше, якщо ви хотіли 2-байтної змінної, але вона була розділена на 2 шматки, то для цього потрібно подвоїти необхідний доступ до пам'яті.

Отже, оскільки всі вважають, що пам'ять дешева, вони просто змусили компілятор вирівняти дані за розмірами процесора, щоб ваш код працював швидше та ефективніше за рахунок витраченої пам'яті.


5

Принципово, причина полягає в тому, що шина пам'яті має певну довжину, яка значно, значно менша за розмір пам'яті.

Отже, процесор зчитує кеш-пам’ять L1, який часто складає 32 КБ. Але шина пам'яті, яка з'єднує кеш-пам'ять L1 з процесором, матиме значно меншу ширину розміру лінії кеша. Це буде в порядку 128 біт .

Так:

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

Зменені доступи час від часу перекриватимуть два рядки кешу, і для цього знадобиться абсолютно новий кеш-запис, щоб отримати дані. Це може навіть пропустити весь шлях до DRAM.

Крім того, деяка частина процесора повинна буде стояти на голові, щоб зібрати один об'єкт з цих двох різних ліній кешу, кожен з яких має частинку даних. В одному рядку це будуть біти дуже високого порядку, в іншому - біти дуже низького порядку.

У конвеєр буде виділено спеціальне обладнання, повністю інтегроване, яке обробляє рухомі вирівняні об'єкти на необхідні біти шини даних процесора, однак такого обладнання може не вистачати для несогласованних об'єктів, оскільки, мабуть, має сенс використовувати ці транзистори для прискорення правильно оптимізованих операцій програм.

У будь-якому випадку, друга прочитана пам'ять, яка іноді необхідна, сповільнить конвеєр, незалежно від того, наскільки апаратне обладнання спеціального призначення (гіпотетично і нерозумно) було призначене для виправлення нерівних операцій з пам'яттю.


5

@joshperry дав чудову відповідь на це питання. На додаток до його відповіді, у мене є деякі цифри, які графічно показують описані ефекти, особливо 2X посилення. Ось посилання на електронну таблицю Google , яка показує, як виглядає ефект від різних вирівнювань слів. Крім того, ось посилання на суть Github з кодом для тесту. Тестовий код адаптований із статті, яку написав Джонатан Ренцш, на яку посилається @joshperry. Тести проводились на Macbook Pro з чотирьохядерним 2,8 ГГц Intel Core i7 64-бітним процесором та 16 ГБ оперативної пам’яті.

введіть тут опис зображення


4
Що означають xі yкоординати?
shuva

1
Яке покоління i7? (Дякуємо за розміщення посилань на код!)
Нік Десольньє,

2

Якщо система з байтовою адресною пам’яттю має 32-бітну шину пам’яті, це означає, що існує фактично чотири байтові системи пам’яті, які всі є провідними для читання або запису однієї адреси. Вирівняне 32-бітове зчитування потребуватиме інформації, що зберігається за однією адресою у всіх чотирьох системах пам'яті, тому всі системи можуть одночасно подавати дані. 32-розрядне зчитування, яке не зрівняється, потребує деяких систем пам'яті для повернення даних з однієї адреси, а деякі для повернення даних із наступної вищої адреси. Хоча є деякі системи пам'яті, які оптимізовані для виконання таких запитів (крім їх адреси, вони фактично мають сигнал "плюс один", який змушує їх використовувати адресу, вищу, ніж зазначена), така функція додає значних витрат і складність системи пам'яті;


2

Якщо у вас є 32-бітна шина даних, адреси адресних шин адреси, підключені до пам'яті, починатимуться з А 2 , тому лише один 32-бітний вирівнюваний адрес можна отримати в одному циклі шини.

Отже, якщо слово охоплює межу вирівнювання адреси - тобто A 0 для даних 16/32 біт або A 1 для 32-бітових даних не дорівнює нулю, для отримання даних потрібні два цикли шини.

Деякі набори архітектур / інструкцій не підтримують нестандартний доступ і створюватимуть виняток з таких спроб, тому генерований компілятором нестандартний код доступу вимагає не просто додаткових циклів шини, а додаткових інструкцій, що робить його ще менш ефективним.


0

На PowerPC ви можете без проблем завантажити ціле число з непарної адреси.

Sparc, I86 та (я думаю) Itatnium підвищують винятки з апаратних засобів, коли ви спробуєте це.

Одне 32-бітове навантаження проти чотирьох 8-бітових навантажень не буде мати велике значення на більшості сучасних процесорів. Будь-які дані вже є в кеші чи ні, матиме набагато більший ефект.


Для Sparc це була "помилка автобуса", звідси розділ "Помилка автобуса, сідайте на поїзд" у "Пітер Ван дер дер Лінден" "Програмування експертів C: Deep C Secrets"
jjg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.