36

私はCで画像処理を行っており、メモリの周りに大量のデータをコピーする必要があります。ソースと宛先が重複することはありません。

GCCを使用してx86プラットフォームでこれを行うための絶対的な最速の方法は何ですか(SSE、SSE2が利用可能ですがSSE3は利用できません)?

ソリューションはアセンブリであるか、GCC組み込み関数を使用することになると思いますか?

次のリンクを見つけましたが、それが最善の方法であるかどうかはわかりません(作成者は、いくつかのバグがあるとも言っています):http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm。 x86 / 2006-02 / msg00123.html

編集:コピーが必要であることに注意してください、私はデータをコピーする必要を回避することはできません(理由を説明することはできますが、説明は割愛します:))

4

7 に答える 7

45

ウィリアムチャンとグーグルの礼儀。Microsoft Visual Studio 2005のmemcpyよりも30〜70%高速です。

void X_aligned_memcpy_sse2(void* dest, const void* src, const unsigned long size)
{

  __asm
  {
    mov esi, src;    //src pointer
    mov edi, dest;   //dest pointer

    mov ebx, size;   //ebx is our counter 
    shr ebx, 7;      //divide by 128 (8 * 128bit registers)


    loop_copy:
      prefetchnta 128[ESI]; //SSE2 prefetch
      prefetchnta 160[ESI];
      prefetchnta 192[ESI];
      prefetchnta 224[ESI];

      movdqa xmm0, 0[ESI]; //move data from src to registers
      movdqa xmm1, 16[ESI];
      movdqa xmm2, 32[ESI];
      movdqa xmm3, 48[ESI];
      movdqa xmm4, 64[ESI];
      movdqa xmm5, 80[ESI];
      movdqa xmm6, 96[ESI];
      movdqa xmm7, 112[ESI];

      movntdq 0[EDI], xmm0; //move data from registers to dest
      movntdq 16[EDI], xmm1;
      movntdq 32[EDI], xmm2;
      movntdq 48[EDI], xmm3;
      movntdq 64[EDI], xmm4;
      movntdq 80[EDI], xmm5;
      movntdq 96[EDI], xmm6;
      movntdq 112[EDI], xmm7;

      add esi, 128;
      add edi, 128;
      dec ebx;

      jnz loop_copy; //loop please
    loop_copy_end:
  }
}

正確な状況や想定できる状況によっては、さらに最適化できる場合があります。

memcpyソース(memcpy.asm)をチェックして、その特殊なケースの処理を取り除くこともできます。さらに最適化できるかもしれません!

于 2009-11-11T14:08:54.113 に答える
9

hapalibashiによって投稿されたSSEコードがその方法です。

さらに高いパフォーマンスが必要で、デバイスドライバーを作成するという長く曲がりくねった道を避けない場合:今日のすべての重要なプラットフォームには、CPUコードと並行してより高速にコピージョブを実行できるDMAコントローラーがあります。出来ました。

ただし、これにはドライバーの作成が含まれます。私が知っている大きなOSは、セキュリティ上のリスクがあるため、この機能をユーザー側に公開していません。

ただし、そのような作業を行うように設計されたハードウェアの一部を上回るコードは地球上に存在しないため、(パフォーマンスが必要な場合は)それだけの価値があるかもしれません。

于 2009-11-12T17:31:27.937 に答える
8

この質問は4年前のものですが、メモリ帯域幅についてまだ誰も言及していないことに少し驚いています。CPU-Zは、私のマシンにPC3-10700RAMがあることを報告します。RAMのピーク帯域幅(転送速度、スループットなど)が10700メガバイト/秒であること。私のマシンのCPUはi5-2430MCPUで、ターボ周波数のピークは3GHzです。

理論的には、CPUとRAMが無限に高速である場合、memcpyはRAMからの読み取りとRAMへの書き込みを行う必要があるため、memcpyは5300 MBytes /秒、つまり10700の半分になる可能性があります。(編集:v.oddouが指摘したように、これは単純な近似です)。

一方、無限に高速なRAMと現実的なCPUがあるとしたら、何を達成できるでしょうか。例として私の3GHzCPUを使用してみましょう。サイクルごとに32ビットの読み取りと32ビットの書き込みを実行できる場合、3e9 * 4= 12000メガバイト/秒を転送できます。これは、最近のCPUでは簡単に手の届くところにあるようです。すでに、CPUで実行されているコードが実際にはボトルネックではないことがわかります。これが、最近のマシンにデータキャッシュがある理由の1つです。

データがキャッシュされていることがわかっているときにmemcpyをベンチマークすることで、CPUが実際に何ができるかを測定できます。これを正確に行うのは面倒です。乱数を配列に書き込み、それらを別の配列にmemcpyしてから、コピーされたデータをチェックサムする簡単なアプリを作成しました。デバッガーのコードをステップ実行して、巧妙なコンパイラーがコピーを削除していないことを確認しました。配列のサイズを変更すると、キャッシュのパフォーマンスが変更されます。小さな配列はキャッシュに収まり、大きな配列は収まりません。次の結果が得られました。

  • 40 Kバイトアレイ:16000メガバイト/秒
  • 400 Kバイトアレイ:11000メガバイト/秒
  • 4000 Kバイトアレイ:3100メガバイト/秒

明らかに、16000は上記で理論的に計算した12000よりも多いため、CPUは1サイクルあたり32ビット以上の読み取りと書き込みを行うことができます。これは、CPUが私がすでに考えていたよりもボトルネックが少ないことを意味します。Visual Studio 2005を使用し、標準のmemcpy実装にステップインすると、マシンでmovqda命令が使用されていることがわかります。これは1サイクルあたり64ビットの読み取りと書き込みができると思います。

hapalibashiが投稿した素晴らしいコードは、私のマシンで4200 MBytes /秒を達成します。これは、VS 2005の実装よりも約40%高速です。プリフェッチ命令を使用してキャッシュのパフォーマンスを向上させるため、より高速だと思います。

要約すると、CPUで実行されているコードはボトルネックではなく、そのコードを調整してもわずかな改善しか得られません。

于 2013-08-15T11:00:18.457 に答える
6

それ以上の最適化レベルでは-O1、GCCは次のような関数の組み込み定義を使用しますmemcpy-適切な-marchパラメーター(-march=pentium4言及した機能のセットに対して)を使用すると、非常に最適なアーキテクチャ固有のインラインコードを生成する必要があります。

私はそれをベンチマークして、何が出てくるかを確認します。

于 2009-11-11T21:54:15.893 に答える
3

Intelプロセッサに固有の場合は、 IPPの恩恵を受ける可能性があります。Nvidia GPUで実行されることがわかっている場合は、おそらくCUDAを使用できます-どちらの場合も、memcpy()を最適化するよりも広く見える方が良いかもしれません-アルゴリズムをより高いレベルで改善する機会を提供します。ただし、どちらも特定のハードウェアに依存しています。

于 2009-11-11T14:10:02.653 に答える
2

Windowsを使用している場合は、グラフィックス処理用に特定のGPU最適化ルーチンを備えたDirectX APIを使用します(どのくらいの速さでしょうか?CPUがロードされていません。GPUがそれを処理している間に何か他のことをしてください)。

OSにとらわれないようにしたい場合は、OpenGLを試してください。

アセンブラをいじらないでください。10年以上の熟練したライブラリ作成ソフトウェアエンジニアを無残に凌駕する可能性が非常に高いからです。

于 2009-11-11T14:00:27.233 に答える
-1

DMAエンジンにアクセスできる場合、これより高速なものはありません。

于 2020-11-18T21:27:56.820 に答える