Как проектировать объекты для исполнения

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

Рассмотрим следующий класс:

class Foo
{
public:
float x;
float y;
float z;

/* Constructors and Methods */

private:
float padding;
}

Автор утверждает, что заполнение, увеличивающее размер объекта до четырех слов в архитектуре x86, приводит к заметному повышению производительности. Это потому что 4 слова сидят больше чисто в памяти, чем 3, что это значит? Дополнение объекта избыточными данными для увеличения производительности кажется мне довольно парадоксальным.

Это также вызывает другой вопрос, как насчет объектов, которые имеют размер 1 или 2 слова?
Если мой класс что-то вроде:

class Bar
{
public:
float x;
float y;

/* Constructors and Methods */

private:
/* padding ?? */
}

Должен ли я добавить отступы к этому классу, чтобы он сидел больше чисто в памяти?

13

Решение

Это компилятора ответственность за принятие решения о том, что является разумным дополнением (при условии типичных схем доступа). Компилятор знает о вашей машине гораздо больше, чем вы когда-либо узнаете. Кроме того, ваша машина будет с вами пару лет; Программа будет существовать в течение десятилетий, работая на широком спектре платформ, в зависимости от ошеломляющего разнообразия моделей использования. То, что является лучшим для сегодняшнего i7, вполне может быть худшим для завтрашнего i8 или ARMv11.

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

9

Другие решения

Процессоры не «читают» память за байтом, как люди, они обрабатывают ее порциями, порциями, в зависимости от процессора. Это называется гранулярностью доступа к памяти;

Путем «выравнивания памяти» вашего объекта время доступа может быть меньше, и вы также можете избежать фрагментации данных.

Вы можете прочитать больше о выравнивании данных Вот

Редактировать: я не говорю, что это хорошая или плохая практика, просто делюсь тем, что я знаю об этом.

3

В ответ на этот вопрос нужно сказать две действительно важные вещи.

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

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

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

1