Звичайно, я не розумію. Скажіть, у вас є пам'ять зі словом пам'яті довжиною 1 байт. Чому ви не можете отримати доступ до 4-байтної змінної в одному доступі до пам’яті по нерівневій адресі (тобто не ділиться на 4), як це стосується вирівняних адрес?
Звичайно, я не розумію. Скажіть, у вас є пам'ять зі словом пам'яті довжиною 1 байт. Чому ви не можете отримати доступ до 4-байтної змінної в одному доступі до пам’яті по нерівневій адресі (тобто не ділиться на 4), як це стосується вирівняних адрес?
Відповіді:
Це обмеження багатьох базових процесорів. Зазвичай це можна обійти, виконуючи 4 неефективні однобайтові вибірки, а не один ефективний вибір слів, але багато специфікаторів мови вирішили, що простіше просто заборонити їх і змусити все вирівняти.
У цьому посиланні є набагато більше інформації, яку відкрила ОП.
Підсистема пам'яті на сучасному процесорі обмежена доступом до пам'яті за деталізацією та вирівнюванням її розміру слова; це відбувається з ряду причин.
Сучасні процесори мають кілька рівнів пам’яті кешу, через які потрібно перетягувати дані; Підтримка однобайтових зчитувань зробить пропускну здатність підсистеми пам'яті щільно пов'язаною з пропускною здатністю блоку виконання (він же пов'язаний з процесором); це все нагадує те, як режим 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.
Для отримання додаткової інформації про те, яку ефективність можна отримати, використовуючи кеші, подивіться у Галереї ефектів кешового процесора ; з цього питання щодо розмірів рядка кеш-пам'яті
Розуміння рядків кешу може бути важливим для певних типів програмних оптимізацій. Наприклад, вирівнювання даних може визначати, чи торкається операція одна чи дві лінії кешу. Як ми бачили в прикладі вище, це може легко означати, що в несогласованном випадку операція буде вдвічі повільнішою.
ви можете з деякими процесорами ( nehalem це може зробити ), але раніше весь доступ до пам'яті був вирівняний на 64-бітній (або 32-бітної) лінії, оскільки шина шириною 64 біт, вам довелося отримати 64 біт за один раз , і було значно простіше отримати їх у вирівняні "шматки" 64 біт.
Отже, якщо ви хотіли отримати один байт, ви дістали 64-бітний шматок, а потім замаскували біти, які ви не хотіли. Легко і швидко, якщо ваш байт знаходився в потрібному кінці, але якби він був посередині цього 64-бітного фрагмента, вам доведеться замаскувати небажані біти, а потім перенести дані в потрібне місце. Гірше, якщо ви хотіли 2-байтної змінної, але вона була розділена на 2 шматки, то для цього потрібно подвоїти необхідний доступ до пам'яті.
Отже, оскільки всі вважають, що пам'ять дешева, вони просто змусили компілятор вирівняти дані за розмірами процесора, щоб ваш код працював швидше та ефективніше за рахунок витраченої пам'яті.
Принципово, причина полягає в тому, що шина пам'яті має певну довжину, яка значно, значно менша за розмір пам'яті.
Отже, процесор зчитує кеш-пам’ять L1, який часто складає 32 КБ. Але шина пам'яті, яка з'єднує кеш-пам'ять L1 з процесором, матиме значно меншу ширину розміру лінії кеша. Це буде в порядку 128 біт .
Так:
262,144 bits - size of memory
128 bits - size of bus
Зменені доступи час від часу перекриватимуть два рядки кешу, і для цього знадобиться абсолютно новий кеш-запис, щоб отримати дані. Це може навіть пропустити весь шлях до DRAM.
Крім того, деяка частина процесора повинна буде стояти на голові, щоб зібрати один об'єкт з цих двох різних ліній кешу, кожен з яких має частинку даних. В одному рядку це будуть біти дуже високого порядку, в іншому - біти дуже низького порядку.
У конвеєр буде виділено спеціальне обладнання, повністю інтегроване, яке обробляє рухомі вирівняні об'єкти на необхідні біти шини даних процесора, однак такого обладнання може не вистачати для несогласованних об'єктів, оскільки, мабуть, має сенс використовувати ці транзистори для прискорення правильно оптимізованих операцій програм.
У будь-якому випадку, друга прочитана пам'ять, яка іноді необхідна, сповільнить конвеєр, незалежно від того, наскільки апаратне обладнання спеціального призначення (гіпотетично і нерозумно) було призначене для виправлення нерівних операцій з пам'яттю.
@joshperry дав чудову відповідь на це питання. На додаток до його відповіді, у мене є деякі цифри, які графічно показують описані ефекти, особливо 2X посилення. Ось посилання на електронну таблицю Google , яка показує, як виглядає ефект від різних вирівнювань слів. Крім того, ось посилання на суть Github з кодом для тесту. Тестовий код адаптований із статті, яку написав Джонатан Ренцш, на яку посилається @joshperry. Тести проводились на Macbook Pro з чотирьохядерним 2,8 ГГц Intel Core i7 64-бітним процесором та 16 ГБ оперативної пам’яті.
x
і y
координати?
Якщо система з байтовою адресною пам’яттю має 32-бітну шину пам’яті, це означає, що існує фактично чотири байтові системи пам’яті, які всі є провідними для читання або запису однієї адреси. Вирівняне 32-бітове зчитування потребуватиме інформації, що зберігається за однією адресою у всіх чотирьох системах пам'яті, тому всі системи можуть одночасно подавати дані. 32-розрядне зчитування, яке не зрівняється, потребує деяких систем пам'яті для повернення даних з однієї адреси, а деякі для повернення даних із наступної вищої адреси. Хоча є деякі системи пам'яті, які оптимізовані для виконання таких запитів (крім їх адреси, вони фактично мають сигнал "плюс один", який змушує їх використовувати адресу, вищу, ніж зазначена), така функція додає значних витрат і складність системи пам'яті;
Якщо у вас є 32-бітна шина даних, адреси адресних шин адреси, підключені до пам'яті, починатимуться з А 2 , тому лише один 32-бітний вирівнюваний адрес можна отримати в одному циклі шини.
Отже, якщо слово охоплює межу вирівнювання адреси - тобто A 0 для даних 16/32 біт або A 1 для 32-бітових даних не дорівнює нулю, для отримання даних потрібні два цикли шини.
Деякі набори архітектур / інструкцій не підтримують нестандартний доступ і створюватимуть виняток з таких спроб, тому генерований компілятором нестандартний код доступу вимагає не просто додаткових циклів шини, а додаткових інструкцій, що робить його ще менш ефективним.
На PowerPC ви можете без проблем завантажити ціле число з непарної адреси.
Sparc, I86 та (я думаю) Itatnium підвищують винятки з апаратних засобів, коли ви спробуєте це.
Одне 32-бітове навантаження проти чотирьох 8-бітових навантажень не буде мати велике значення на більшості сучасних процесорів. Будь-які дані вже є в кеші чи ні, матиме набагато більший ефект.