Выравнивание строк кэша (требуется уточнение по статье) - PullRequest
9 голосов
/ 16 ноября 2009

Недавно я столкнулся с проблемой ложного обмена в моем приложении, и я просмотрел статью Саттера о том, как выровнять мои данные по строкам кэша. Он предлагает следующий код 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) истинно - структура cache_line_storage просто заканчивается тем, что занимает одну полную строку кэша памяти. Однако, когда sizeof(T) больше, чем одна строка кэша, я думаю, что мы должны дополнить данные CACHE_LINE_SIZE - T % CACHE_LINE_SIZE байтами, чтобы полученная структура имела размер, который является целым кратным размеру строки кэша. Что не так с моим пониманием? Почему достаточно заполнения с 1 байтом?

Ответы [ 3 ]

7 голосов
/ 16 ноября 2009

У вас не может быть массивов размера 0, поэтому для его компиляции требуется 1. Тем не менее, текущий черновой вариант спецификации говорит, что такие дополнения не нужны; компилятор должен дополнить выравнивание структуры.

Также обратите внимание, что этот код некорректен, если CACHE_LINE_SIZE меньше alignof(T). Чтобы исправить это, вам, вероятно, следует использовать [[align(CACHE_LINE_SIZE), align(T)]], что гарантирует, что меньшее выравнивание никогда не будет выбрано.

3 голосов
/ 17 ноября 2009

Представьте себе

#define CACHE_LINE_SIZE 32
sizeof(T) == 48

Теперь рассмотрим, как работает [[ align(CACHE_LINE_SIZE) ]]. например:

[[ align(32) ]] Foo foo;

Это заставит sizeof(Foo) == 32n для некоторых n. то есть 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 голосов
/ 25 августа 2010

«У вас не может быть массивов размера 0, поэтому для компиляции требуется 1» - GNU C разрешает массивы с нулевым размером. Смотри также http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Zero-Length.html

...