Назначение выравнивания памяти

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

8 Solutions collect form web for “Назначение выравнивания памяти”

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

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

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

скорость

Современные процессоры имеют несколько уровней кеш-памяти, которые необходимо протащить; поддерживающие однобайтовые чтения сделают пропускную способность подсистемы памяти плотно связанной с пропускной способностью исполнительного блока (также известной как cpu-bound); все это напоминает то, как режим 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, вы получите 2-кратное усиление. Процессор будет считывать с 0x0000 в реестр результатов и сдвигать влево 1 байт, затем снова считывать с 0x0004 во временный регистр, сдвигать вправо 3 байта, затем OR с результирующим регистром.

Ассортимент

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

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

валентность

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

Вывод

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

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

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

Бонус: Кэши

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

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

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

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

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

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

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

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

Так:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Как многомерные массивы отформатированы в памяти?
  • Определить размер кучи приложения в Android
  • Является ли sizeof (некоторый указатель) всегда равным четырем?
  • Ориентировочная стоимость доступа к различным кешам и основной памяти?
  • Когда именно это безопасно для утечки для использования (анонимных) внутренних classов?
  • Что такое fragmentация памяти?
  • Получение максимальной пропускной способности на Haswell в кеше L1: получение только 62%
  • Почему не указатели инициализируются с помощью NULL по умолчанию?
  • Определить размер динамически распределенной памяти в C
  • Как получить размер объекта в памяти?
  • Создание утечки памяти с помощью Java
  • Давайте будем гением компьютера.