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

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

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

ark 19.12.2008 18:31

Прочтите эту небольшую статью для тех, кто начинает это изучать: blog.virtualmethodstudio.com/2017/03/memory-alignment-run-fo‌ ols

darkgaze 11.12.2017 16:31

ссылка @ark не работает

John Jiang 22.03.2020 08:00

@JohnJiang Я думаю, что нашел здесь новую ссылку: developer.ibm.com/technologies/systems/articles/pa-dalign

ejohnso49 17.04.2020 06:56
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
211
4
85 212
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

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

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

Спасибо, @AveMilia, я обновил ответ.

Paul Tomblin 10.03.2021 00:56

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

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

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

На Sparc это была «Ошибка шины», отсюда и глава «Ошибка шины, сядьте на поезд» в книге Питера Ван дер Линдена «Экспертное программирование на C: секреты Deep C».

jjg 01.04.2020 22:35

Он говорит здесь, что PowerPC может обрабатывать 32-битные невыровненные данные, вызывает аппаратное исключение для 64-битных данных.

Harsh 21.08.2020 13:44

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

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

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

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

Скорость

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

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

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

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

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

Struct Layout

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

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

Packed Struct

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

Когда вы просите процессор дать вам 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.

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

Understanding of cache lines can be important for certain types of program optimizations. For example, alignment of data may determine whether an operation touches one or two cache lines. As we saw in the example above, this can easily mean that in the misaligned case, the operation will be twice slower.

следующие структуры 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 байт заполнения};

Gavin 04.05.2014 08:39

Это также хорошая ссылка, основанная на главе книги Джейсона Грегори «Программирование игрового движка»: hjistcgam475.blogspot.se/2013/02/…

AzP 09.05.2014 17:17

Если я правильно понимаю, причина, ПОЧЕМУ компьютер не может прочитать невыровненное слово за один шаг, заключается в том, что в суммах используется 30 бит, а не 32 бита ??

GetFree 17.06.2014 02:50

Незначительное примечание: «ЦП ВСЕГДА читает в соответствии с размером слова»: не со старым 8088

chux - Reinstate Monica 20.06.2014 07:00

@GetFree Нет. Как и многое в жизни, есть компромиссы, плюсы и минусы. Ограничение количества адресных строк более сложное, чем в, причина того, что современные архитектуры не делают невыровненный доступ. Если процессор никогда не будет обращаться к невыровненной памяти, тогда зачем включать физические трассы на плату и нести расходы на проектирование, тестирование, отладку и производство?

joshperry 22.06.2014 21:29

@chux Да, это правда, абсолютов никогда не бывает. 8088 представляет собой интересное исследование компромисса между скоростью и стоимостью, в основном это был 16-битный 8086 (с полной 16-битной внешней шиной), но с половиной шинных линий для экономии производственных затрат. Из-за этого 8088 требовалось в два раза больше тактовых циклов для доступа к памяти, чем 8086, поскольку ему приходилось делать два чтения, чтобы получить полное 16-битное слово. Интересно то, что 8086 может выполнять 16-битное чтение слово выровнено за один цикл, невыровненное чтение занимает 2. Тот факт, что у 8088 была полусловная шина, маскировала это замедление.

joshperry 22.06.2014 21:40

@joshperry В этот вопрос я спрашиваю, какова настоящая причина, по которой это невозможно, но никто не дал убедительного ответа.

GetFree 23.06.2014 01:16

@joshperry: Небольшая коррекция: 8086 может выполнять 16-битное чтение с выравниванием по словам за циклы четыре, в то время как невыровненное чтение занимает восемь. Из-за медленного интерфейса памяти время выполнения на машинах на базе 8088 обычно определяется выборкой инструкций. Команда типа «MOV AX, BX» номинально на один цикл быстрее, чем «XCHG AX, BX», но если ей не предшествует или не следует инструкция, выполнение которой занимает более четырех циклов на байт кода, потребуется на четыре цикла больше времени, чтобы выполнять. На 8086 выборка кода иногда может поспевать за выполнением, но на 8088, если вы не используете ...

supercat 01.03.2015 06:19

Так это влияет только на чтение с диска или тоже влияет на объекты в памяти? сколько бит-ридера, который читает и кэширует блок размером 8 байт, на 64-битном компьютере?

MarcusJ 19.06.2015 15:39

Я считаю, что выравнивание mystruct неправильное. Структуры C всегда выравниваются по выравниванию самого большого члена, поэтому после s должно быть два дополнительных байта заполнения.

Martin 16.12.2015 22:51

Совершенно верно, @martin. Я убрал эти байты заполнения, чтобы сфокусировать обсуждение внутри структуры, но, возможно, было бы лучше включить их.

joshperry 16.12.2015 23:04

"The CPU can operate on an aligned word of memory atomically", как понять это предложение? IMO, операция с памятью не всегда будет атомарной, как ++i, процедура может быть следующей: 1. чтение значения i в регистр 2. регистр приращения 3. сохранение значения регистра в i

xiaodong 04.04.2016 11:11

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

joshperry 15.04.2016 23:28

@joshperry Понятно! Большое спасибо ~

xiaodong 20.04.2016 17:22

Вы имели в виду 64Б (байта) для строк кеша?

Lmn 14.02.2017 19:28
ЦП всегда читает в соответствии с размером слова (4 байта на 32-битном процессоре) - Нет, это чрезмерное упрощение. Большинство процессоров x86 имеют полностью эффективные невыровненные нагрузки, если они не пересекают границу строки кэша. См. Как я могу точно измерить скорость невыровненного доступа на x86_64. Кроме того, 32-разрядные процессоры нередко обращаются к кеш-памяти по 8 байтов за раз. например P5 Pentium и более поздние версии гарантируют атомарность выровненных 8-байтовых загрузок и сохранений. (Возможно в 32-битном режиме с FP или MMX или с SSE movq). Точно так же многие 32-битные ARM гарантируют атомарность пары нагрузки.
Peter Cordes 19.08.2020 11:46

Также кеши x86 поддерживают байт магазины с полной эффективностью. (Однако микроархитектуры для многих других ISA выполняют цикл RMW для фиксации узких или смещенных хранилищ в кэш.)

Peter Cordes 19.08.2020 11:47

@PeterCordes Совершенно верно! Динамика кэширования и выровненной памяти невероятно интересна, а иногда и довольно сложна. Я пытался исключить обсуждение того, как кеши взаимодействуют с выравниванием, в своем ответе, чтобы он был кратким, но ваши комментарии хорошо принимаются.

joshperry 09.10.2020 20:18

Разве нет архитектур, которые вообще не поддерживают невыровненный доступ?

Oskar Skog 24.10.2020 21:17

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

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

Так:

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

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

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

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

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

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

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

Peter Cordes 19.08.2020 11:53

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

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

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

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

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

Что означают координаты x и y?

shuva 02.10.2018 23:07

Какое поколение Core i7? (Спасибо за размещение ссылок на код!)

Nick Desaulniers 07.01.2019 10:11

Другие вопросы по теме