[C++] есть ли смысл в выравнивании на Intel ?
Нагуглилось:
http://lemire.me/blog/archives/2012/05/31/data-alignment-for...
читать включая комментарии, в них едва ли не половина всего интересного.
В связи с этим накладываю еще одно ограничение : пусть моя структура лежит в одной кеш-линии и плохо выровнена. Какие проблемы тем не менее возможны?на новых x86 похоже никаких, но есть ещё странный atom который может чудить.
проблемы:
* дырки в структурах. неэффективное использование памяти и кэшей
* разный layout между i386 и x86_64
если выключить выравнивание
* не все архитектуры позволяют не выравненный доступ, компилятор начнёт городить плохой код или получишь SIGBUS
* производительность всё-же упадёт, хотя бы из-за удвоения cache misses в некоторых случаях
* load/store станут совсем неатомарными
* производительность всё-же упадёт, хотя бы из-за удвоения cache misses в некоторых случаяхв каком случае упадет? можно примерчик описать? напоминаю, что моя структура все же в кеш влезает по условию
Нагуглилось:в общем, я тоже не вижу проблем. хотя автор блога мог бы потестить offset 61, 62, 63, чтобы увидеть проседание скорости из-за расползания инта по двум кеш-линиям
И еще random access неплохо бы потестить, а не последовательный доступ.
Афтар небельмесе в тестировании таких подводных камней.
Если переделать код на рандомное вытаскивание данных из памяти, - апа ! получаем 2х прирост производительности.
в каком случае упадет? можно примерчик описать? напоминаю, что моя структура все же в кеш влезает по условиюЕсли влазит то cache miss будет конечно один.
Мне кажется измерять скорость одной инструкции бесполезно, это какой-то сферический конь.
Если брать какой-то кусок то инструкции явно разобьются на большее число операций и как-то иначе распределятся конвейером.
Если чего-то не хватит или появятся конфликты и параллелизм упадёт то и производительность тоже упадёт.
Нужен некий цикл который на каждом такте нагружает почти все блоки и в нём уже сломать выравнивание.
* load/store станут совсем неатомарнымина самом деле это важное замечание т.к. влияет на корректность многопоточного приложения
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <time.h>
#define TEST_ALIGNED 0
#define REPEAT_COUNT 10000
uint16_t indexes[100000];
uint32_t data1[32768];
uint32_t data2[32768];
uint32_t data3[32768];
uint32_t data4[32768];
uint32_t accumulate_non_aligned(uint8_t *data1, uint8_t *data2, uint8_t *data3,
uint8_t *data4, uint16_t *indexes, uint32_t size, int offset) {
int i, j;
uint32_t result = 0;
for (j=0; j<REPEAT_COUNT; j++) {
for (i=0; i<size; i++) {
result += *volatile uint32_t *data1+indexes[i]*4+offset;
result += *volatile uint32_t *data2+indexes[i]*4+offset;
result += *volatile uint32_t *data3+indexes[i]*4+offset;
result += *volatile uint32_t *data4+indexes[i]*4+offset;
}
}
return result;
}
int main(int argc, char **argv) {
int i;
uint32_t result = 0;
clock_t start, end;
srand(1234);
for (i=0;i<100000;i++) {
indexes[i] = rand % 32766;
// indexes[i] = i % 32766;
}
for (i=0;i<32768;i++) {
data1[i] = rand;
data2[i] = rand;
data3[i] = rand;
data4[i] = rand;
}
for (i = 0; i < 8; i++) {
start = clock;
result = accumulate_non_aligneduint8_t *)data1, (uint8_t *)data2,
(uint8_t *)data3, (uint8_t *)data4, indexes, 100000, i);
end = clock;
printf("%d: result = %d, time = %0.5f\n", i, result, doubleend-start)/CLOCKS_PER_SEC;
}
return 0;
}
У меня невыровненный доступ получается медленнее всегда, как при последовательном, так и при произвольном доступе.
На Core 2 E8400 невыровненный на 35% медленнее при произвольном и на 20% при последовательном.
На Core i7 3770K на 10% и 5% соответственно.
Ни твоих 100%, ни авторовских 0% у меня воспроизвести не получилось.
на самом деле это важное замечание т.к. влияет на корректность многопоточного приложенияугу, тут недавно был трэд который вылился в два патча в гцц и один в ядро
В связи с этим накладываю еще одно ограничение : пусть моя структура лежит в одной кеш-линии и плохо выровнена.Как ты собираешься гарантировать первое без избавления от второго? Или так, подрочить кругообразно хочется?
но непонятно нафига всё это — пересортировав поля можно всё выравнять.
пересортировав поля можно всё выравнятьодин задал непонятный вопрос, второй дал непонятный ответ
не представляю как сортировка полей может повлиять на выравнивание она может повлиять на размер структуры, на паддинги между полями, но никак не на требование к выравниванию
пример структуры, которая влазит в кеш-линию, но которая может быть размещена с нарушением требований выравнивания:
struct A
{
int x;
};
// требование к выравниванию скорее всего "адрес кратен 4"
void * address = // такой адрес, что % cache_line_size == 1;
new (address) A;
A* a = (A*) address; // плохо выровненный объект, помещающийся в кеш-линию
не проще ли его выпрямить чтоб он выравнивал адреса хотя бы на 8 байт вместо
того чтоб упарываться с этим выраванием потом.
В ядре повсюду пару младших бит поинтеров используют под разные интересные нужды
то фражок туда такой воткнут то вообще бит-спинлок. А если где-то вылазит нечётный
поинтер (кроме некторых char *) то это сразу сигнализирует о баге или каррапшне.
у тебя есть специальный кривой аллокатор?есть. собственно вопрос изначальный в том и состоит - надо ли его выпрямлять
не проще ли его выпрямить
чтоб он выравнивал адреса хотя бы на 8 байтпланку надо поднять до 16 : http://liveworkspace.org/code/3ASJEy%242
если не знаешь на каких машинах в будущем этот код будет работать то лучше выправить.
если не знаешь на каких машинахя знаю, это в первом посте указано
я знаю, это в первом посте указанотогда забей
Оставить комментарий
Maurog
а есть ли реальный смысл в выравнивании данных на современных интелах? более конкретно:пусть у меня есть некая структура типа
и я ее "криво" размещаю в памяти (нарушая правило выравнивания)
с какими реальными проблемами я могу столкнуться? это интересно как с точки зрения корректности работы программы, так и с точки зрения перформанса. если такие случаи есть, то хотелось бы их воспроизвести
опытным путем было выяснено, что чтение int работает с одинаковой скоростью независимо от его выравнивания, однако проседание скорости чтения было отмечено при размазывании int по двум кеш-линиям. В связи с этим накладываю еще одно ограничение : пусть моя структура лежит в одной кеш-линии и плохо выровнена. Какие проблемы тем не менее возможны?