2016-07-24 59 views
2

Ich versuche, eine Summe von komponentenweise Exponentialfunktionen eines Arrays zu berechnen. Das Array ist ein Eigen::ArrayXd, also erwarte ich, dass Eigens exp Funktion auf denselben Code oder besser als eine manuelle Schleife optimiert wird. Stattdessen sehe ich, dass eine manuelle Schleife einige zehn Prozent schneller ist. (Im folgenden Beispiel ungefähr 2,1 Sekunden für Eigen und 1,6 Sekunden für eine manuelle Schleife.)Eigener Ausdruck Vorlage langsamer als manuelle Schleife für exponentielle

Ich verwende keine Eigen-Vektorisierung (SSE ist deaktiviert), MKL oder irgendetwas anderes Besonderes. Dies ist nur ein Standard-Visual Studio 2010-Projekt in der Release-Konfiguration mit Eigen 3.2.9 out-of-the-box. Die Angabe von "Vollständige Optimierung" (/ Ox) und "Bevorzugter schneller Code" (/ Ot) macht keinen Unterschied zu den Ergebnissen.

Ich bin nicht sachkundig genug, um kompilierten Code zu sehen, um zu verstehen, was passiert - könnte jemand vorschlagen, warum Eigennutzung direkt langsamer sein könnte, und wie man es dazu bringt, die gleiche Leistung wie eine manuelle Schleife zu erzeugen?

#include <ctime> 
#include <iostream> 
#include <Eigen/Dense> 

int main(int argc, char* argv[]) 
{ 
    const Eigen::ArrayXd xs(Eigen::ArrayXd::Random(1000000)); 
    Eigen::ArrayXd array_result(Eigen::ArrayXd::Zero(xs.size())), loop_result(Eigen::ArrayXd::Zero(xs.size())); 

    { 
     std::clock_t start_time = std::clock(); 
     for (int i = 1; i <= 100; ++i) { 
      const double b = i; // Values not important; 
      array_result += exp(b * xs); 
     } 
     std::clock_t end_time = std::clock(); 
     std::cout << "Array time (seconds): " << static_cast<double>(end_time - start_time)/CLOCKS_PER_SEC << std::endl; 
    } 

    { 
     std::clock_t start_time = std::clock(); 
     for (int i = 1; i <= 100; ++i) { 
      const double b = i; // Values not important; 
      for (Eigen::ArrayXd::Index i = 0; i < xs.size(); ++i) { 
       loop_result[i] += exp(b * xs[i]); 
      } 
     } 
     std::clock_t end_time = std::clock(); 
     std::cout << "Loop time (seconds): " << static_cast<double>(end_time - start_time)/CLOCKS_PER_SEC << std::endl; 
    } 

    system("pause"); 
    return 0; 
} 
+0

Haben Sie versucht, '(b * xs) .exp()'? –

+0

Sie haben 'EIGEN_DONT_VECTORIZE' definiert? – kangshiyin

+0

@Avi, ich habe versucht '(b * xs) .exp()' - die Leistung schien identisch. @ kangshiyin, das'EIGEN_DONT_VECTORIZE' definiert, scheint die Leistung nicht zu beeinträchtigen. – GavinTruter

Antwort

2

Wenn Sie definiert EIGEN_DONT_VECTORIZE werden beide Ansätze fast das gleiche in Bezug auf die C++ Code, über jedes Element des Arrays Looping.

Mit /Ox und /Ot weisen Sie Ihren Compiler an, die Schleifen automatisch zu vektorisieren. Aber die Schleife, die von Eigen generiert wird, kann etwas komplexer/ineffizienter als die handgeschriebene Schleife sein. Somit ist die Leistung geringer.

Dies hängt auch vom Compiler ab. Bei Compilern, die die Schleife nicht automatisch vektorisieren, ist Eigen mit EIGEN_DONT_VECTORIZE fast identisch mit der Schleifenmethode.

$ g++ -DEIGEN_DONT_VECTORIZE -g -O3 -DNDEBUG eigen-speed.cpp -o eigen-speed && ./eigen-speed 
Array time (seconds): 1.94 
Loop time (seconds): 1.93 

Mit Eigenvektorisierung aktiviert Eigen besser.

$ g++ -g -O3 -DNDEBUG eigen-speed.cpp -o eigen-speed && ./eigen-speed 
Array time (seconds): 0.63 
Loop time (seconds): 1.86 

Mit Compiler, den Auto-vectorize die Schleife, mit Eigen EIGEN_DONT_VECTORIZE zum Schleifen Ansatz noch ähnlich ist, aber beide vom Compiler vektorisiert.

$ icpc -DEIGEN_DONT_VECTORIZE -g -O3 -DNDEBUG eigen-speed.cpp -o eigen-speed && ./eigen-speed 
Array time (seconds): 0.43 
Loop time (seconds): 0.38 

Aber wenn Sie ermöglichen Eigen Vektorisierung,

$ icpc -g -O3 -DNDEBUG eigen-speed.cpp -o eigen-speed && ./eigen-speed 
Array time (seconds): 0.7 
Loop time (seconds): 0.36 

$ icpc -mavx -g -O3 -DNDEBUG eigen-speed.cpp -o eigen-speed && ./eigen-speed 
Array time (seconds): 0.32 
Loop time (seconds): 0.18 

darauf hindeutet, dass Eigens vektorisiert exp() Code ist schlechter als Compilers Auto-vektorisierte Version, sowohl für Eigen's SSE version und Eigen's AVX version.

So können Sie sehen, dass VS mehr wie icpc ist.

+0

Es ist sehr interessant, dass die Vektorisierung die Leistung verschlechtern kann, danke. Sie sagen, dass die von Eigen erzeugte Schleife möglicherweise weniger effizient ist als die handgeschriebene Schleife (wie in Ihrem dritten Satz von Ergebnissen und meiner zu sehen ist) - könnten Sie bitte erklären, warum das so ist? Soweit ich es verstehe, sollen die Ausdruckvorlagen genau auf den gleichen Code wie die Schleife kompiliert werden. – GavinTruter

+0

@GavinTruter Es ist eine Vermutung. Ich habe den Eigencode nicht überprüft. Vielleicht hat es einen Header und einen Tail vor und nach der Hauptschleife, um mit den nicht ausgerichteten Daten umzugehen, ursprünglich für vektorisierten Code. – kangshiyin