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

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


person ark    schedule 19.12.2008    source источник
comment
После некоторого дополнительного поиска в Google я нашел это отличная ссылка, которая действительно хорошо объясняет проблему.   -  person ark    schedule 19.12.2008
comment
Прочтите эту небольшую статью для тех, кто начинает это изучать: blog.virtualmethodstudio .com / 2017/03 / memory-alignment-run-fools.   -  person Darkgaze    schedule 11.12.2017
comment
ссылка @ark не работает   -  person John Jiang    schedule 22.03.2020
comment
@JohnJiang Я думаю, что нашел здесь новую ссылку: developer.ibm.com/ технологии / системы / статьи / pa-dalign   -  person ejohnso49    schedule 17.04.2020


Ответы (8)


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

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

person Paul Tomblin    schedule 19.12.2008
comment
Спасибо, @AveMilia, я обновил ответ. - person Paul Tomblin; 10.03.2021

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

Скорость

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

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

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

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 битами для чего-то вроде флагов. Удаление 2 младших битов из адреса даст вам 4-байтовое выравнивание; также называется шагом размером 4 байта. Каждый раз, когда адрес увеличивается, он фактически увеличивает бит 2, а не бит 0, т.е. последние 2 бита всегда будут равны 00.

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

Атомарность

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

Заключение

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

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

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

Бонус: Тайники

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

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

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

