7

タイム クリティカルな関数で、比較的短いメモリ シーケンス (1 KB 未満、通常は 2 ~ 200 バイト) をコピーしたいと考えています。CPU側でこれに最適なコードはrep movsd. ただし、コンパイラにこのコードを生成させることはできません。memcpy を使用すると、コンパイラの組み込み組み込み関数を使用してこれが行われることを望んでいましたが (漠然とそうしていたのを覚えています)、逆アセンブリとデバッグに基づいて、コンパイラは代わりに memcpy/memmove ライブラリ実装への呼び出しを使用しているようです。また、コンパイラが次のループを認識して単独で使用できるほどスマートであることを願っていましrep movsdたが、そうではないようです。

char *dst;
const char *src;
// ...
for (int r=size; --r>=0; ) *dst++ = *src++;

rep movsdインライン アセンブリを使用する以外に、Visual Studio コンパイラでシーケンスを生成する方法はありますか?

4

6 に答える 6

6

いくつかの疑問が頭に浮かびます。

まず、movsd の方が高速であるとどのように判断できますか? レイテンシー/スループットを調べましたか? x86 アーキテクチャには、最新の CPU ではあまり効率的ではないため、使用すべきではない古い命令がたくさんあります。

std::copy次に、 memcpy の代わりに使用するとどうなりますか? std::copyコンパイル時に特定のデータ型に特化できるため、潜在的に高速です。

そして 3 番目に、プロジェクト プロパティ -> C/C++ -> 最適化で組み込み関数を有効にしましたか?

もちろん、他の最適化も有効になっていると思います。

于 2009-07-16T13:10:22.387 に答える
4

最適化されたビルドを実行していますか? 最適化がオンでない限り、組み込み関数は使用されません。また、rep movsd よりも優れたコピー ループを使用する可能性が高いことも注目に値します。一度に 64 ビットのコピーを実行するには、少なくとも MMX を使用する必要があります。実際、6 年か 7 年前に、この種のことを行うために MMX に最適化されたコピー ループを作成しました。残念ながら、コンパイラの組み込み memcpy は、私の MMX コピーよりも約 1% 優れていました。これは、コンパイラが何をしているかについて仮定をしないことを本当に教えてくれました。

于 2009-07-16T12:59:22.697 に答える
3

一定サイズでの memcpy の使用

その間に私が見つけたもの:

コピーされたブロック サイズがコンパイル時にわかっている場合、コンパイラは組み込み関数を使用します。そうでない場合は、ライブラリの実装を呼び出します。サイズがわかっている場合、生成されるコードは非常に優れており、サイズに基づいて選択されます。必要に応じて、単一の mov、movsd、または movsd の後に movsb を指定できます。

常に movsb または movsd を使用したい場合は、「動的な」サイズであっても、インライン アセンブリまたは特別な組み込み関数 (以下を参照) を使用する必要があるようです。サイズが「かなり短い」ことはわかっていますが、コンパイラはそれを認識しておらず、これを伝えることができません.__assume(size <16)を使用しようとしましたが、十分ではありません。

デモ コード、"-Ob1 (インラインのみの展開) でコンパイル:

  #include <memory.h>

  void MemCpyTest(void *tgt, const void *src, size_t size)
  {
    memcpy(tgt,src,size);
  }

  template <int size>
  void MemCpyTestT(void *tgt, const void *src)
  {
    memcpy(tgt,src,size);
  }

  int main ( int argc, char **argv )
  {
    int src;
    int dst;
    MemCpyTest(&dst,&src,sizeof(dst));
    MemCpyTestT<sizeof(dst)>(&dst,&src);
    return 0;
  }

特殊な組み込み関数

私は最近、movsd を使用して Visual Studio コンパイラに文字をコピーさせる非常に簡単な方法があることを発見しました。次の組み込み関数が便利な場合があります。

于 2009-07-16T13:18:11.023 に答える
0

memcpyの時間を測定しましたか?最近のバージョンの Visual Studio では、memcpy の実装で SSE2 が使用されていますrep movsd。コピーしているブロックが 1 KB の場合、関数呼び出しの時間はコピーの時間と比較して無視できるため、コンパイラが組み込みを使用していないことは実際には問題ではありません。

于 2009-07-16T13:04:51.573 に答える
-1

を使用するには、32 ビット境界に整列されたメモリを指し、その長さが 4 バイトの倍数である必要があることに注意してmovsdくださいsrc

もしそうなら、なぜあなたのコードはchar *代わりにint *or 何かを使うのですか? そうでない場合、あなたの質問は意味がありません。

に変更char *するとint *、からより良い結果std::copy得られる場合があります。

編集:コピーがボトルネックであることを測定しましたか?

于 2009-07-16T13:02:03.867 に答える
-1

memcpy を使用します。この問題はすでに解決されています。

参考までに、rep movsd が常に最適であるとは限りません。rep movsb は、状況によってはより高速になる可能性があり、SSE などでは、movntq [edi]、xmm0 が最適です。データをバッファーに移動してから宛先に移動することにより、ページの局所性を使用して大量のメモリをさらに最適化することもできます。

于 2009-07-16T13:12:30.780 に答える