Сегодня утром была интересная лекцыя. Привожу слегка почищенный лог.
=======================================================
[11:02] <dDIMA> Потому что например на песи народ обленился вконец и не знает страшного слова align
[11:03] * kas низнает
[11:03] <dDIMA> kas, скажи мне. Сколько будет sizeof() структуры следующего вида:
[11:04] <dDIMA> char c1; double f1; short c2;
[11:04] <kas> ну, если прагма пак(1), то так и будет 11
[11:04] <dDIMA> На целевой платформе sizeof(double)=8, sizeof(short)=2
[11:04] <dDIMA> прагмы нету. Default align = 8
[11:05] * dDIMA нилюбит прагма пак, ибо это сильно медленнее при промахе по кратности адреса
[11:05] <kas> ну, тада пусть будет 16
[11:05] <dDIMA> нифига
[11:05] <kas> чо, 24 шоли?
[11:06] * kas проверяет
[11:06] <dDIMA> ну поехали. Смещение поля с1 - очевидно, 0.
[11:06] <dDIMA> Сколько будет смещение поля f1?
[11:06] <kas> я бы сказал 1
[11:06] <dDIMA> double должен быть выровнен на свой sizeof()
[11:07] <dDIMA> поэтому его смещение будет 8
[11:09] <dDIMA> Поэтому после с1 и f1 структура уже занимает 16 байт
[11:10] <dDIMA> Потом идет с2, оно располагается со смещением 16 и 17, и общий размер структуры будет 18 байт
[11:10] <dDIMA> А дальше начинается самое страшное
[11:10] <dDIMA> Потому что компилятор думает: "а что если какой-то программер рикнет завести массив структур"
[11:11] <dDIMA> Это что-же получится? адрес поля f1 во втором элементе структуры станет не кратен 8?
[11:11] <dDIMA> Ни фига. Не позволю! И быстренько добивает структуру байтами до размера в 24
[11:13] <dDIMA> Так что примитивной перестановкой f1 в начало структуры мы можем уменьшить ее sizeof() в полтора раза!
[11:13] <kas> ща дима, 10 минут :)
[11:14] <dDIMA> можешь еще адреса полей проинспектировать и подсчитать реальные смещения полей
[11:14] <dDIMA> А если адрес нашей переменной double не кратен 8, то процессор встает раком.
[11:14] <kas> тогда нипанятно почему ссе не взлетает
[11:14] <kas> без мемманагера
[11:15] <kas> если он всё выравнивает на алигн заданый
[11:15] <kas> ну, для ссе надо выравнивание на 16
[11:15] <dDIMA> Для VC заданный алигн - 8
[11:15] <kas> ну, можно и 16 задатьже
[11:15] <kas> только не спасает
[11:15] <dDIMA> Наверное можно
[11:15] <dDIMA> Это означает, что структуры и типы, большие по размеру чем 8, будут алайницца максимум на 8.
[11:16] <dDIMA> А вообще интеловский процессор слишком умный
[11:16] <dDIMA> Если переменная типа double не выровнена на границу в 8 байт, все работает
[11:16] <dDIMA> Только процессор считывает по шине 2 адреса и компонует число уже у себя в мозгах
[11:17] <dDIMA> Уважающие себя процессоры при такой наглости предпочитают умирать с позором
[11:18] <dDIMA> То есть если ты задаешь aligh = 1, то все действительно стыкуецца вполтную друг к другу. Все поля
[11:18] <dDIMA> Но если ты сделаешь aligh по умолчанию и правильно распределишь поля в структурах, у тебя скорость доступа к полям возрастет вдвое
Что лучше делать в таком случае:
typedef struct { emath::mat4 matWorld; // 16 bytes emath::mat4 matRelative; // 16 bytes IMesh *pMesh; // 4 bytes IMaterial *pMaterial; // 4 bytes short nParentID; // -1 means no parent short nFirstChild; // -1 means no children short nChildCount; // -1 means no children short nbDoTransform; // 0 means there are no relative transform } t_submesh;
правка: tabs
Padawan
>Что лучше делать в таком случае:
> [cut]
Тут вроде все оптимально :)
Димка
Да. Но есть дополнение. Когда бежим по трансформациям, хочеца локальность их. При том жутко хочется, ибо vfpu. Вот индексы поэтому я бы отдельно делал. Не делал бы также иерархии для простых мешей, анимацию отдельно бы делал.
neteraser
Да, все правильно. В контексте оптимизации доступа к памяти: если сначала идет пакетная работа с matWorld, а потом пакетная работа с nbDoTransform (где t_submesh - это массив или, извиняюсь за выражение, std::vector) - лучше разнести на 2 структуры.
Сначала обрабатывать массив с matWorld, потом - массив с nbDoTransform.
еще бы было интересно попрофайлить на pad с выравниванием на 64 байта.
KVaks
Долго соображал, потом до меня дошло. Компилятор CW тебе не даст сделать pad на 64 байта, так как стандартный аллокатор выдает тебе адреса, кратные только 16 байтам. Соответственно, структуры с таким выравниванием надо или только создавать в стеке (там будет правильно), либо принудительно пользоваться для их обработки вызовов memalign().
Даже если удастся изнасиловать компилятор и заставить его это делать, потери от "рваного" распределения памяти (как внутри самих структур, так и внутри memory manager) будут уже слишком велики. ИМХО.
Димка
Ась??
Update: ну полюбому, а кто-то пользуется malloc?
я - нет, у меня custom new по типу stack alloc c маркерами.
там принудительно задается align.
p.s. а на вызов malloc у меня все падает. почему - не знаю. желания разбираться не должно быть :)
Димка
в случае статик __attribute__((aligned(64))) ?:)
в случае динамик конечно же memalign
для особых извращенцев :) :
vifDma = new(memalign(64,sizeof(wglGfxDma)))wglGfxDma(SCE_DMA_VIF1,VIF1_BUFFER_SIZE);
vifDma->m_DmacHandlerId = AddDmacHandler(DMAC_VIF1,DmaInterruptHandler,0);
:)
neteraser
Вот почему-то всегда, когда я сравниваю malloc с new, меня перестают понимать :)
А у них тем не менее общий heap, и память они выдают из него, выровненную на 16 байт.
Так что даже если написать у структуры (или у поля структуры) aligned(64), а потом распределить ее по new, все накроется.
То есть надо писать либо custom allocator, либо напрямую пользоваться memalign(64).
А общий аллокатор new переопределять на 64-байта выравнивания - очень нерациональная трата оперативной памяти.
Димка
> А общий аллокатор new переопределять на 64-байта выравнивания - очень нерациональная трата оперативной памяти.
А не надо такое. Надо new (user, 64) byte [64]; user - map, 64 - align. Т.е. всегда указывать и следить.
Тема в архиве.