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

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

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

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

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 ?? */
}

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Подробнее о выравнивании данных вы можете прочитать здесь

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

Ответ 3

В ответ на этот вопрос есть две очень важные вещи.

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

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

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