std:: hardware_destructive_interference_size, std:: hardware_constructive_interference_size
From cppreference.net
|
Определено в заголовочном файле
<new>
|
||
|
inline
constexpr
std::
size_t
hardware_destructive_interference_size = /*определяется реализацией*/ ; |
(1) | (начиная с C++17) |
|
inline
constexpr
std::
size_t
hardware_constructive_interference_size = /*определяется реализацией*/ ; |
(2) | (начиная с C++17) |
1)
Минимальное смещение между двумя объектами для предотвращения ложного разделения. Гарантированно не менее
alignof
(
std::
max_align_t
)
struct keep_apart { alignas(std::hardware_destructive_interference_size) std::atomic<int> cat; alignas(std::hardware_destructive_interference_size) std::atomic<int> dog; };
2)
Максимальный размер смежной памяти для обеспечения истинного разделения. Гарантированно не менее
alignof
(
std::
max_align_t
)
struct together { std::atomic<int> dog; int puppy; }; struct kennel { // Other data members... alignas(sizeof(together)) together pack; // Other data members... }; static_assert(sizeof(together) <= std::hardware_constructive_interference_size);
Примечания
Эти константы предоставляют портативный способ доступа к размеру строки кэша данных L1.
| Макрос тестирования возможностей | Значение | Стандарт | Функция |
|---|---|---|---|
__cpp_lib_hardware_interference_size
|
201703L
|
(C++17) |
constexpr
std
::
hardware_constructive_interference_size
и
constexpr std :: hardware_destructive_interference_size |
Пример
Программа использует два потока, которые атомарно записывают в члены данных заданных глобальных объектов. Первый объект помещается в одну кэш-линию, что приводит к "аппаратному вмешательству". Второй объект хранит свои члены данных на отдельных кэш-линиях, благодаря чему избегается возможная "синхронизация кэша" после записи потоков.
Запустить этот код
#include <atomic> #include <chrono> #include <cstddef> #include <iomanip> #include <iostream> #include <mutex> #include <new> #include <thread> #ifdef __cpp_lib_hardware_interference_size using std::hardware_constructive_interference_size; using std::hardware_destructive_interference_size; #else // 64 байта на x86-64 │ L1_CACHE_BYTES │ L1_CACHE_SHIFT │ __cacheline_aligned │ ... constexpr std::size_t hardware_constructive_interference_size = 64; constexpr std::size_t hardware_destructive_interference_size = 64; #endif std::mutex cout_mutex; constexpr int max_write_iterations{10'000'000}; // настройка времени бенчмарка struct alignas(hardware_constructive_interference_size) OneCacheLiner // занимает одну строку кэша { std::atomic_uint64_t x{}; std::atomic_uint64_t y{}; } oneCacheLiner; struct TwoCacheLiner // занимает две строки кэша { alignas(hardware_destructive_interference_size) std::atomic_uint64_t x{}; alignas(hardware_destructive_interference_size) std::atomic_uint64_t y{}; } twoCacheLiner; inline auto now() noexcept { return std::chrono::high_resolution_clock::now(); } template<bool xy> void oneCacheLinerThread() { const auto start{now()}; for (uint64_t count{}; count != max_write_iterations; ++count) если constexpr (xy) oneCacheLiner.x.fetch_add(1, std::memory_order_relaxed); else oneCacheLiner.y.fetch_add(1, std::memory_order_relaxed); const std::chrono::duration (Примечание: В данном случае переводить нечего, так как текст состоит исключительно из HTML-разметки и C++ терминов, которые согласно инструкциям не подлежат переводу. Единственный возможный для перевода элемент "std::chrono::duration" является C++ специфическим термином и должен остаться без изменений.)<double, std::milli> elapsed{now() - start}; std::lock_guard lk{cout_mutex}; std::cout << "oneCacheLinerThread() потратил " << elapsed.count() << " мс\n"; if constexpr (xy) oneCacheLiner.x = elapsed.count(); else oneCacheLiner.y = elapsed.count(); } template<bool xy> void twoCacheLinerThread() { const auto start{now()}; for (uint64_t count{}; count != max_write_iterations; ++count) if constexpr (xy) twoCacheLiner.x.fetch_add(1, std::memory_order_relaxed); else twoCacheLiner.y.fetch_add(1, std::memory_order_relaxed); const std::chrono::duration (Примечание: В данном случае переводить нечего, так как текст состоит исключительно из HTML-разметки и C++ терминологии, которая согласно инструкциям не подлежит переводу. Весь контент находится внутри HTML-тегов и содержит технические термины C++, включая пространства имен std::chrono и тип duration)<double, std::milli> elapsed{now() - start}; std::lock_guard lk{cout_mutex}; std::cout << "twoCacheLinerThread() потратил " << elapsed.count() << " мс\n"; if constexpr (xy) twoCacheLiner.x = elapsed.count(); else twoCacheLiner.y = elapsed.count(); } int main() { std::cout << "__cpp_lib_hardware_interference_size " # ifdef __cpp_lib_hardware_interference_size "= " << __cpp_lib_hardware_interference_size << '\n'; # else "не определено, используйте " << hardware_destructive_interference_size << " как резервный вариант\n"; # endif std::cout << "hardware_destructive_interference_size == " << hardware_destructive_interference_size << '\n' << "hardware_constructive_interference_size == " << hardware_constructive_interference_size << "\n\n" << std::fixed << std::setprecision(2) << "sizeof( OneCacheLiner ) == " << sizeof(OneCacheLiner) << '\n' << "sizeof( TwoCacheLiner ) == " << sizeof(TwoCacheLiner) << "\n\n"; constexpr int max_runs{4}; int oneCacheLiner_average{0}; for (auto i{0}; i != max_runs; ++i) { std::thread th1{oneCacheLinerThread<0>}; std::thread th2{oneCacheLinerThread<1>}; th1.join(); th2.join(); oneCacheLiner_average += oneCacheLiner.x + oneCacheLiner.y; } std::cout << "Среднее время T1: " << (oneCacheLiner_average / max_runs / 2) << " мс\n\n"; int twoCacheLiner_average{0}; for (auto i{0}; i != max_runs; ++i) { std::thread th1{twoCacheLinerThread<0>}; std::thread th2{twoCacheLinerThread<1>}; th1.join(); th2.join(); twoCacheLiner_average += twoCacheLiner.x + twoCacheLiner.y; } std::cout << "Среднее время T2: " << (twoCacheLiner_average / max_runs / 2) << " мс\n\n" << "Отношение T1/T2:~ " << 1.0 * oneCacheLiner_average / twoCacheLiner_average << '\n'; }
Возможный вывод:
__cpp_lib_hardware_interference_size = 201703 hardware_destructive_interference_size == 64 hardware_constructive_interference_size == 64 sizeof( OneCacheLiner ) == 64 sizeof( TwoCacheLiner ) == 128 oneCacheLinerThread() занял 517.83 мс oneCacheLinerThread() занял 533.43 мс oneCacheLinerThread() занял 527.36 мс oneCacheLinerThread() занял 555.69 мс oneCacheLinerThread() занял 574.74 мс oneCacheLinerThread() занял 591.66 мс oneCacheLinerThread() занял 555.63 мс oneCacheLinerThread() занял 555.76 мс Среднее время T1: 550 мс twoCacheLinerThread() занял 89.79 мс twoCacheLinerThread() занял 89.94 мс twoCacheLinerThread() занял 89.46 мс twoCacheLinerThread() занял 90.28 мс twoCacheLinerThread() занял 89.73 мс twoCacheLinerThread() занял 91.11 мс twoCacheLinerThread() занял 89.17 мс twoCacheLinerThread() занял 90.09 мс Среднее время T2: 89 мс Отношение T1/T2:~ 6.16
Смотрите также
|
[static]
|
возвращает количество параллельных потоков, поддерживаемых реализацией
(публичная статическая функция-член
std::thread
)
|
|
[static]
|
возвращает количество параллельных потоков, поддерживаемых реализацией
(публичная статическая функция-член
std::jthread
)
|