SeniorПроизводительностьИногдаЕщё не отвечали
Что такое false sharing и как его устранить?
False sharing — когда два потока пишут в разные переменные, попавшие на одну кэш-линию: каждая запись инвалидирует копию у другого ядра, вызывая ping-pong линии. Лечится выравниванием горячих данных на std::hardware_destructive_interference_size.
- ✗Путать false sharing с настоящей гонкой данных — это баг производительности, не ошибка логики
- ✗Упаковывать счётчики потоков в плотный массив или структуру, так что соседние элементы делят кэш-линию
- ✗Хардкодить 64 как размер линии вместо
hardware_destructive_interference_size
- →Как обнаружить false sharing с помощью
perfили VTune? - →Что такое true sharing и почему паддинг его не лечит?
Оглавление
Что происходит
Кэш когерентен на уровне кэш-линий (обычно 64 байта), а не отдельных байт. Если две переменные лежат на одной линии, запись в любую из них помечает всю линию как изменённую и инвалидирует копию у других ядер — даже если потоки логически независимы.
struct Counters {
std::atomic<long> a; // оба поля
std::atomic<long> b; // на одной кэш-линии
};
Counters c;
// Поток 1: цикл c.a.fetch_add(1)
// Поток 2: цикл c.b.fetch_add(1)
// Логически независимы, но линия пинг-понгует между ядрами.
Как чинить
Развести горячие поля по разным линиям через выравнивание:
struct Counters {
alignas(std::hardware_destructive_interference_size)
std::atomic<long> a;
alignas(std::hardware_destructive_interference_size)
std::atomic<long> b;
};
Или ручной паддинг, если константа недоступна:
struct alignas(64) PaddedCounter {
std::atomic<long> value;
char pad[64 - sizeof(std::atomic<long>)];
};
Замечания
- Это не проблема корректности: программа без паддинга считает правильно, просто медленно. Поэтому false sharing трудно заметить без профилировщика.
- Цена — память: каждый паддинг тратит до линии на объект, поэтому выравнивают только реально горячие, конкурентно записываемые данные.
hardware_destructive_interference_size— минимальное смещение, гарантирующее отсутствие false sharing;hardware_constructive_interference_size— наоборот, максимальный размер для совместного размещения.
Оглавление