std::hardware_destructive_interference_size, std::hardware_constructive_interference_size
Материал из cppreference.com
Определено в заголовочном файле <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 { // Другие элементы данных... alignas(sizeof(together)) together pack; // Другие элементы данных... }; static_assert(sizeof(together) <= std::hardware_constructive_interference_size);
[править] Примечание
Эти константы обеспечивают переносимый способ доступа к размеру строки кэша данных L1.
Макрос Тестирования функциональности | Значение | Стандарт | Функциональность |
---|---|---|---|
__cpp_lib_hardware_interference_size |
201703L | (C++17) | constexpr std::hardware_constructive_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) if 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<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<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::cout << std::fixed <<