Descomposició de dades · 5.3
Padding contra el false sharing
El padding afegeix espai perquè les dades de threads diferents caiguin en línies de caché separades. El veuràs aplicat a structs i a vectors petits de control.
Conceptes clau
- Padding en structs
- Padding en vectors (
vec[id * PAD]) - Cost en memòria del padding
línia de cache escrita per més d'un fil
A més d’alinear BS a la línia de caché, podem aplicar padding directament a les estructures de dades per garantir que elements de threads diferents ocupin línies separades.
Padding en structs
L’objectiu és que cada instància d’struct ocupi exactament un múltiple de la línia de caché. S’afegeix un camp padding dins l’struct per omplir fins al proper múltiple:
#define CL <cache_line_size_bytes>
struct telem {
<camps_utils>
char padding[CL - (sizeof(<camps_utils>) % CL)];
}; // Utilitzem char pq ocupa 1 byte, aixi controlem els bytes de padding
Sense padding, els elements de struct telem arr[4] comparteixen línia (T0 i T1); amb el camp padding, cada instància queda alineada a una línia de caché i desapareixen les zones de false sharing. (figura al dossier, p. 26)
Padding en vectors
Quan threads escriuen a posicions contigües d’un vector compartit type vec[nt], diversos elements poden caure en la mateixa línia de caché, causant false sharing. Per evitar-ho, es separen els elements amb un factor PAD igual al nombre d’elements per línia de caché.
#define CL <cache_line_size_bytes>
#define PAD (CL / sizeof(type))
type vec[nt * PAD]; // cada thread a una linia diferent
// Acces: vec[id * PAD] en lloc de vec[id]
Sense padding, vec[0]…vec[3] cauen a la mateixa línia de caché (false sharing!); amb padding, cada element ocupa una línia de caché sencera. (figura al dossier, p. 26)
El padding augmenta l’ús de memòria (la major part de l’array és espai buit), però en vectors petits de control com comptadors o sumes parcials, el cost és negligible comparat amb la millora de rendiment.