4

私はしばらくの間c++でeigen3線形代数ライブラリを使用してきましたが、常にベクトル化のパフォーマンスの利点を利用しようとしました。今日、私は、ベクトル化によってプログラムが実際にどれだけ高速化されるかをテストすることにしました。だから、私は次のテストプログラムを書きました:

--- eigentest.cpp ---

#include <eigen3/Eigen/Dense>
using namespace Eigen;

#include <iostream>

int main() {
        Matrix4d accumulator=Matrix4d::Zero();
        Matrix4d randMat = Matrix4d::Random();
        Matrix4d constMat = Matrix4d::Constant(2);
        for(int i=0; i<1000000; i++) {
                randMat+=constMat;
                accumulator+=randMat*randMat;
        }
        std::cout<<accumulator(0,0)<<"\n"; // To avoid optimizing everything away
        return 0;
}

次に、さまざまなコンパイラオプションを使用してコンパイルした後、このプログラムを実行しました:(結果は1回限りではなく、多くの実行で同様の結果が得られます)

$ g++ eigentest.cpp  -o eigentest -DNDEBUG -std=c++0x -march=native
$ time ./eigentest
5.33334e+18

real    0m4.409s
user    0m4.404s
sys 0m0.000s
$ g++ eigentest.cpp  -o eigentest -DNDEBUG -std=c++0x
$ time ./eigentest 
5.33334e+18

real    0m4.085s
user    0m4.040s
sys 0m0.000s
$ g++ eigentest.cpp  -o eigentest -DNDEBUG -std=c++0x -march=native -O3
$ time ./eigentest 
5.33334e+18

real    0m0.147s
user    0m0.136s
sys 0m0.000s
$ g++ eigentest.cpp  -o eigentest -DNDEBUG -std=c++0x -O3
$time ./eigentest
5.33334e+18

real    0m0.025s
user    0m0.024s
sys 0m0.000s

そして、これが私の関連するCPU情報です:

model name  : AMD Athlon(tm) 64 X2 Dual Core Processor 5600+
flags       : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt rdtscp lm 3dnowext 3dnow extd_apicid pni cx16 lahf_lm cmp_legacy svm extapic cr8_legacy 3dn

-march=nativeコンパイラオプションを使用しない場合は、使用する場合とは対照的に、セグメンテーション違反やベクトル化による誤った結果が発生しないため、コンパイラオプションを使用しない場合はベクトル化が行われないことを知っています(と-NDEBUG)。

これらの結果から、少なくともeigen3を使用したCPUのベクトル化では、実行が遅くなると思います。誰のせいですか?私のCPU、eigen3またはgcc?

編集:疑問を取り除くために、-DEIGEN_DONT_ALIGNベクトル化なしの場合のパフォーマンスを測定しようとしている場合にコンパイラオプションを追加しようとしましたが、結果は同じです。-DEIGEN_DONT_ALIGNさらに、一緒に追加すると-march=native、結果は。なしの場合に非常に近くなり-march=nativeます。

4

1 に答える 1

9

コンパイラはあなたが思っているよりも賢く、多くのものを最適化しているようです。

私のプラットフォームでは、なし-march=nativeで約 9 ミリ秒、ありで約 39 ミリ秒かかり-march=nativeます。ただし、リターンの上の行を次のように置き換えると、

std::cout<<accumulator<<"\n";

次に、タイミングは、なしで 78ms、-march=nativeありで約 39ms に変わり-march=nativeます。

したがって、ベクトル化を行わないと、コンパイラーは行列の (0,0) 要素のみを使用することを認識し、その要素のみを計算するように見えます。ただし、ベクトル化が有効になっている場合、その最適化は実行できません。

行列全体を出力して、コンパイラにすべてのエントリを計算させると、ベクトル化によってプログラムが予想どおり 2 倍に高速化されます (ただし、私のタイミングでは正確に 2 倍であることに驚きました)。

于 2012-03-26T16:32:59.657 に答える