Цель выравнивания памяти

196

Правда, я не понимаю. Скажем, у вас есть память со словом памяти длиной 1 байт. Почему вы не можете получить доступ к переменной длиной 4 байта в одном доступе к памяти по невыровненному адресу (т.е. не делится на 4), как это имеет место с выровненными адресами?

ковчег
источник
17
После некоторого дополнительного поиска в Google я нашел эту замечательную ссылку, которая действительно хорошо объясняет проблему.
Ковчег
Посмотрите эту небольшую статью для людей, которые начинают изучать это: 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 неэффективных однобайтовых выборки, а не одну эффективную выборку слов, но многие спецификаторы языка решили, что будет проще просто запретить их и заставить все выровняться.

По этой ссылке гораздо больше информации, которую обнаружил ОП.

Пол Томблин
источник
310

Подсистема памяти на современном процессоре ограничена доступом к памяти по степени детализации и выравниванию ее размера слова; это имеет место по ряду причин.

скорость

Современные процессоры имеют несколько уровней кэш-памяти, через которую должны извлекаться данные; поддержка однобайтовых считываний сделает пропускную способность подсистемы памяти тесно связанной с пропускной способностью исполнительного блока (иначе, связанной с процессором); все это напоминает то, как режим PIO был превзойден DMA по многим из тех же причин в жестких дисках.

Процессор всегда читает со своим размером слова (4 байта на 32-разрядном процессоре), поэтому, когда вы выполняете доступ с невыровненным адресом - на процессоре, который его поддерживает, процессор будет читать несколько слов. Процессор будет читать каждое слово памяти, которое заполняет ваш запрошенный адрес. Это приводит к увеличению в 2 раза количества транзакций памяти, необходимых для доступа к запрашиваемым данным.

Из-за этого очень легко прочитать два байта медленнее, чем четыре. Например, скажем, у вас есть структура в памяти, которая выглядит следующим образом:

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

На 32-битном процессоре он, скорее всего, будет выровнен, как показано здесь:

Структура макета

Процессор может прочитать каждый из этих членов в одной транзакции.

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

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

Чтение первого байта будет таким же.

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

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

Ассортимент

Для любого данного адресного пространства, если архитектура может предполагать, что 2 младших бита всегда равны 0 (например, 32-разрядные машины), тогда она может получить доступ в 4 раза больше памяти (2 сохраненных бита могут представлять 4 различных состояния), или столько же памяти с 2 битами для чего-то вроде флагов. Удаление двух младших битов из адреса даст вам 4-байтовое выравнивание; также называется шагом 4 байта. Каждый раз, когда адрес увеличивается, он эффективно увеличивает бит 2, а не бит 0, т. Е. Последние 2 бита всегда будут оставаться 00.

Это может даже повлиять на физический дизайн системы. Если для шины адреса требуется на 2 бита меньше, на процессоре может быть на 2 контакта меньше, а на плате - 2 трассы.

валентность

Процессор может атомарно работать с выровненным словом памяти, что означает, что никакая другая инструкция не может прервать эту операцию. Это имеет решающее значение для правильной работы многих структур данных без блокировки и других парадигм параллелизма .

Вывод

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

Есть много других преимуществ соблюдения выравнивания памяти, которые вы можете прочитать в этой статье IBM .

Основное назначение компьютера - преобразование данных. Современные архитектуры и технологии памяти были оптимизированы на протяжении десятилетий, чтобы упростить получение большего объема данных, вход, выход и между более быстрыми исполнительными блоками - с высокой надежностью.

Бонус: кеши

Другое выравнивание по производительности, о котором я упоминал ранее, это выравнивание по строкам кэша, которые (например, на некоторых процессорах) имеют 64B.

Для получения дополнительной информации о том, как можно повысить производительность за счет использования кэшей, см. « Галерея эффектов кэша процессора» ; из этого вопроса о размерах строки кэша

Понимание строк кэша может быть важно для определенных типов программных оптимизаций. Например, выравнивание данных может определять, касается ли операция одной или двух строк кэша. Как мы видели в приведенном выше примере, это может легко означать, что в случае неправильного выравнивания операция будет в два раза медленнее.

