Выравнивание линии кэша (требуется разъяснение по статье)
недавно я столкнулся с тем, что я думаю, является проблемой ложного обмена в моем приложении, и я посмотрел статья Саттера о том, как выровнять мои данные в кэш-линии. Он предлагает следующий C++ код:
// C++ (using C++0x alignment syntax)
template<typename T>
struct cache_line_storage {
[[ align(CACHE_LINE_SIZE) ]] T data;
char pad[ CACHE_LINE_SIZE > sizeof(T)
? CACHE_LINE_SIZE - sizeof(T)
: 1 ];
};
Я вижу, как это будет работать, когда CACHE_LINE_SIZE > sizeof(T)
истинно -- The struct cache_line_storage
просто заканчивается тем, что занимает одну полную строку кэша памяти. Однако, когда sizeof(T)
больше, чем одна строка кэша, я бы подумал, что мы должны заполнить данные CACHE_LINE_SIZE - T % CACHE_LINE_SIZE
байт, так что результирующая структура имеет размер, который является интегральным кратным размеру строки кэша. Что не так с моим пониманием? Почему достаточно заполнения 1 байтом?
3 ответов
у вас не может быть массивов размером 0, поэтому для его компиляции требуется 1. Однако текущая черновая версия спецификации говорит, что такое заполнение не требуется; компилятор должен заполнять до выравнивания структуры.
Обратите также внимание, что этот код плохо сформирован, если CACHE_LINE_SIZE
меньше, чем alignof(T)
. Чтобы исправить это, вы, вероятно, должны использовать [[align(CACHE_LINE_SIZE), align(T)]]
, что обеспечит меньшую расклад не брал.
представьте себе,
#define CACHE_LINE_SIZE 32
sizeof(T) == 48
Теперь рассмотрим, как [[ align(CACHE_LINE_SIZE) ]]
, работает. например:
[[ align(32) ]] Foo foo;
это sizeof(Foo) == 32n
для некоторых n
. ie align () будет прокладкой для вас, если необходимо, для таких вещей, как Foo foo[10];
для каждого foo[i]
выровнено по запросу.
так, в нашем случае с sizeof(T) == 48
, это значит sizeof(cache_line_storage<T>) == 64
.
таким образом, выравнивание дает вам дополнение, на которое вы надеялись.
однако, это одна "ошибка" в шаблоне. Рассмотрим этот случай:
#define CACHE_LINE_SIZE 32
sizeof(T) == 32
здесь мы заканчиваем с char pad[1];
. Что означает sizeof(cache_line_storage<T>) == 64
. Наверное, не то, что ты хочешь!
Я думаю, что шаблон должен быть несколько изменен:
template <typename T, int padding>
struct pad_or_not
{
T data;
char pad[padding];
};
// specialize the 0 case
// As it is late, I am SURE I've got the specialization syntax wrong...
template <typename T, int>
struct pad_or_not<0>
{
T data;
};
template<typename T>
struct cache_line_storage {
[[ align(CACHE_LINE_SIZE) ]] pad_or_not<T, (sizeof(T) > CACHE_LINE_SIZE ? 0 : CACHE_LINE_SIZE - sizeof(T) ) > data;
};
или что-то в этом роде.
"У вас не может быть массивов размером 0, поэтому для его компиляции требуется 1" - GNU C разрешает массивы с нулевым размером. См. также http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Zero-Length.html