DAXPY線形代数カーネルのタイミングを実行する必要があります。単純に、私は次のようなことを試してみたいと思います:
fill(X,operand_size);
fill(Y,operand_size);
double seconds = timer();
daxpy(alpha,X,Y,operand_size);
seconds = timer() - seconds;
必要に応じて、コード全体のリンクが最後にあります。
問題は、オペランド x と y を埋めるためのメモリ アクセスによって、それらがプロセッサ キャッシュに配置されることです。したがって、DAXPY 呼び出しでのメモリへのその後のアクセスは、実際の運用よりもはるかに高速です。
これを回避する 2 つの方法を比較します。最初の方法は、 clflush命令を使用してすべてのレベルのキャッシュからオペランドをフラッシュすることです。2 番目の方法は、オペランド エントリがキャッシュから「自然に」追い出されるまで、非常に大きな配列を読み取ることです。両方をテストしました。これは、サイズ 2048 のオペランドを使用した単一の DAXPY 呼び出しのランタイムです。
Without flush: time=2840 ns
With clflush: time=4090 ns
With copy flush: time=5919 ns
数秒後に行われた別の実行を次に示します。
Without flush: time=2717 ns
With clflush: time=4121 ns
With copy flush: time=4796 ns
予想どおり、フラッシュによって実行時間が長くなります。ただし、コピー フラッシュによって DAXPY ルーチンの実行時間が大幅に長くなる理由がわかりません。clflush 命令はすべてのキャッシュからオペランドを削除する必要があるため、clflush の時間は、他のキャッシュ フラッシュ手順の実行時間の上限となる必要があります。それだけでなく、(両方の方法で) フラッシュされたタイミングもかなり跳ね返ります (数百ナノ秒対、フラッシュされていない場合の 10 ナノ秒未満)。手動フラッシュが実行時に劇的な違いをもたらす理由を知っている人はいますか?
付録
すべてのタイミング ルーチンとフラッシュ ルーチンを含む完全なコードは次のとおりです (194 行)。
これは私のgccバージョンです。コードは -O3 オプションでコンパイルされます。(私は知っています、それは古いです;私が構築しなければならないいくつかのソフトウェアは、新しいgccと互換性がありません)
組み込みの仕様を使用します。
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5646.1~2/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5646) (dot 1)
Intel Xeon 5650 プロセッサを搭載した Mac OS X 10.6 を使用しています。