joshperry
источник
следующие структуры xyz имеют разные размеры, поскольку правило каждого члена должно начинаться с адреса, кратного его размеру, а строка должна заканчиваться адресом, кратным наибольшему размеру члена структуры. struct x {short s; // 2 байта и 2 дополнительных поля int i; // 4 байта char c; // 1 байт и 3 байта заполнения long long l; }; struct y {int i; // 4 байта char c; // 1 байт и 1 дополнительный байт short s; // 2 байта}; struct z {int i; // 4 байта короткого s; // 2 байта char c; // 1 байт и 1 байт заполнения};
Гэвин
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, если не используется ...
суперкат
1
Очень верно, @martin. Я исключил эти байты заполнения, чтобы сфокусировать обсуждение внутри структуры, но, возможно, было бы лучше включить их.
Joshperry
22

вы можете использовать некоторые процессоры ( это может сделать nehalem ), но ранее весь доступ к памяти был выровнен по 64-битной (или 32-битной) линии, поскольку шина имеет 64-битную ширину, вам приходилось извлекать 64-битную за раз и было значительно проще получить их в выровненных «блоках» по 64 бита.

Итак, если вы хотите получить один байт, вы получили 64-битный блок, а затем скрыли ненужные биты. Легко и быстро, если ваш байт был в правильном конце, но если бы он был в середине этого 64-битного фрагмента, вам пришлось бы маскировать ненужные биты и затем перемещать данные в нужное место. Хуже того, если вы хотели 2-байтовую переменную, но она была разделена на 2 блока, то это требовало двойного доступа к памяти.

Итак, поскольку все думают, что память дешева, они просто заставили компилятор выровнять данные по размерам блоков процессора, чтобы ваш код работал быстрее и эффективнее за счет потраченной памяти.

gbjbaanb
источник
5

По сути, причина в том, что шина памяти имеет определенную длину, намного меньшую, чем объем памяти.

Таким образом, процессор считывает данные из кэш-памяти L1, которая в наши дни часто составляет 32 КБ. Но шина памяти, которая соединяет кэш L1 с процессором, будет иметь значительно меньшую ширину строки кэша. Это будет порядка 128 бит .

Так:

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

Неверно выровненные обращения иногда перекрывают две строки кэша, и для получения данных потребуется совершенно новое чтение из кэша. Это может даже пропустить весь путь к DRAM.

Кроме того, некоторая часть ЦП должна будет стоять на голове, чтобы собрать один объект из этих двух разных строк кэша, в каждой из которых есть часть данных. В одной строке это будут биты очень высокого порядка, в другой - биты очень низкого порядка.

Будет выделенное оборудование, полностью интегрированное в конвейер, который обрабатывает перемещение выровненных объектов на необходимые биты шины данных ЦП, но такого оборудования может не хватать для смещенных объектов, потому что, вероятно, более целесообразно использовать эти транзисторы для ускорения, правильно оптимизированного программы.

В любом случае, второе чтение памяти, которое иногда необходимо, будет замедлять конвейер, независимо от того, сколько специального оборудования было (гипотетически и глупо) выделено для исправления смещенных операций с памятью.

DigitalRoss
источник
5

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

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

Adino
источник
4
Что xи yкоординаты означают?
Шува
1
Какое поколение Core i7? (Спасибо за размещение ссылок на код!)
Ник
2

Если система с адресуемой в байтах памятью имеет шину памяти шириной 32 бита, это означает, что фактически существуют четыре системы памяти шириной в байт, которые все подключены для чтения или записи одного и того же адреса. Для выравниваемого 32-разрядного чтения потребуется информация, хранящаяся по одному и тому же адресу во всех четырех системах памяти, поэтому все системы могут предоставлять данные одновременно. 32-разрядное чтение без выравнивания потребовало бы, чтобы некоторые системы памяти возвращали данные с одного адреса, а некоторые - с другого, более высокого адреса. Хотя есть некоторые системы памяти, которые оптимизированы для выполнения таких запросов (в дополнение к их адресу у них фактически есть сигнал «плюс один», который заставляет их использовать адрес на один выше указанного), такая функция добавляет значительную стоимость и сложность системы памяти;

Supercat
источник
2

Если у вас есть 32-битная шина данных, адресные линии адресной шины, подключенные к памяти, начнутся с A 2 , так что только 32-битные выровненные адреса могут быть доступны за один цикл шины.

Таким образом, если слово охватывает границу выравнивания адреса - т.е. A 0 для 16/32-битных данных или A 1 для 32-битных данных не равны нулю, для получения данных требуются два такта шины.

Некоторые архитектуры / наборы инструкций не поддерживают не выровненный доступ и генерируют исключение при таких попытках, поэтому сгенерированный компилятором код не выровненного доступа требует не только дополнительных циклов шины, но и дополнительных инструкций, что делает его еще менее эффективным.

Клиффорд
источник
0

На PowerPC вы можете загрузить целое число с нечетного адреса без проблем.

Sparc и I86 и (я думаю) Itatnium поднимают аппаратные исключения, когда вы пытаетесь это сделать.

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

Джеймс Андерсон
источник
На Sparc это была «Ошибка шины», отсюда и глава «Ошибка шины, сядьте на поезд» в
книге