Код: Выделить всё
#include
#include
#include
template
struct S {
T a;
T b;
T c;
T d;
};
template
struct A {
alignas(64) T a;
alignas(64) T b;
alignas(64) T c;
alignas(64) T d;
};
template
void test(benchmark::State& state) {
S s;
for (auto&& _ : state) {
std::jthread ta([&] { for (int i = 0; i < 10000; i++) s.a++; });
std::jthread tb([&] { for (int i = 0; i < 10000; i++) s.b++; });
std::jthread tc([&] { for (int i = 0; i < 10000; i++) s.c++; });
std::jthread td([&] { for (int i = 0; i < 10000; i++) s.d++; });
}
}
BENCHMARK(test);
BENCHMARK(test);
BENCHMARK(test);
BENCHMARK(test);
BENCHMARK_MAIN();
Код: Выделить всё
$ g++ -o false_sharing false_sharing.cpp -lbenchmark -std=c++20
$ ./false_sharing
Running ./false_sharing
Run on (20 X 2995.2 MHz CPU s)
CPU Caches:
L1 Data 48 KiB (x10)
L1 Instruction 32 KiB (x10)
L2 Unified 1280 KiB (x10)
L3 Unified 24576 KiB (x1)
Load Average: 0.17, 0.14, 0.05
--------------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------------
test 106807 ns 79044 ns 8911
test 102056 ns 78521 ns 8948
test 545677 ns 89455 ns 7690
test 166520 ns 84400 ns 8212
В этом вопросе я предполагаю x86, на котором проводится тест (i9-13900H). Информация о других архитектурах также приветствуется.
Насколько я понимаю, мы не можем иметь одну и ту же строку кэша более чем в одном ядре кэша, независимо от базовых данных. Можно применить некоторые оптимизации, но, в конце концов, если два ядра изменяют одну и ту же строку кэша, строка кэша текущего ядра должна быть перенесена в общий кэш (L2) или основную память (если она загрязнена) и перейдет в кэш L1 другого ядра.
В каких именно ситуациях эффект ложного разделения становится очевидным?
Подробнее здесь: https://stackoverflow.com/questions/791 ... mic-values