std:: hardware_destructive_interference_size, std:: hardware_constructive_interference_size
From cppreference.net
C++
Concurrency support library
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
定義済みヘッダー
<new>
|
||
|
inline
constexpr
std::
size_t
hardware_destructive_interference_size = /*implementation-defined*/ ; |
(1) | (C++17以降) |
|
inline
constexpr
std::
size_t
hardware_constructive_interference_size = /*implementation-defined*/ ; |
(2) | (C++17以降) |
1)
偽共有を避けるための2つのオブジェクト間の最小オフセット。少なくとも
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
および
constexpr std :: hardware_destructive_interference_size |
例
このプログラムは、与えられたグローバルオブジェクトのデータメンバーに対してアトミック書き込みを行う2つのスレッドを使用します。最初のオブジェクトは1つのキャッシュラインに収まるため、「ハードウェア干渉」が発生します。2番目のオブジェクトはデータメンバーを別々のキャッシュラインに保持するため、スレッド書き込み後の「キャッシュ同期」の可能性が回避されます。
このコードを実行
#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
// x86-64上の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 // 1つのキャッシュラインを占有する
{
std::atomic_uint64_t x{};
std::atomic_uint64_t y{};
}
oneCacheLiner;
struct TwoCacheLiner // 2つのキャッシュラインを占有する
{
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
(注:指示に従い、HTMLタグ・属性、C++固有用語、タグ内のテキストは翻訳せず、元のフォーマットを保持しています)(); }
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() << " ms\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() << " ms\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) << " ms\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) << " ms\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 ms oneCacheLinerThread() 所要時間: 533.43 ms oneCacheLinerThread() 所要時間: 527.36 ms oneCacheLinerThread() 所要時間: 555.69 ms oneCacheLinerThread() 所要時間: 574.74 ms oneCacheLinerThread() 所要時間: 591.66 ms oneCacheLinerThread() 所要時間: 555.63 ms oneCacheLinerThread() 所要時間: 555.76 ms 平均 T1 時間: 550 ms twoCacheLinerThread() 所要時間: 89.79 ms twoCacheLinerThread() 所要時間: 89.94 ms twoCacheLinerThread() 所要時間: 89.46 ms twoCacheLinerThread() 所要時間: 90.28 ms twoCacheLinerThread() 所要時間: 89.73 ms twoCacheLinerThread() 所要時間: 91.11 ms twoCacheLinerThread() 所要時間: 89.17 ms twoCacheLinerThread() 所要時間: 90.09 ms 平均 T2 時間: 89 ms 比率 T1/T2: ~6.16
関連項目
|
[static]
|
実装によってサポートされる同時実行スレッドの数を返す
(
std::thread
のpublic staticメンバー関数)
|
|
[static]
|
実装によってサポートされる同時実行スレッドの数を返す
(
std::jthread
のpublic staticメンバー関数)
|