2009-11-16 14 views
9

J'ai récemment rencontré ce que je pense être un faux problème de partage dans mon application, et j'ai recherché Sutter's article sur la façon d'aligner mes données sur les lignes de cache. Il suggère le code C++ suivant:Alignement de la ligne de cache (Besoin de clarification sur l'article)

// 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 ]; 
}; 

Je peux voir comment cela fonctionnerait quand CACHE_LINE_SIZE > sizeof(T) est vrai - la struct cache_line_storage termine juste en prenant une ligne complète de cache de la mémoire. Cependant, lorsque le sizeof(T) est plus grand qu'une seule ligne de cache, je pense que nous devrions tamponner les données par CACHE_LINE_SIZE - T % CACHE_LINE_SIZE octets, de sorte que la structure résultante ait une taille qui soit un multiple entier de la taille de la ligne de cache. Quel est le problème avec ma compréhension? Pourquoi le remplissage avec 1 octet suffit-il?

Répondre

7

Vous ne pouvez pas avoir de tableaux de taille 0, donc 1 est requis pour le compiler. Cependant, la version actuelle de la spécification dit qu'un tel rembourrage n'est pas nécessaire; le compilateur doit aller jusqu'à l'alignement de la structure. Notez également que ce code est mal formé si CACHE_LINE_SIZE est inférieur à alignof(T). Pour résoudre ce problème, vous devez probablement utiliser [[align(CACHE_LINE_SIZE), align(T)]], ce qui garantit qu'un alignement plus petit n'est jamais sélectionné.

+0

+1, bien que, en pratique, je ne connaisse aucun cas où un alignement struct peut être supérieur à la taille de la cacheline. Après tout, les contraintes d'alignement de type proviennent généralement des contraintes de la ligne de commande. – Bahbar

+1

L'alignement est-il appliqué à la structure ou au premier élément de la structure dans votre suggestion? –

+1

Mais quant à la mécanique du faux-partage lui-même ... pour l'empêcher, ne devrait-on pas aligner T sur un multiple entier de la taille de la ligne de cache, même si 'sizeof (T)> CACHE_LINE_SIZE'? Ou n'est-ce pas nécessaire? – int3

3

Imaginer

#define CACHE_LINE_SIZE 32 
sizeof(T) == 48 

Maintenant, examiner comment [[ align(CACHE_LINE_SIZE) ]], fonctionne. par exemple:

[[ align(32) ]] Foo foo; 

Cela forcera sizeof(Foo) == 32n pour certains n. ie align() remplira pour vous, si nécessaire, pour que des choses comme Foo foo[10]; soient alignées sur chaque foo[i] comme demandé. Ainsi, dans notre cas, avec sizeof(T) == 48, cela signifie sizeof(cache_line_storage<T>) == 64. Donc, l'alignement vous donne le rembourrage que vous espériez.

Cependant, il s'agit d'une 'erreur' dans le modèle. Considérez ce cas:

#define CACHE_LINE_SIZE 32 
sizeof(T) == 32 

nous finissons ici avec char pad[1];. Ce qui signifie sizeof(cache_line_storage<T>) == 64. Probablement pas ce que tu veux!

Je pense que le modèle devrait être quelque peu modifié:

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; 
}; 

ou quelque chose comme ça.