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

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

8 ответов

Решение

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

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

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

скорость

Современные процессоры имеют несколько уровней кэш-памяти, через которую должны извлекаться данные; поддержка однобайтовых считываний сделает пропускную способность подсистемы памяти тесно связанной с пропускной способностью исполнительного блока (иначе, связанной с процессором); все это напоминает то, как режим 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 битами для чего-то вроде флагов. Удаление 2 младших битов из адреса даст вам 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 Gist с кодом для теста. Тестовый код взят из статьи, написанной Джонатаном Рентзшем, на которую ссылается @joshperry. Тесты проводились на Macbook Pro с четырехъядерным 64-битным процессором Intel Core i7 с частотой 2,8 ГГц и 16 ГБ оперативной памяти.

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

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

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

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

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

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

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

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