Расскажите про реальные минусы, плюсы. Подводные камни.
Ну упаковали мы структуру, ну стала она меньше памяти занимать. Как бы всё. Но допустим мы не экономим на памяти (допустим!) если ещё реальный смысл паковать? Где-то говорят что промахи кеша уменьшаются и от того код работает быстрее ведь как следствие конвеер не перезапускается, но я не верю.
UDP: На заметку (Всем спасибо за советы! (•◡•)/ )
Утилита pahole
для выявления дыр в структурах и их реорганизации в Debian утилита доступна из пакета dwarves
sudo apt install dwarves
gcc/clang c опцией -g3 -Wpadded
+ -Wextra -Wall -Werror
не пропустят код с дырявыми структурами
Например для такой структуры
typedef struct {
bool collided;
float time;
vec3 point;
vec3 norm;
int flags;
} collision;
Clang выдаёт чуть более информативно
./include/physics.h:13:9: error: padding struct 'collision' with 3 bytes to align 'time' [-Werror,-Wpadded]
float time;
GCC же просто указывает на предмет «проблемы»
./include/physics.h:13:9: error: padding struct to align ‘time’ [-Werror=padded]
float time;
^~~~
Прогон pahole же при компиляции с -g3
даёт чёткое указание на «проблему»
И это «ничего» меня поставило в ступор сначала, но дело в том что я использую typedef
и по какой то причине
pahole игнорирует не именованные структуры, если исправить так
typedef struct collision{
bool collided;
float time;
vec3 point;
vec3 norm;
int flags;
} collision;
То pahole
выдаёт чёткие подробности
struct collision {
_Bool collided; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
float time; /* 4 4 */
vec3 point; /* 8 12 */
vec3 norm; /* 20 12 */
int flags; /* 32 4 */
/* size: 36, cachelines: 1, members: 5 */
/* sum members: 33, holes: 1, sum holes: 3 */
/* last cacheline: 36 bytes */
};
Исправление на
typedef struct collision {
vec3 point;
vec3 norm;
float time;
int flags;
bool collided;
} collision;
Убирает предупреждения/ошибки из gcc/clang
, а pahole
репортует что в целом всё впорядке
struct collision {
vec3 point; /* 0 12 */
vec3 norm; /* 12 12 */
float time; /* 24 4 */
int flags; /* 28 4 */
_Bool collided; /* 32 1 */
/* size: 36, cachelines: 1, members: 5 */
/* padding: 3 */
/* last cacheline: 36 bytes */
};
Но, для полного счастья было бы хорошо заполнить 3 байта для выравнивания структур (массивы структур или дву/одно связные списки к примеру) в данном случае можно заменить bool
на int
или добавить заполнение char pad[3]
если изменение типа структуры выливается в геморой ползания по коду или нарушает читабельность.
При окончательном изменении на
typedef struct collision {
vec3 point;
vec3 norm;
float time;
int flags;
bool collided;
char __unused_struct_padding__[3];
} collision;
получаем репорт от pahole
что всё ok
struct collision {
vec3 point; /* 0 12 */
vec3 norm; /* 12 12 */
float time; /* 24 4 */
int flags; /* 28 4 */
_Bool collided; /* 32 1 */
char __unused_struct_padding__[3]; /* 33 3 */
/* size: 36, cachelines: 1, members: 6 */
/* last cacheline: 36 bytes */
};
Заполнять пустотой это конечно такое себе, но зато на будущее есть понимание что практически бесплатно можно будет в эту структуру засунуть ещё три флага например, таким образом использовать для дела в пустую в данном случае гоняемую память.
Ну вот как то так.