Подтвердить что ты не робот

Действительно ли выравнивание имеет значение для производительности на С++ 11?

Действительно ли выравнивание имеет значение для производительности в С++ 11?

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

4b9b3361

Ответ 1

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

Совет для сортировки членов в порядке убывания размера для оптимальной упаковки/минимального пространства, потраченного путём, а не для выравнивания или скорости. Члены будут правильно выровнены независимо от того, в каком порядке вы их перечисляете, если вы не запросите несоответствующую компоновку с использованием специализированных прагм (т.е. не переносимых #pragma pack) или ключевых слов. Хотя на общий размер структуры влияет добавка, а также влияет на скорость, часто есть оптимальное оптимальное упорядочение.

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

Ответ 2

Просто чтобы добавить к Бену отличный ответ:

Определение членов структуры в том же порядке, к которому они будут впоследствии доступны в вашем приложении, уменьшит промахи в кэше и, возможно, повысит производительность. Это будет работать, если вся структура не впишется в кеш L1.

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

Предположим, что для архитектуры (я не знаю, что это хорошо, я думаю, что это будет иметь место для настроек по умолчанию 32bit gcc, кто-то поправит меня в комментариях) эта структура:

struct MemoryUnused {
  uint8_t val0;
  uint16_t val1;
  uint8_t val2;
  uint16_t val3;
  uint8_t val4;
  uint32_t val5;
  uint8_t val6;
}

занимает 20 байтов в памяти, а это:

struct MemoryNotLost {
  uint32_t val5;
  uint16_t val1;
  uint16_t val3;
  uint8_t val0;
  uint8_t val2;
  uint8_t val4;
  uint8_t val6;
}

Возьмем 12. Это 8 байт потеряно из-за заполнения, и это на 67% больше размера структуры smallers. С большим массивом таких структур коэффициент усиления будет значительным и, просто из-за объема используемой памяти, уменьшит количество промахов в кэше.