C ++ 11 — Нужно ли выравнивание в C ++?

Я уверен, что я делаю. Матричная библиотека Eigen3, вероятно, намного быстрее, чем любая из моих собственных реализаций матриц благодаря выравниванию.

Недавно я начал исследовать выравнивание с помощью C ++. Я наткнулся на функции alignas и alignof и решил провести несколько тестов.

Моя первая находка было то, что члены структуры выравниваются автоматически. Давайте возьмем следующую структуру в качестве примера:

struct MyStruct
{
char m_c; // 1 byte
double m_x; // 8 bytes
};

и сравните с этим:

struct MyAlignedStruct
{
char m_c; // 1 byte
alignas(8) double m_x; // 8 bytes
};

где я использовал alignas вместо добавления отступа (char [7]), что, по моему мнению, эквивалентно.

Теперь просмотрщик памяти для обеих структур показал следующее:

62 00 00 00 8e a8 79 35 00 00 00 00 00 00 10 40 // MyStruct
62 ff ff ff 24 00 00 00 00 00 00 00 00 00 10 40 // MyAlignedStruct

Первый байт соответствует символу (‘b’). При использовании Mystruct следующие 7 байтов заполняются что-то, и 8 последних байтов представляют двойное число. При использовании MyAlignedStruct происходит нечто очень похожее. Функция sizeof () возвращает 16 байтов для обеих структур (я ожидал 9 байтов для MyStruct).

Итак, вот мой первый вопрос: зачем мне выровнять, если компилятор выравнивается сам?

Моя вторая находка было то, что alignas (..) не ускоряет мою программу. Мой эксперимент был следующим. Представьте себе следующую простую структуру:

struct Point
{
double m_x, m_y, m_z;
};

Если я заполню вектор экземплярами этой структуры и предположим, что первый экземпляр выровнен по 32 байта, каждая структура будет занимать 24 байта, а последовательность байтов больше не будет выровнена по 32 байта. Честно говоря, я не уверен, каким образом скорость может быть увеличена путем выравнивания, иначе я бы, скорее всего, не писал здесь. Тем не менее, я использовал alignas для получения следующей структуры:

alignas(32) struct Point
{
double m_x, m_y, m_z;
};

Теперь непрерывные экземпляры Point будут начинаться с кратности 32 байта. Я протестировал обе версии: после заполнения огромного вектора экземплярами структур я суммировал все двойные числа и записал время. Я не нашел различий между 32-байтовой выровненной структурой и другой.

Итак, мой второй вопрос такой же, как и мой первый: зачем мне использовать alignas?

3

Решение

Зачем мне выравнивание, если компилятор выравнивается сам по себе?

Несколько причин из головы:

  1. Компилятор может быть настроен для упаковки структур, как описано здесь:

    Заставить структуру C ++ плотно упаковать

    но вы хотите, чтобы какая-то конкретная структура имела выровненные элементы

  2. Вы хотите выравнивание, которое выходит за рамки того, что требует тип, например,

    alignas(1024) struct MyStruct
    {
    char m_c; // 1 byte
    alignas(32) double m_x; // 8 bytes
    };
    

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

  3. Введите punning / slicing: вы можете получить адрес для массива:

    struct s1
    {
    char m_c;
    uint32_t m_d;
    char m_e;
    };
    

    но я на самом деле использовал

    struct s2
    {
    char m_c;
    mystery_type_with_size_64_bits m_d;
    char m_e;
    };
    

    так что даже если вы хотите работать с m_d как uint32_t, но вы также должны получить m_e право.

2

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

Других решений пока нет …