почему выравнивание структуры данных важно для производительности? - PullRequest
26 голосов
/ 05 января 2010

Может ли кто-нибудь дать мне краткое и правдоподобное объяснение того, почему компилятор добавляет заполнение к структурам данных для выравнивания своих членов? Я знаю, что это сделано для того, чтобы процессор мог более эффективно получать доступ к данным, но я не понимаю, почему это так.

И если это связано только с процессором, почему в Linux выровнены двойные 4 байта, а в Windows - 8 байтов?

Ответы [ 4 ]

16 голосов
/ 05 января 2010

Выравнивание помогает процессору эффективно извлекать данные из памяти: меньше пропуска / сброса кэша, меньше транзакций шины и т. Д.

Некоторые типы памяти (например, RDRAM, DRAM и т. Д.) Должны быть доступны структурированным образом (выровненные «слова» и «пакетные транзакции», то есть много слов за один раз) для получения эффективных результатов. Это связано со многими вещами, среди которых:

  1. время установки: время, необходимое устройствам памяти для доступа к ячейкам памяти
  2. издержки арбитража по шине, т. Е. Многим устройствам может потребоваться доступ к запоминающему устройству

«Заполнение» используется для корректировки выравнивания структур данных с целью оптимизации эффективности передачи.


Другими словами, доступ к «неправильно выровненной» структуре приведет к снижению общей производительности. Хороший пример такой ловушки: предположим, что структура данных выровнена неправильно и требует, чтобы ЦП / контроллер памяти выполнил 2 транзакции шины (вместо 1), чтобы извлечь указанную структуру, следовательно, производительность ниже.

12 голосов
/ 05 января 2010

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

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

7 голосов
/ 05 января 2010

Строка кэша является основной единицей кэширования. Обычно это 16-64 байта или более.

Pentium IV: 64 байта; Pentium Pro / II: 32 байта; Pentium I: 32 байта; 486: 16 байтов.

myrandomreader:
  ; ...
  ; ten instructions to generate next pseudo-random
  ; address in ESI from previous address
  ; ...
  MOV EAX, DS:[ESI]   ; X
  LOOP myrandomreader

Для чтения из памяти, расположенной на двух линиях кеша:

(для пропуска кэша L1) процессор должен дождаться, пока вся строка кэша 1 будет считана из L2-> L1 в процессор, прежде чем он сможет запросить вторую строку кэша, что приведет к короткому останову выполнения

(для пропуска кэша L2) процессор должен ждать двух пакетных чтений из кэша L3 (если имеется) или основной памяти, чтобы завершить, а не один

Процессор останавливается

  • Случайное 4-байтовое чтение будет охватывать границу кэширования примерно в 5% времени для 64-байтовых кэшированных строк, 10% для 32-байтовых и 20% для 16-байтовых.

  • Могут быть дополнительные накладные расходы на выполнение некоторых инструкций по смещенным данным, даже если они находятся в пределах кэша. Об этом говорится на веб-сайте Intel для некоторых инструкций SSE.

  • Если вы сами определяете структуры, возможно, имеет смысл взглянуть на перечисление всех <32-битных полей данных вместе в <code>struct, чтобы уменьшить накладные расходы на заполнение, или в качестве альтернативы проверить, лучше ли перевернуть упаковку вкл или выкл для конкретной структуры.

  • На MIPS и многих других платформах у вас нет выбора и вы должны выполнить выравнивание - исключение ядра, если вы этого не сделаете !!

  • Выравнивание может также иметь особое значение для вас, если вы выполняете ввод / вывод на шине или используете атомарные операции, такие как атомарное увеличение / уменьшение или если вы хотите иметь возможность переносить свой код на не-Intel.

  • В коде только (!) Intel распространенной практикой является определение одного набора упакованных структур для сети и диска и другого дополненного набора для оперативной памяти и наличие подпрограмм для преобразования данных между этими форматами (также учитывайте «порядковый номер» для дисков и сетевых форматов).

3 голосов
/ 05 января 2010

В дополнение к ответу jldupont, в некоторых архитектурах есть инструкции загрузки и хранения (те, которые используются для чтения / записи в память и из памяти), что только работают на границах с выравниванием по словам - таким образом, для загрузки невыровненных Слово из памяти заняло бы две инструкции загрузки, инструкцию сдвига, а затем инструкцию маски - гораздо менее эффективно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...