person joshperry    schedule 19.12.2008
comment
следующие структуры x y z имеют разные размеры, потому что правило каждого члена должно начинаться с адреса, который кратен его размеру, а strcut должен заканчиваться адресом, который кратен наибольшему размеру члена структуры. struct x {короткие s; // 2 байта и 2 отступа int i; // 4 байта char c; // 1 байт и 3 байта заполнения long long l; }; структура у {int я; // 4 байта char c; // 1 байт и 1 байт заполнения short s; // 2 байта}; struct z {int i; // 4 байта короткие s; // 2 байта char c; // 1 байт и 1 байт заполнения}; - person Gavin; 04.05.2014
comment
Это также хорошая ссылка, основанная на главе книги Джейсона Грегори «Программирование игрового движка»: hjistcgam475.blogspot.se/2013/02/ - person AzP; 09.05.2014
comment
Если я правильно понимаю, причина, ПОЧЕМУ компьютер не может прочитать невыровненное слово за один шаг, заключается в том, что в суммах используется 30 бит, а не 32 бита ?? - person GetFree; 17.06.2014
comment
Незначительное примечание: ЦП ВСЕГДА читает в соответствии с размером слова: не со старым 8088 - person chux - Reinstate Monica; 20.06.2014
comment
@GetFree Нет. Как и во многих вещах в жизни, есть компромиссы, плюсы и минусы. Ограничение числа адресных строк более сложно, чем причина того, что современные архитектуры не делают невыровненный доступ. Если процессор никогда не будет обращаться к невыровненной памяти, тогда зачем включать физические трассы на плату и нести расходы на проектирование, тестирование, отладку и производство? - person joshperry; 22.06.2014
comment
@chux Да, это правда, абсолютов никогда не бывает. 8088 представляет собой интересное исследование компромисса между скоростью и стоимостью, в основном это был 16-битный 8086 (с полной 16-битной внешней шиной), но с половиной шинных линий для экономии производственных затрат. Из-за этого 8088 требовалось в два раза больше тактовых циклов для доступа к памяти, чем 8086, поскольку ему приходилось делать два чтения, чтобы получить полное 16-битное слово. Интересно то, что 8086 может выполнять выравнивание по словам 16-битное чтение за один цикл, невыровненное чтение занимает 2. Тот факт, что 8088 имел шину на полуслова, маскировал это замедление. - person joshperry; 22.06.2014
comment
@joshperry В этом вопросе я спрашиваю, какова настоящая причина, по которой это невозможно, но убедительного ответа никто не получил. - person GetFree; 23.06.2014
comment
@joshperry: Небольшая поправка: 8086 может выполнять 16-битное чтение с выравниванием по словам за четыре цикла, в то время как невыровненное чтение занимает восемь. Из-за медленного интерфейса памяти время выполнения на машинах на базе 8088 обычно определяется выборкой инструкций. Такая инструкция, как MOV AX, BX, номинально на один цикл быстрее, чем XCHG AX, BX, но если ей не предшествует или не следует инструкция, выполнение которой занимает более четырех циклов на байт кода, для ее выполнения потребуется на четыре цикла больше. На 8086 выборка кода иногда может поспевать за выполнением, но на 8088, если вы не используете ... - person supercat; 01.03.2015
comment
Так это влияет только на чтение с диска или тоже влияет на объекты в памяти? сколько бит-ридера, который читает и кэширует блок размером 8 байт, на 64-битном компьютере? - person MarcusJ; 19.06.2015
comment
Я думаю, что выравнивание mystruct неверно. Структуры C всегда выравниваются по выравниванию самого большого члена, поэтому после s должно быть два дополнительных байта заполнения. - person Martin; 16.12.2015
comment
Совершенно верно, @martin. Я убрал эти байты заполнения, чтобы сфокусировать обсуждение внутри структуры, но, возможно, было бы лучше включить их. - person joshperry; 16.12.2015
comment
The CPU can operate on an aligned word of memory atomically, как понять это предложение? IMO, операция с памятью не всегда будет атомарной, как ++i, процедура может быть следующей: 1. чтение значения i в регистр 2. регистр приращения 3. сохранение значения регистра в i - person cifer; 04.04.2016
comment
@cli__: многие процессоры имеют специальные инструкции для блокированного увеличения, уменьшения и обмена (среди других атомарных операций), которые даже плохой компилятор будет использовать во многих случаях, таких как этот, и - за исключением ограждений памяти - сам процессор может свободно использовать переупорядочить инструкции для наиболее эффективного выполнения. Современные процессоры невероятно сложны, особенно когда речь идет о кэшировании, потоке данных в основную память и из нее, а также о распараллеливании ядер современного конвейера процессора. - person joshperry; 15.04.2016
comment
@joshperry Понятно! Большое спасибо ~ - person cifer; 20.04.2016
comment
Вы имели в виду 64Б (байта) для строк кеша? - person Lmn; 14.02.2017
comment
ЦП всегда читает со своим размером слова (4 байта на 32-битном процессоре) - Нет, это чрезмерное упрощение. Большинство процессоров x86 имеют полностью эффективные невыровненные нагрузки, если они не пересекают границу строки кэша. См. Как я могу точно измерить скорость невыровненного доступа на x86_64. Кроме того, 32-разрядные процессоры нередко обращаются к кеш-памяти по 8 байтов за раз. например P5 Pentium и более поздние версии гарантируют атомарность выровненных 8-байтовых загрузок и сохранений. (Возможно в 32-битном режиме с FP или MMX, или с SSE movq). Точно так же многие 32-битные ARM гарантируют атомарность пары нагрузки. - person Peter Cordes; 19.08.2020
comment
Кроме того, кеши x86 поддерживают байтовые хранилища с полной эффективностью. (Однако микроархитектуры для многих других ISA выполняют цикл RMW для фиксации узких или смещенных хранилищ в кэш.) - person Peter Cordes; 19.08.2020
comment
@PeterCordes Совершенно верно! Динамика кэширования и согласованной памяти невероятно интересна, а иногда и довольно сложна. Я пытался исключить обсуждение того, как кеши взаимодействуют с выравниванием, в своем ответе, чтобы он был кратким, но ваши комментарии хорошо принимаются. - person joshperry; 09.10.2020
comment
Разве нет архитектур, которые вообще не поддерживают невыровненный доступ? - person Oskar Skog; 24.10.2020

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

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

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

person gbjbaanb    schedule 19.12.2008

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

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

So:

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

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

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

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

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

person DigitalRoss    schedule 01.03.2011
comment
независимо от того, сколько специального оборудования было (гипотетически и по глупости) предназначено для исправления несогласованных операций с памятью - современные процессоры Intel, пожалуйста, встаньте и / помашите. : P Полностью эффективная обработка смещенных 256-битных загрузок AVX (при условии, что они не пересекают границу строки кэша) удобна для программного обеспечения. Даже разделенная загрузка не так уж и плоха, поскольку Skylake значительно снижает штраф за загрузку / сохранение разделенной страницы с ~ 100 циклов до ~ 10. (Что произойдет при векторизации по невыровненному буферу с циклом, который не тратит лишние указатели выравнивания кода запуска / очистки) - person Peter Cordes; 19.08.2020
comment
ЦП AVX512 с 512-битными путями между кешем L1d и исполнительными модулями загрузки / сохранения значительно больше страдают от смещенных указателей, потому что каждая загрузка смещена, а не все остальные. - person Peter Cordes; 19.08.2020

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

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

person adino    schedule 06.04.2016
comment
Что означают координаты x и y? - person shuva; 02.10.2018
comment
Какое поколение Core i7? (Спасибо за размещение ссылок на код!) - person Nick Desaulniers; 07.01.2019

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

person supercat    schedule 15.06.2011

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

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

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

person Clifford    schedule 19.06.2014

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

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

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

person James Anderson    schedule 19.12.2008
comment
На Sparc это была ошибка шины, отсюда и глава Ошибка шины, Сядьте на поезд в книге Питера Ван дер Линдена «Экспертное программирование на C: секреты Deep C». - person jjg; 01.04.2020
comment
Здесь говорится, что PowerPC может обрабатывать 32-разрядные невыровненные данные. вызывает аппаратное исключение для 64-битных данных. - person Harsh; 21.08.2020