偽共有のパフォーマンスへの影響をテストしようとしています。テストコードは以下のとおりです。
constexpr uint64_t loop = 1000000000;
struct no_padding_struct {
no_padding_struct() :x(0), y(0) {}
uint64_t x;
uint64_t y;
};
struct padding_struct {
padding_struct() :x(0), y(0) {}
uint64_t x;
char padding[64];
uint64_t y;
};
alignas(64) volatile no_padding_struct n;
alignas(64) volatile padding_struct p;
constexpr core_a = 0;
constexpr core_b = 1;
void func(volatile uint64_t* addr, uint64_t b, uint64_t mask) {
SetThreadAffinityMask(GetCurrentThread(), mask);
for (uint64_t i = 0; i < loop; ++i) {
*addr += b;
}
}
void test1(uint64_t a, uint64_t b) {
thread t1{ func, &n.x, a, 1<<core_a };
thread t2{ func, &n.y, b, 1<<core_b };
t1.join();
t2.join();
}
void test2(uint64_t a, uint64_t b) {
thread t1{ func, &p.x, a, 1<<core_a };
thread t2{ func, &p.y, b, 1<<core_b };
t1.join();
t2.join();
}
int main() {
uint64_t a, b;
cin >> a >> b;
auto start = std::chrono::system_clock::now();
//test1(a, b);
//test2(a, b);
auto end = std::chrono::system_clock::now();
cout << (end - start).count();
}
その結果、おおむね次のようになりました。
x86 x64
cores test1 test2 cores test1 test2
debug release debug release debug release debug release
0-0 4.0s 2.8s 4.0s 2.8s 0-0 2.8s 2.8s 2.8s 2.8s
0-1 5.6s 6.1s 3.0s 1.5s 0-1 4.2s 7.8s 2.1s 1.5s
0-2 6.2s 1.8s 2.0s 1.4s 0-2 3.5s 2.0s 1.4s 1.4s
0-3 6.2s 1.8s 2.0s 1.4s 0-3 3.5s 2.0s 1.4s 1.4s
0-5 6.5s 1.8s 2.0s 1.4s 0-5 3.5s 2.0s 1.4s 1.4s
私のCPUはintel core i7-9750h
です。「core0」と「core1」は物理コアであり、「core2」と「core3」なども同様です。コンパイラは MSVC 14.24 を使用しました。
記録された時間は、多数のバックグラウンド タスクがあったため、複数回の実行での最高スコアのおおよその値です。結果は明確にグループに分けられ、0.1 秒~0.3 秒の誤差はグループ分けに影響を与えなかったので、これは十分公平だったと思います。
Test2 の説明は非常に簡単でした。x
とは異なるキャッシュ ラインにあるためy
、2 つの物理コアで実行するとパフォーマンスが 2 倍向上します (シングル コアで 2 つのスレッドを実行する場合のコンテキスト スイッチのコストはここでは無視できます)。物理コア、coffee-lake のスループットによって制限され (Ryzen の方がわずかに優れていると信じています)、一時的なマルチスレッドよりも効率的です。ここでは 64bit モードの方が効率が良いようです。
しかし、test1 の結果はわかりにくいです。まず、デバッグ モードでは、0-2、0-3、および 0-5 は 0-0 よりも遅く、これは理にかなっています。これは、特定のデータが L1 から L3 へ、L3 から L1 へと繰り返し移動されるためであると説明しました。これは、キャッシュが 2 つのコア間で一貫性を保つ必要があるためです。一方、単一のコアで実行している場合、キャッシュは常に L1 にとどまります。しかし、この理論は、0-1 ペアが常に最も遅いという事実と矛盾します。技術的には、2 つのスレッドは同じ L1 キャッシュを共有する必要があります。0-1 は 0-0 の 2 倍の速さで実行する必要があります。
次に、リリース モードでは、0-2、0-3、および 0-5 が 0-0 よりも高速であり、上記の理論が反証されました。
最後に、0-1 は64 ビット モードと 32 ビット モードの両方でrelease
より遅く実行されます。debug
それが一番理解できない。生成されたアセンブリ コードを読みましたが、何も役に立ちませんでした。