Supermicro X11DPH-Iマザーボードを搭載した2x Xeon Gold 6154 CPUと96GB RAMを使用してサーバーをテストしましたが、1 CPU(1ソケットが空)、同様のデュアルCPU Haswell Xeon E5-2687Wv3(この一連のテスト用ですが、他のBroadwellは同様に動作します)、Broadwell-E i7s、およびSkylake-X i9s(比較用)。
さまざまなmemcpy関数やメモリ割り当て(回避策が見つかったため、以下のテストではカバーされていません)に関しては、メモリが高速なSkylake XeonプロセッサはHaswellよりも高速に実行されることが予想されますが、代わりに両方のCPUがインストールされています、Skylake XeonsはHaswell Xeonsのほぼ半分の速度で動作し、i7-6800kと比較するとさらに遅くなります。さらに奇妙なのは、Windows VirtualAllocExNumaを使用してメモリ割り当て用のNUMAノードを割り当てる場合です。プレーンメモリコピー機能は、リモートノードとローカルノードではパフォーマンスが低下すると予想されますが、SSE、MMX、AVXレジスタを使用するメモリコピー機能は、多くの場合実行しますローカルNUMAノードよりもリモートNUMAノードの方が高速です(何?)。上記のように、Skylake Xeonsでは、
これがマザーボードまたはCPUのバグなのか、UPI対QPIのバグなのか、上記のどれなのかはわかりませんが、BIOS設定の組み合わせはこれを利用していないようです。BIOSでNUMA(テスト結果に含まれない)を無効にすると、SSE、MMX、AVXレジスタを使用するすべてのコピー機能のパフォーマンスが向上しますが、他のすべてのプレーンメモリコピー機能も大きな損失を被ります。
テストプログラムでは、インラインアセンブリ関数と_mm
組み込み関数の両方を使用してテストしました。アセンブリ関数を除くすべてに対してVisual Studio 2017でWindows 10を使用しました。msvc++はx64のasmをコンパイルしないため、-c -O2
msvc ++リンカーに含まれているフラグを使用して、objファイルをコンパイルします。
システムがNUMAノードを使用している場合、各NUMAノードに対してVirtualAllocExNumaを使用して新しいメモリ割り当て演算子をテストし、各メモリコピー機能ごとに16 MBのメモリバッファコピーの累積平均を100回行い、どのメモリ割り当てをオンにするかを切り替えますテストの各セット間。
100個のソースバッファと100個の宛先バッファはすべて64バイトに揃えられ(ストリーミング機能を使用したAVX512までの互換性のため)、ソースバッファの増分データと宛先バッファの0xffに一度初期化されます。
一部の構成でははるかに高速で、他の構成でははるかに低速だったため、各構成で各マシンで平均されるコピーの数は異なりました。
結果は次のとおりです。
Haswell Xeon E5-2687Wv3 32GB DDR4-2400(10c / 20t、25 MBのL3キャッシュ)を搭載したSupermicro X10DAi上の1つのCPU(1つの空のソケット)。ただし、ベンチマークは100ペアの16MBバッファーを循環するため、L3キャッシュヒットはおそらく発生しません。
---------------------------------------------------------------------------
Averaging 7000 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy averaging 2264.48 microseconds
asm_memcpy (asm) averaging 2322.71 microseconds
sse_memcpy (intrinsic) averaging 1569.67 microseconds
sse_memcpy (asm) averaging 1589.31 microseconds
sse2_memcpy (intrinsic) averaging 1561.19 microseconds
sse2_memcpy (asm) averaging 1664.18 microseconds
mmx_memcpy (asm) averaging 2497.73 microseconds
mmx2_memcpy (asm) averaging 1626.68 microseconds
avx_memcpy (intrinsic) averaging 1625.12 microseconds
avx_memcpy (asm) averaging 1592.58 microseconds
avx512_memcpy (intrinsic) unsupported on this CPU
rep movsb (asm) averaging 2260.6 microseconds
64GB RAMを搭載したSupermicro X10DAi上のHaswell Dual Xeon E5-2687Wv3 2 CPU
---------------------------------------------------------------------------
Averaging 6900 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 0(local)
---------------------------------------------------------------------------
std::memcpy averaging 3179.8 microseconds
asm_memcpy (asm) averaging 3177.15 microseconds
sse_memcpy (intrinsic) averaging 1633.87 microseconds
sse_memcpy (asm) averaging 1663.8 microseconds
sse2_memcpy (intrinsic) averaging 1620.86 microseconds
sse2_memcpy (asm) averaging 1727.36 microseconds
mmx_memcpy (asm) averaging 2623.07 microseconds
mmx2_memcpy (asm) averaging 1691.1 microseconds
avx_memcpy (intrinsic) averaging 1704.33 microseconds
avx_memcpy (asm) averaging 1692.69 microseconds
avx512_memcpy (intrinsic) unsupported on this CPU
rep movsb (asm) averaging 3185.84 microseconds
---------------------------------------------------------------------------
Averaging 6900 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 1
---------------------------------------------------------------------------
std::memcpy averaging 3992.46 microseconds
asm_memcpy (asm) averaging 4039.11 microseconds
sse_memcpy (intrinsic) averaging 3174.69 microseconds
sse_memcpy (asm) averaging 3129.18 microseconds
sse2_memcpy (intrinsic) averaging 3161.9 microseconds
sse2_memcpy (asm) averaging 3141.33 microseconds
mmx_memcpy (asm) averaging 4010.17 microseconds
mmx2_memcpy (asm) averaging 3211.75 microseconds
avx_memcpy (intrinsic) averaging 3003.14 microseconds
avx_memcpy (asm) averaging 2980.97 microseconds
avx512_memcpy (intrinsic) unsupported on this CPU
rep movsb (asm) averaging 3987.91 microseconds
---------------------------------------------------------------------------
Averaging 6900 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy averaging 3172.95 microseconds
asm_memcpy (asm) averaging 3173.5 microseconds
sse_memcpy (intrinsic) averaging 1623.84 microseconds
sse_memcpy (asm) averaging 1657.07 microseconds
sse2_memcpy (intrinsic) averaging 1616.95 microseconds
sse2_memcpy (asm) averaging 1739.05 microseconds
mmx_memcpy (asm) averaging 2623.71 microseconds
mmx2_memcpy (asm) averaging 1699.33 microseconds
avx_memcpy (intrinsic) averaging 1710.09 microseconds
avx_memcpy (asm) averaging 1688.34 microseconds
avx512_memcpy (intrinsic) unsupported on this CPU
rep movsb (asm) averaging 3175.14 microseconds
Skylake Xeon Gold 6154 48GB DDR4-2666(18c / 36t、24.75 MBのL3キャッシュ)を搭載したSupermicro X11DPH-I上の1 CPU(1つの空のソケット)
---------------------------------------------------------------------------
Averaging 5000 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy averaging 1832.42 microseconds
asm_memcpy (asm) averaging 1837.62 microseconds
sse_memcpy (intrinsic) averaging 1647.84 microseconds
sse_memcpy (asm) averaging 1710.53 microseconds
sse2_memcpy (intrinsic) averaging 1645.54 microseconds
sse2_memcpy (asm) averaging 1794.36 microseconds
mmx_memcpy (asm) averaging 2030.51 microseconds
mmx2_memcpy (asm) averaging 1816.82 microseconds
avx_memcpy (intrinsic) averaging 1686.49 microseconds
avx_memcpy (asm) averaging 1716.15 microseconds
avx512_memcpy (intrinsic) averaging 1761.6 microseconds
rep movsb (asm) averaging 1977.6 microseconds
Skylake Xeon Gold 6154 96GB DDR4-2666を搭載したSupermicro X11DPH-I上の2 CPU
---------------------------------------------------------------------------
Averaging 4100 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 0(local)
---------------------------------------------------------------------------
std::memcpy averaging 3131.6 microseconds
asm_memcpy (asm) averaging 3070.57 microseconds
sse_memcpy (intrinsic) averaging 3297.72 microseconds
sse_memcpy (asm) averaging 3423.38 microseconds
sse2_memcpy (intrinsic) averaging 3274.31 microseconds
sse2_memcpy (asm) averaging 3413.48 microseconds
mmx_memcpy (asm) averaging 2069.53 microseconds
mmx2_memcpy (asm) averaging 3694.91 microseconds
avx_memcpy (intrinsic) averaging 3118.75 microseconds
avx_memcpy (asm) averaging 3224.36 microseconds
avx512_memcpy (intrinsic) averaging 3156.56 microseconds
rep movsb (asm) averaging 3155.36 microseconds
---------------------------------------------------------------------------
Averaging 4100 copies of 16MB of data per function for VirtualAllocExNuma to NUMA node 1
---------------------------------------------------------------------------
std::memcpy averaging 5309.77 microseconds
asm_memcpy (asm) averaging 5330.78 microseconds
sse_memcpy (intrinsic) averaging 2350.61 microseconds
sse_memcpy (asm) averaging 2402.57 microseconds
sse2_memcpy (intrinsic) averaging 2338.61 microseconds
sse2_memcpy (asm) averaging 2475.51 microseconds
mmx_memcpy (asm) averaging 2883.97 microseconds
mmx2_memcpy (asm) averaging 2517.69 microseconds
avx_memcpy (intrinsic) averaging 2356.07 microseconds
avx_memcpy (asm) averaging 2415.22 microseconds
avx512_memcpy (intrinsic) averaging 2487.01 microseconds
rep movsb (asm) averaging 5372.98 microseconds
---------------------------------------------------------------------------
Averaging 4100 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy averaging 3075.1 microseconds
asm_memcpy (asm) averaging 3061.97 microseconds
sse_memcpy (intrinsic) averaging 3281.17 microseconds
sse_memcpy (asm) averaging 3421.38 microseconds
sse2_memcpy (intrinsic) averaging 3268.79 microseconds
sse2_memcpy (asm) averaging 3435.76 microseconds
mmx_memcpy (asm) averaging 2061.27 microseconds
mmx2_memcpy (asm) averaging 3694.48 microseconds
avx_memcpy (intrinsic) averaging 3111.16 microseconds
avx_memcpy (asm) averaging 3227.45 microseconds
avx512_memcpy (intrinsic) averaging 3148.65 microseconds
rep movsb (asm) averaging 2967.45 microseconds
SkySUS-X i9-7940X on ASUS ROG Rampage VI Extreme with 32GB DDR4-4266(14c / 28t、19.25 MB of L3 cache)(overclocked to 3.8GHz / 4.4GHz turbo、DDR at 4040MHz、Target AVX Frequency 3737MHz、Target AVX- 512周波数3535MHz、ターゲットキャッシュ周波数2424MHz)
---------------------------------------------------------------------------
Averaging 6500 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy averaging 1750.87 microseconds
asm_memcpy (asm) averaging 1748.22 microseconds
sse_memcpy (intrinsic) averaging 1743.39 microseconds
sse_memcpy (asm) averaging 3120.18 microseconds
sse2_memcpy (intrinsic) averaging 1743.37 microseconds
sse2_memcpy (asm) averaging 2868.52 microseconds
mmx_memcpy (asm) averaging 2255.17 microseconds
mmx2_memcpy (asm) averaging 3434.58 microseconds
avx_memcpy (intrinsic) averaging 1698.49 microseconds
avx_memcpy (asm) averaging 2840.65 microseconds
avx512_memcpy (intrinsic) averaging 1670.05 microseconds
rep movsb (asm) averaging 1718.77 microseconds
24GB DDR4-2400を搭載したASUS X99上のBroadwell i7-6800k(6c / 12t、15 MBのL3キャッシュ)
---------------------------------------------------------------------------
Averaging 64900 copies of 16MB of data per function for operator new
---------------------------------------------------------------------------
std::memcpy averaging 2522.1 microseconds
asm_memcpy (asm) averaging 2615.92 microseconds
sse_memcpy (intrinsic) averaging 1621.81 microseconds
sse_memcpy (asm) averaging 1669.39 microseconds
sse2_memcpy (intrinsic) averaging 1617.04 microseconds
sse2_memcpy (asm) averaging 1719.06 microseconds
mmx_memcpy (asm) averaging 3021.02 microseconds
mmx2_memcpy (asm) averaging 1691.68 microseconds
avx_memcpy (intrinsic) averaging 1654.41 microseconds
avx_memcpy (asm) averaging 1666.84 microseconds
avx512_memcpy (intrinsic) unsupported on this CPU
rep movsb (asm) averaging 2520.13 microseconds
アセンブリ関数はxine-libsのfast_memcpyから派生し、主にmsvc ++のオプティマイザーと比較するためにのみ使用されます。
テストのソースコードは、https://github.com/marcmicalizzi/memcpy_testで入手できます(投稿するのには少し時間がかかります)
他の誰かがこれに遭遇しましたか、または誰かがこれがなぜ起こっているのかについての洞察を持っていますか?
更新2018-05-15 13:40EST
そのため、Peter Cordesが提案したように、プリフェッチ済みとプリフェッチなし、およびNTストアと通常ストアを比較するテストを更新し、各関数で行われるプリフェッチを調整しました(プリフェッチを書く意味のある経験がないので、私はこれで間違いを犯しています、私に知らせてください、そして、私はそれに応じてテストを調整します。プリフェッチは影響があるので、少なくともそれは何かをしています。これらの変更は、ソースコードを探している人のために以前に作成したGitHubリンクの最新リビジョンに反映されています。
SSE4.1 Iの前には、任意見つけることができないので、私はまた、SSE4.1用のmemcpyを追加した_mm_stream_load
(私は、具体的に使用される_mm_stream_load_si128
ので、)SSE機能をsse_memcpy
とsse2_memcpy
NTストアを使用して完全にすることができず、同様avx_memcpy
の機能がAVX2関数を使用しますストリームの読み込み用。
私は、純粋なストアと純粋なロードアクセスパターンのテストをまだ行わないことを選択しました。純粋なストアに意味があるかどうかはわかりません。アクセスしているレジスタへのロードがなければ、データは無意味で検証不可能になります。
新しいテストの興味深い結果は、Xeon Skylake Dual Socketセットアップでのみ、そのセットアップでのみ、ストア機能が16MBメモリコピーのNTストリーミング機能よりも大幅に高速だったことです。同様にのみ、その設定上だけでなく、いくつかのテストではprefetchnta命令(SSE、SSE4.1)prefetcht0なしプリフェッチの両方を凌駕する(そして唯一のLLCとのプリフェッチは、BIOSで有効)。
この新しいテストの生の結果は長すぎて投稿に追加できないため、以下のソースコードと同じgitリポジトリに投稿されます results-2018-05-15
NTストアをストリーミングする場合、Skylake SMPセットアップではリモートNUMAノードが高速である理由はまだわかりませんが、通常のストアを使用することはローカルNUMAノードのそれよりも高速です
prefetchnta
NTストアを使用しています!それはあなたが質問から除外した非常に重要な事実です!ERMSB とNTベクターストアと通常のベクターストアの詳細については、memcpyのEnhanced REP MOVSBを参照してくださいrep movsb
。それをいじるのは、MMX対SSEよりも便利です。おそらく、AVXおよび/またはAVX512を使用し、NTと通常の両方を試して、および/またはSWプリフェッチを省略します。
prefetchnta
はL3とL2をバイパスするため(L3は非包括的であるため)、プリフェッチ距離の影響を受けやすくなります(遅すぎると、L3だけでなく、データがDRAMから再び到達する必要があります)。適切な距離の調整に敏感です。ただし、asmを正しく読み取っていれば、プリフェッチ距離はかなり低く見えますが、500バイト未満です。@MysticialのSKXでのテストではprefetchnta
、このアーキテクチャが大幅に減速する可能性があることがわかりました)、彼は推奨していません。