[解決済み] memmoveはなぜmemcpyより速いのですか?
質問
私は、時間の 50% を memmove(3) に費やすアプリケーションのパフォーマンス上のホットスポットを調査しています。 を費やしているアプリケーションのパフォーマンスのホットスポットを調査しています。このアプリケーションは、何百万もの 4 バイト整数をソートされた配列に挿入します。 を挿入し、挿入された値のスペースを確保するために memmove を使用してデータを右方向にシフトします。 挿入された値のためのスペースを確保するためです。
私の予想では、メモリのコピーは非常に速いと思っていたので、メモリに多くの時間が費やされていることに驚きました。
私の予想では、メモリのコピーは非常に高速で、memmove にこれほど多くの時間が費やされていることに驚きました。しかしその後、memmove が遅いのは、重複する領域を移動しているからではないかという考えが浮かびました。 が遅いのは、オーバーラップしている領域を移動しているためで、タイトなループで実装する必要があります。 をタイトループで実装しなければならないからだ、と思いつきました。私は、小さな とmemmoveの間に性能差があるかどうかを調べるために、小さなマイクロベンチマークを書きました。 memcpy と memmove の間に性能差があるかどうかを調べるために、私は小さなマイクロベンチマークを書きました。
2 台のマシン (core i5 と core i7) でベンチマークを実行したところ、memmove は memcpy よりも実際に高速であることがわかりました。 古い core i7 では、memcpy よりも 2 倍近く速いことさえありました。 今、私はその説明を探しています。
これは私のベンチマークです。memcpy で 100 mb をコピーし、memmove で約 100 mb を移動し、移動元と移動先は重なっています。移動元と移動先は重なっています。 を試しています。各テストは10回実行され、その平均時間が表示される。 平均時間が表示されます。
https://gist.github.com/cruppstahl/78a57cdf937bca3d062c
以下はCore i5での結果です(Linux 3.5.0-54-generic #81~precise1-Ubuntu)。 SMP x86_64 GNU/Linux、gccは4.6.3(Ubuntu/Linaro 4.6.3-1ubuntu5)です。括弧内の数字 括弧内の数字は、ソースとデスティネーション間の距離(ギャップの大きさ)です。
memcpy 0.0140074
memmove (002) 0.0106168
memmove (004) 0.01065
memmove (008) 0.0107917
memmove (016) 0.0107319
memmove (032) 0.0106724
memmove (064) 0.0106821
memmove (128) 0.0110633
MemmoveはSSE最適化アセンブラコードとして実装され、後ろから前にコピーされます。 から前へコピーします。データをキャッシュにロードするためにハードウェアプリフェッチを使用し、128 バイトを XMM レジスタにコピーし、目的地に格納します。 128 バイトを XMM レジスタにコピーし、目的地に格納します。
( memcpy-ssse3-back.S , 1650行目 ff)
L(gobble_ll_loop):
prefetchnta -0x1c0(%rsi)
prefetchnta -0x280(%rsi)
prefetchnta -0x1c0(%rdi)
prefetchnta -0x280(%rdi)
sub $0x80, %rdx
movdqu -0x10(%rsi), %xmm1
movdqu -0x20(%rsi), %xmm2
movdqu -0x30(%rsi), %xmm3
movdqu -0x40(%rsi), %xmm4
movdqu -0x50(%rsi), %xmm5
movdqu -0x60(%rsi), %xmm6
movdqu -0x70(%rsi), %xmm7
movdqu -0x80(%rsi), %xmm8
movdqa %xmm1, -0x10(%rdi)
movdqa %xmm2, -0x20(%rdi)
movdqa %xmm3, -0x30(%rdi)
movdqa %xmm4, -0x40(%rdi)
movdqa %xmm5, -0x50(%rdi)
movdqa %xmm6, -0x60(%rdi)
movdqa %xmm7, -0x70(%rdi)
movdqa %xmm8, -0x80(%rdi)
lea -0x80(%rsi), %rsi
lea -0x80(%rdi), %rdi
jae L(gobble_ll_loop)
memmoveはなぜmemcpyより速いのですか?memcpyはメモリページをコピーするものと思っています。 ループするよりもずっと速いはずです。最悪の場合、memcpyはmemmoveと同じ速さになると思います。 はmemmoveと同じ速度になると思います。
PS: 私のコードでmemmoveをmemcpyで置き換えることができないことは知っています。私は知っています。 コードサンプルは C と C++ を混合しています。この質問は、本当に学術的な目的のためだけです。 目的です。
アップデイト1
様々な回答に基づいて、いくつかのテストのバリエーションを実行しました。
- memcpy を 2 回実行すると、2 回目の実行が 1 回目の実行より速くなります。
-
memcpy の宛先バッファに "touch" したとき (
memset(b2, 0, BUFFERSIZE...)
) の場合、memcpy の最初の実行も高速化されます。 - memcpy は memmove よりもまだ少し遅いです。
以下はその結果です。
memcpy 0.0118526
memcpy 0.0119105
memmove (002) 0.0108151
memmove (004) 0.0107122
memmove (008) 0.0107262
memmove (016) 0.0108555
memmove (032) 0.0107171
memmove (064) 0.0106437
memmove (128) 0.0106648
私の結論は、@Oliver Charlesworth のコメントに基づいて、オペレーティング システムは memcpy の宛先バッファが最初にアクセスされるとすぐに物理メモリをコミットしなければなりません (誰かがこれを "proof" する方法を知っていれば、回答を追加してください!)。さらに、@Mats Petersson が言ったように、memmove は memcpy よりもキャッシュ フレンドリーです。
すべての素晴らしい回答およびコメントに感謝します!
どのように解決するのですか?
あなたの
memmove
の呼び出しは、メモリを2〜128バイトずつシャッフルしています。
memcpy
のコピー元とコピー先がまったく異なるのにです。 どういうわけか、これがパフォーマンスの違いを説明しています。同じ場所にコピーする場合は
memcpy
の方がわずかに速く終わる可能性があります。例えば
ideone.com
:
memmove (002) 0.0610362
memmove (004) 0.0554264
memmove (008) 0.0575859
memmove (016) 0.057326
memmove (032) 0.0583542
memmove (064) 0.0561934
memmove (128) 0.0549391
memcpy 0.0537919
すでにフォールトを起こしたインメモリページに書き戻すと、そのページには
多くの
があるという証拠もありませんし、時間が半分になったわけでもありません...。
memcpy
を不必要に遅くすることは問題ではないということを示しています。
関連
-
[解決済み】指定範囲内の乱数で配列を埋める(C++)
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] B "の印刷が "#"の印刷より劇的に遅いのはなぜですか?
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] なぜC++はPythonよりもstdinからの行の読み込みが遅いのですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] <は<=より速いのか?
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
-
[解決済み] なぜ[]はlist()よりも速いのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み】C++のGetlineの問題(オーバーロードされた関数 "getline "のインスタンスがない
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++
-
[解決済み] memmoveとmemcpyの違いは何ですか?