Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.net  
   

Die mobilen Seiten von c++.net:
https://m.c-plusplus.net

  
C++ Forum :: C++ (alle ISO-Standards) ::  std::complex vs. Eigenbau     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 20:37:57 04.08.2010   Titel:   std::complex vs. Eigenbau            Zitieren

Hi!

Das hier ist keine Frage, sondern nur eine Feststellung. Und zwar sitze ich gerade an einer WinXP-Kiste und habe den GCC (g++) 4.5 etwas getriezt. Dabei ist mir folgendes aufgefallen:

  • std::complex<double> mit Operatoren (*,+) ist im Verglech zum "manuellen" Hantieren von Real- und Imaginärteil im Default-Modus etwa 7mal langsamer
  • schaltet man -ffast-math ein, wird std::complex<double> fast genauso flott wie die "manuelle Alternative".


Was ich berechne: Ich accumuliere einen Haufen von komplexwertigen Matrix-Produkten der Art T1H*T1 + T2H*T2 + ... + TNH*TN wobei die Ts komplexwertige Matrizen sind und das H im Superskript für eine konjugierte Transposition steht.

Ich werde morgen vielleicht nochmal den MSVC Compiler anschmeißen und gucken, wie es da mit der Performanz aussieht. Jedenfalls haben mich diese Ergebnisse überrascht und ich wollte sie Euch nicht vorenthalten. :)

Scheinbar wird ohne -ffast-math noch ganz viel an Sonderbehandlungen bzgl NaN und Inf in den std::complex-Operatoren gemacht, die ich eigentlich auch gar nicht brauche.

kk
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23665
Beitrag hustbaer Mitglied 21:18:11 04.08.2010   Titel:              Zitieren

Ist std::complex denn beim GCC nicht eine reine Library-Implementierung?

Falls ja, dürfte (sollte) der -ffast-math switch keine Auswirkung auf das haben was in std::complex gemacht wird, sondern nur darauf, was der Compiler daraus im Endeffekt für Code macht.
Anders gesagt: ich glaube dass man den selbe Unterschied sehem müsste, wenn man sich eine eigene "complex" Klasse bastelt, und dann einmal mit und einmal ohne -ffast-math compiliert.

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 21:26:37 04.08.2010   Titel:              Zitieren

Nee, das stimmt so nicht. Ich habe es ja ausprobiert. Beide Implementierung (also std::complex vs meinen Kram) mit und ohne -ffast-math. Übrigens setzt -ffast-mat das Makro __FAST_MATH__ (wenn ich mich richtig erinnere, ich habe die Doku grad nicht mehr vor mir liegen).

kk
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 21:33:20 04.08.2010   Titel:              Zitieren

krümelkacker schrieb:
Nee, das stimmt so nicht. Ich habe es ja ausprobiert. Beide Implementierung (also std::complex vs meinen Kram) mit und ohne -ffast-math.

Ergebnis: ffast-math macht bei der eigenen Implementierungen so gut wie keinen Unterschied. std::complex<double> wird etwa 7mal schneller dadurch (und damit etwa genauso schnell wie die eigene Impl).
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 22:10:25 04.08.2010   Titel:              Zitieren

Habe ähnliche Infos hier gefunden:
http://old.nabble.com/per ....... -versions-td27187415.html
Anscheinend war std::complex<double> bem GCC 4.2 und früher noch nicht so lahm und ab 4.3 hamse std::complex "konform" implementiert, was nicht mehr so schnell ist, wie vorher -- zumindest nicht, wenn man sich ffast-math spart.
Unregistrierter





Beitrag Unregistrierter 22:15:04 04.08.2010   Titel:              Zitieren

Rein aus Interesse: Teste mal gegen _Complex. Das ist C99 aber die gcc könnte das auch im C++-Mode unterstützen.

Achja, der Code wäre auch ganz interessant.
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23665
Beitrag hustbaer Mitglied 00:12:31 05.08.2010   Titel:              Zitieren

@krümelkacker: dann guck doch bitte einfach in der Implementierung von std::complex nach ob __FAST_MATH__ dort vorkommt. Ich würde mal tippen es kommt nicht vor. Wieso sollte es auch.

Deine Implementierung wird einfach anders aussehen, und dadurch seltener dazu führen dass ohne -ffast-math irgendwelche langsamen Checks/... generiert werden müssen.

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at
Athar
Mitglied

Benutzerprofil
Anmeldungsdatum: 24.12.2009
Beiträge: 989
Beitrag Athar Mitglied 00:24:30 05.08.2010   Titel:              Zitieren

Was ist eigentlich der "Default-Modus"? -O3, will ich hoffen?
SeppJ
Global Moderator

Benutzerprofil
Anmeldungsdatum: 10.06.2008
Beiträge: 28070
Beitrag SeppJ Global Moderator 01:03:52 05.08.2010   Titel:              Zitieren

Niemanden interessiert es, wie schnell Code ohne Compileroptimierungen läuft.
seldon
Unregistrierter




Beitrag seldon Unregistrierter 01:29:48 05.08.2010   Titel:              Zitieren

Das dürfte hiermit zusammenhängen:
g++ manpage schrieb:

-fcx-limited-range

When enabled, this option states that a range reduction step is not needed when performing complex division. Also, there is no checking whether the result of a complex multiplication or division is "NaN + I*NaN", with an attempt to rescue the situation in that case. The default is -fno-cx-limited-range, but is enabled by -ffast-math.

This option controls the default setting of the ISO C99 "CX_LIMITED_RANGE" pragma. Nevertheless, the option applies to all languages.
rüdiger
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2001
Beiträge: 23086
Beitrag rüdiger Moderator 02:10:54 05.08.2010   Titel:              Zitieren

hustbaer schrieb:
Ist std::complex denn beim GCC nicht eine reine Library-Implementierung?


Kommt drauf an, was du unter "reine Library-Implementierung" verstehst. libstdc++s std::complex nutzt intern je nach Situation auch C99s _Complex.

_________________
.
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23665
Beitrag hustbaer Mitglied 03:54:26 05.08.2010   Titel:              Zitieren

Etwas was keine Compiler-Magick verwendet.
_Complex zu verwenden rechne ich in C++ zu Compiler-Magick, da es _Complex in Standard-C++ nicht gibt.

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at
unskilled
Mitglied

Benutzerprofil
Anmeldungsdatum: 06.07.2007
Beiträge: 3926
Beitrag unskilled Mitglied 05:58:29 05.08.2010   Titel:              Zitieren

hustbaer schrieb:
Compiler-Magick


Wieder was dazugelernt:
http://de.wikipedia.org/wiki/Magick

war das mit Absicht oder ists nur Zufall, dass es das Wort gibt? :P

bb

_________________
Keiner kann besser nix als ich - Tagedieb mit Lächeln im Gesicht :o)
asc
Mitglied

Benutzerprofil
Anmeldungsdatum: 13.01.2007
Beiträge: 6663
Beitrag asc Mitglied 09:22:04 05.08.2010   Titel:   Re: std::complex vs. Eigenbau            Zitieren

krümelkacker schrieb:
im Default-Modus etwa 7mal langsamer


Was ist bitte der Default-Modus. Und zudem hoffe ich das du die Geschwindigkeit grundsätzlich im Release-Modus testest (Debug ist nur zum debuggen).

_________________
in theory there's no difference between theory and practice. in practice there is. (yogi berra)

In der Theorie gibt es kein Unterschied zwischen Theorie und Praxis. In der Praxis sehr wohl.
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 10:26:17 05.08.2010   Titel:              Zitieren

Hmm... dass man hier eher davon ausgeht, dass ich Mist gebaut habe, als dass std::complex ohne -ffast-math wirklich sehr langsam ist, bestätigt mich, was den Sinn des Threads angeht. :) Wie gesagt, ich war auch überrascht.

Den originalen Quellcode kann ich aus rechtlichen Gründen nicht zeigen. Ich habe aber ein anderes Testprogramm geschrieben:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <complex>
#include <vector>
#include <algorithm>
 
using std::complex;
using std::vector;
 
typedef std::complex<double> complx;
 
complx scalarproduct_version1(vector<complx> const& a, vector<complx> const& b)
{
  typedef vector<complx>::size_type sizt;
  complx accumulator = 0;
  sizt len = std::min(a.size(),b.size());
  for (sizt i=0; i<len; ++i) {
    accumulator += conj(a[i]) * b[i];
  }
  return accumulator;
}
 
complx scalarproduct_version2(vector<complx> const& a, vector<complx> const& b)
{
  typedef vector<complx>::size_type sizt;
  double accumR = 0;
  double accumI = 0;
  sizt len = std::min(a.size(),b.size());
  for (sizt i=0; i<len; ++i) {
    double ar = real(a[i]);
    double ai = imag(a[i]);
    double br = real(b[i]);
    double bi = imag(b[i]);
    accumR += ar*br+ai*bi;
    accumI += ar*bi-ai*br;
  }
  return complx(accumR,accumI);
}

#include <iostream>

#include <ostream>
#include <ctime>
 
using std::cout;
using std::endl;
 
const int vecsize = 4096;
const int passes  = 15000;
 
int main()
{
  vector<complx> a (vecsize, complx(2,1));
  vector<complx> b (vecsize, complx(1,3));
  std::clock_t time1 = std::clock();
  for (int pass=0; pass<passes; ++pass) {
    scalarproduct_version1(a,b);
  }
  std::clock_t time2 = std::clock();
  for (int pass=0; pass<passes; ++pass) {
    scalarproduct_version2(a,b);
  }
  std::clock_t time3 = std::clock();
  cout << double(time2-time1)/CLOCKS_PER_SEC << endl;
  cout << double(time3-time2)/CLOCKS_PER_SEC << endl;
}

Hier kann man sehen, dass scalarproduct_version1 Multiplikation und Addition über die überladenen Operatorn für std::complex<double> verwendet. scalarproduct_version2 rechnet manuell auf Real-/Imaginärteil.

Es ergibt sich auf meinem Bürorechner (WinXP, MinGW-TDM, GCC4.5) folgende Tabelle:
Code:
                         --Zeit, in Sekunden--
Compiler-Optionen        Version 1   Version 2
----------------------------------------------
-O3 -DNDEBUG               4.515       0.375
-O3 -DNDEBUG -ffast-math   0.375       0.375


I rest my case.

kk
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 10:58:30 05.08.2010   Titel:              Zitieren

Selber Rechner, selber Compiler (GCC), andere Optionen:
Code:
                                                     --Zeit, in Sekunden--
Compiler-Optionen                                    Version 1   Version 2
--------------------------------------------------------------------------
-O3 -DNDEBUG -march=native -mtune=native               2.406       0.375
-O3 -DNDEBUG -march=native -mtune=native -ffast-math   0.406       0.312


Selber Rechner mit Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86. Der Microsoft Compiler hat scheinbar erkannt, dass der Aufruf scalarproduct_version2(a,b); komplett wegoptimiert werden kann. Ich habe daher das Programm etwas modifiziert, so dass das Ergebnis des Funktionsaufruf wieder an eine andere Funktion "foo" übergeben wird, die ich so definiert habe:
C++:
void foo(complx) {}

Damit erhalte ich folgende Ergebnisse
Code:
                        --Zeit, in Sekunden--
Compiler-Optionen        Version 1   Version 2
----------------------------------------------
/O2 /Ob1 /Oi               0.512       0.283


Ich muss gestehen, dass ich mich mit dem Microsoft-Compiler nicht richtig gut auskenne. Vielleicht habt ihr noch Ideen, was man für Optionen verwenden kann.

So richtig überzeugen tut mich std::complex<double> bzgl Performance nicht. Beim GCC muss ich -ffast-math verwenden und beim Microsoft Compiler bekomme ich bisher nicht an die "manuelle" Version dran. Ich bin bei meiner Anwendung nicht an super-duper Genauigkeit für extrem kleine oder extrem große Werte interessiert. Nan und Inf kommt bei mir auch nicht vor. Daher brauche ich keine (genauigkeiterhaltende) Sonderbehandlungen. Das kostet nur Zeit. Laut Profiler sind komplex-wertige Produkte in meiner Anwendung der Flaschenhals.

kk
knivil
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.02.2009
Beiträge: 7325
Beitrag knivil Mitglied 11:19:40 05.08.2010   Titel:              Zitieren

Der Benchmark ist fuer den Arsch. bei mir dauert alles 0 Sekunden mit g++ -O3 unter Linux. Ausserdem vergleichst du hier zwei unterschiedliche Ansaetze zur Berechnung des Skalarprodukts und nicht die Performance von std::complex.

_________________
If it were not for laughter, there would be no Tao.
Sie können einen Beitrag nicht so schnell nach Ihrem letzten absenden, bitte warten Sie einen Augenblick.


Zuletzt bearbeitet von knivil am 11:35:35 05.08.2010, insgesamt 2-mal bearbeitet
Tachyon
Mitglied

Benutzerprofil
Anmeldungsdatum: 03.12.2003
Beiträge: 3478
Beitrag Tachyon Mitglied 12:39:19 05.08.2010   Titel:              Zitieren

knivil schrieb:
Der Benchmark ist fuer den *****. bei mir dauert alles 0 Sekunden mit g++ -O3 unter Linux. Ausserdem vergleichst du hier zwei unterschiedliche Ansaetze zur Berechnung des Skalarprodukts und nicht die Performance von std::complex.

Keine Ahnung, was Du da treibst. Bei mir verhält es sich sowohl unter Linux (mit gcc 4.4) als auch unter Windows (MSVC2008SP1) so, wie es KK beschreibst. Außerdem gibt es nur einen Ansatz zur Berechnung des Skalarproduktes.

Offensichtlich verhalten sich die Operatoren und Funktionen, die für std::complex definiert sind, je nach eingestellter Optimierung unterschiedlich. Hätte ich so eigentlich nicht erwartet.

_________________
タキオン
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 13:01:17 05.08.2010   Titel:              Zitieren

knivil schrieb:

Der Benchmark ist fuer den *****. bei mir dauert alles 0 Sekunden mit g++ -O3 unter Linux.

Das kann zwei Gründe haben. Entweder wurde erkannt, dass die Berechnungen ins leere laufen und nach der as-if Regel komplett wegoptimiert werden können, oder sie liefen alle so schnell bei dir, dass die Granularität der Uhr bei der Zeitmessung das Problem ist. Letzteres kannst Du mit Erhöhen von 'passes' und 'vecsize' kompensieren. Ersteres kannst Du umgehen, indem Du zB die Skalarprodukte nochmal alle aufsummierst und ganz zum Schluss auf die Konsole schickst. Ich bin mir dessen wohl bewusst, auch ohne Deinen Kommentar. Ich habe nicht behauptet, dass die Ergebnisse des Benchmarks von jedem korrekt interpretiert werden können.

knivil schrieb:

Ausserdem vergleichst du hier zwei unterschiedliche Ansaetze zur Berechnung des Skalarprodukts und nicht die Performance von std::complex

Der "Ansatz" ist der gleiche. Nur in einem Fall verwende ich conj, operator* und operator+ für std::complex<double> und in anderem Fall eben nicht. Wie Du auf diese These kommst, ist mir schleirhaft.

kk
SeppJ
Global Moderator

Benutzerprofil
Anmeldungsdatum: 10.06.2008
Beiträge: 28070
Beitrag SeppJ Global Moderator 13:13:26 05.08.2010   Titel:              Zitieren

Ich muss knivil Zustimmen. Da wird bei mir vom GCC alles wegoptimiert, selbst mit dem foo-Trick. Deshalb frage ich mich, ob da nicht vielleicht etwas mit den Optimierungseinstellungen bei euch nicht passt, wenn ihr doch den gleichen Compiler benutzt.

Was ich ganz lustig finde: Ich habe das mal durch den Intel-Compiler gejagt. Bei normaler Optimierung erhält man das gleiche Ergebnis wie krümelkacker, d.h. Version 2 ist ungefähr doppelt so schnell wie Version 1. Was jetzt aber interessant ist, was passiert, wenn ich architekturspezifische Optimierung anschalte: Dann braucht Version 1 nämlich auf einmal 5x so lange wie vorher, während dies keine Auswirkungen auf die andere Version hat. Da geht irgendetwas Mysteriöses vor sich.


Was man noch erwähnen sollte ist, dass der Intel-Compiler in der erfahrungsgemäß (meine Erfahrung) besten Optimierungsstufe (d.h. mit Optimierungsprofil) für beide Versionen fast gleich schnellen Code produziert. Wobei Version 2 bei allen beschriebenen Versuchen immer gleich schnell war. Anscheinend besteht bei Version 1 gehöriges Optimierungspotential, der Compiler benötigt nur genügend Informationen. Version 2 scheint hingegen schon perfekt handoptimiert zu sein, da ist nichts mehr herauszuholen.


Zuletzt bearbeitet von SeppJ am 13:14:34 05.08.2010, insgesamt 1-mal bearbeitet
Unregistrierter





Beitrag Unregistrierter 13:19:30 05.08.2010   Titel:              Zitieren

Hab den Code bei mir mal mit VS2010 durchlaufen lassen:

Zitat:

Version1 = 1.859
Version2 = 1.437

vecsize = 40960;
passes = 10000;


Compilereinstellungen sind:
Zitat:

/Zi /nologo /W3 /WX- /O2 /Oi /Ot /Oy- /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope /Fp"Release\complexTest.pch" /Fa"Release" /Fo"Release" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue


Die std:: Implementierung ist also schon etwas langsamer. Ich vermute mal, dass da noch irgendwo (Beim operator+ ?)eine temporäre Kopie erzeugt wird.
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 14:02:52 05.08.2010   Titel:              Zitieren

SeppJ schrieb:

Ich muss knivil Zustimmen.
Da wird bei mir vom GCC alles wegoptimiert, selbst mit dem foo-Trick.

Dann mach's besser.

Wenn man da ganz auf Nummer sicher gehen will, kommt wohl nicht drum herum, die Vektoren aus einer Datei zur Laufzeit zu lesen und die Produkte zu speichern und zum Schluss auszugeben, so dass da nichts nach as-if wegoptimiert werden kann. Soweit bin ich dann noch nicht gegangen. Es muss einfach nur "kompliziert" genug sein. Im Moment sieht es bei mir so aus:
C++:
1
2
3
4
5
6
7
8
9
10
11
complx sum1 = 0;
for (long pass=0; pass<passes; ++pass) {
  sum1 += scalarproduct_version1(a,b);
}
...
complx sum2 = 0;
for (long pass=0; pass<passes; ++pass) {
  sum1 += scalarproduct_version1(a,b);
}
...
cout << sum1 << sum2 << endl;

Ich denke nicht, dass irgendein Compiler den interessanten Teil (skalarproduct_xxx) hier wegoptimieren kann.

SeppJ schrieb:

Deshalb frage ich mich, ob da nicht vielleicht etwas mit den Optimierungseinstellungen bei euch nicht passt,

Ich weiß nicht, welche GCC Version knivel benutzt hat. Vielleicht spielt es auch noch eine Rolle, ob es die MinGW-TDM Version für Win32 ist oder der "native" GCC für Linux.

Hier nochmal mit der Modifikation von oben (sum1,sum2), mit vecsize=8192, mit passes=88000, mit "-O3 -DNDEBUG -march=native -mtune=native", mit und ohne ffast-math:
Code:
ffast-math   version 1   version 2
----------------------------------
   ohne       18.484       4.563
   mit         4.891       3.703


Verwende ich zusätzlich die Option -pg (für den Profiler GProf) erhalte ich folgende Ausgaben:

ohne ffast-math
Code:
1
2
3
4
5
6
7
8
9
10
Flat profile:
 
Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total          
 time   seconds   seconds    calls  us/call  us/call  name    
 54.94     11.79    11.79                             __muldc3
 25.44     17.25     5.46    88000    62.05    62.05  scalarproduct_version1
 19.52     21.44     4.19    88000    47.61    47.61  scalarproduct_version2
  0.05     21.45     0.01                             std::string::_S_construct
  0.05     21.46     0.01                             main


mit ffast-math:
Code:
1
2
3
4
5
6
7
8
9
Flat profile:
 
Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total          
 time   seconds   seconds    calls  us/call  us/call  name    
 56.59      4.64     4.64    88000    52.73    52.73  scalarproduct_version1
 43.17      8.18     3.54    88000    40.23    40.23  scalarproduct_version2
  0.12      8.19     0.01                             std::basic_streambuf<...>::imbue(std::locale const&)
  0.12      8.20     0.01                             main


wobei __muldc3 eine "interne" vom GCC bereitgestellte Funktion ist, die ein Produkt von zwei "complex doubles" berechnet. Sie taucht im ffast-math Modus nicht auf. Im ffast-math-Modus findet man die Multiplikationen direkt in der scalarprodukt-Funktion. Ohne ffast-math sieht man nichts von irgendwelchen Multiplikationen im Assemblercode der Funktion *_version1. Ich sehe zwar keinen __muldc3 Aufruf direkt, aber irgendwo müssen ja die Multiplikationen sein. Den Assembler-Code poste ich jetzt aber nicht mehr. Dass kann jeder selbst mal nachgucken.

kk
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 14:04:31 05.08.2010   Titel:              Zitieren

krümelkacker schrieb:

C++:
1
2
3
4
5
6
7
8
9
10
11
complx sum1 = 0;
for (long pass=0; pass<passes; ++pass) {
  sum1 += scalarproduct_version1(a,b);
}
...
complx sum2 = 0;
for (long pass=0; pass<passes; ++pass) {
  sum1 += scalarproduct_version1(a,b);
}
...
cout << sum1 << sum2 << endl;


Das muss natürlich "_version2" in der zweiten Schleife heißen.
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 14:07:17 05.08.2010   Titel:              Zitieren

SeppJ schrieb:
Niemanden interessiert es, wie schnell Code ohne Compileroptimierungen läuft.

Richtig. Mich auch nicht. Haltet ihr mich für blöd oder was?

kk
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 15:20:41 05.08.2010   Titel:              Zitieren

ogni42 schrieb:

Hab den Code bei mir mal mit VS2010 durchlaufen lassen:
...
Compilereinstellungen sind:
Zitat:

/Zi /nologo /W3 /WX- /O2 /Oi /Ot /Oy- /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope /Fp"Release\complexTest.pch" /Fa"Release" /Fo"Release" /Fd"Release\vc100.pdb" /Gd /analyze- /errorReport:queue


Selbst mit diesen Einstellungen scheint Version2 fast 2mal so schnell zu laufen, wie Version1 bei mir. Fp, Fa, Fo, Fd habe ich einfach mal weggelassen.

kk
Unregistrierter





Beitrag Unregistrierter 15:42:39 05.08.2010   Titel:              Zitieren

Zitat:

Selbst mit diesen Einstellungen scheint Version2 fast 2mal so schnell zu laufen, wie Version1 bei mir. Fp, Fa, Fo, Fd habe ich einfach mal weggelassen.


Bei mir ist es ein Faktor 1,29. Benutzt Du denn VS 2010? Ich nehme mal an, dass dort in der StdLib durch Move-Semantik dort noch einiges an Zeit raus geholt werden kann, weil temporäre Kopien weg fallen.

Edit: Habe jetzt noch beim inlining "Any suitable" eingestellt und - um den Einfluss der Schleifen und Funktionsaufrufe zu reduzieren Size erhöht und passes verkleinert:
Zitat:

VecSize = 100000
passes = 5000
Version 1 = 3.703
Version 2 = 3.672
Rate = 1.00844
Result1 = 499683+i496250
Result2 = 499683+i496250


Also beide Versionen praktisch gleich schnell!


Zuletzt bearbeitet von Unregistrierter am 15:53:29 05.08.2010, insgesamt 1-mal bearbeitet
camper
Moderator

Benutzerprofil
Anmeldungsdatum: 06.08.2004
Beiträge: 7176
Beitrag camper Moderator 15:58:14 05.08.2010   Titel:              Zitieren

Nach ein bisschen experimentieren (und genauerer Messmethodik) ist g++ bei mir ca. 95% langsamer bei std::complex ohne -ffast-math als die andere Variante, mit -ffast-math sind es nur ca. 4%.

Der Verantwortliche Schalter scheint dabei -fcx-limited-range zu sein
gcc Manual schrieb:

-fcx-limited-range
When enabled, this option states that a range reduction step is not needed when performing complex division. Also, there is no checking whether the result of a complex multiplication or division is NaN + I*NaN, with an attempt to rescue the situation in that case. The default is -fno-cx-limited-range, but is enabled by -ffast-math.

This option controls the default setting of the ISO C99 CX_LIMITED_RANGE pragma. Nevertheless, the option applies to all languages.
Die beiden Varianten sind also tatsächlich nicht äquivalent, wobei ich vermute, dass in den meisten Anwendungsfällen (wegen der Eigenart der EIngabedaten) -fcx-limited-range eine sichere Option ist.

Offenbar bildet die Standardbibliothek von g++ std::complex auf den C99-Typ _Complex ab, bei anderen Compilern ist das möglicherweise nicht so.

Mit -fcx-limited-range (ohne -ffast-math) differieren die Zeiten bei mir nur um ca. 1-2 %.


Zuletzt bearbeitet von camper am 16:04:20 05.08.2010, insgesamt 2-mal bearbeitet
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 17:49:26 05.08.2010   Titel:              Zitieren

ogni42 schrieb:
Zitat:

Selbst mit diesen Einstellungen scheint Version2 fast 2mal so schnell zu laufen, wie Version1 bei mir. Fp, Fa, Fo, Fd habe ich einfach mal weggelassen.

Bei mir ist es ein Faktor 1,29. Benutzt Du denn VS 2010?

Ja. Vielleicht sind unsere Rechner auch einfach zu verschieden. Ich hab hier schon ne recht alte Krücke im Moment (Intel Petium 4). Mit all den Optimierungen ist std::complex nur halb so schnell.

ogni42 schrieb:

Ich nehme mal an, dass dort in der StdLib durch Move-Semantik dort noch einiges an Zeit raus geholt werden kann, weil temporäre Kopien weg fallen.

Nein. Das braucht man nicht annehmen. Es gibt keinen guten Grund, std::complex<double> mit benutzerdefinierten Copy/Move Funktionen auszustatten. Die vom Compiler generierten Funktionen sind schon optimal.

ogni42 schrieb:

Edit: Habe jetzt noch beim inlining "Any suitable" eingestellt

Habe ich auch gerade. Keine Änderung.

ogni42 schrieb:

Also beide Versionen praktisch gleich schnell!

Kann ich nicht reproduzieren auf meiner Kiste. Habe hier immer ein Verhältnis von etwa 1:2 in der Laufzeit.

camper schrieb:

Nach ein bisschen experimentieren (und genauerer Messmethodik) ist g++ bei mir ca. 95% langsamer bei std::complex ohne -ffast-math als die andere Variante, mit -ffast-math sind es nur ca. 4%.

Das scheint auch stark Rechnerabhängig zu sein. Bei mir sieht es wie gesagt noch viel schlimmer aus. Mit -O3 -march=native -mtune=native immerhin noch 1:4.

camper schrieb:

Der Verantwortliche Schalter scheint dabei -fcx-limited-range zu sein

Das steht auch in etwa so in der Diskussion, die ich von der ersten Seite aus verlinkt hatte.

Wen's interessiert, ich habe im Projekt jetzt in einer cpp-Datei (in etwa) folgendes stehen:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#ifdef USE_NATIVE_COMPLEX_OPERATORS
 
/// computes t += conj(a)*b
static inline void cmac(complx_d & t, complx_d const& a, complx_d const& b)
{
   t += conj(a) * b;
}

#if defined(__GNUG__) && !defined(__FAST_MATH__)

#warning "use of native complex operators without -ffast_math might degrade performance"
#endif

#else // manual handling of real and imaginary parts

 
/// computes t += conj(a)*b
static inline void cmac(complx_d & t, complx_d const& a, complx_d const& b)
{
   double const ar = real(a);
   double const ai = imag(a);
   double const br = real(b);
   double const bi = imag(b);
   t = complx_d(
      real(t) + (ar*br+ai*bi),
      imag(t) + (ar*bi-ai*br)
   );
}

#endif

Ich sehe keine Notwendigkeit noch weiter zu experimentieren. Vielleicht auf einem anderen Rechner dann wieder... Per Default nehme ich die zweite Variante.

kk
rüdiger
Moderator

Benutzerprofil
Anmeldungsdatum: 11.07.2001
Beiträge: 23086
Beitrag rüdiger Moderator 18:05:06 05.08.2010   Titel:              Zitieren

Frag am besten die GCC Entwickler nach einer Begründung: http://news.gmane.org/gmane.comp.gcc.help

_________________
.
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23665
Beitrag hustbaer Mitglied 01:43:51 06.08.2010   Titel:              Zitieren

unskilled schrieb:
hustbaer schrieb:
Compiler-Magick


Wieder was dazugelernt:
http://de.wikipedia.org/wiki/Magick

war das mit Absicht oder ists nur Zufall, dass es das Wort gibt? :P

Zufall nicht wirklich. Ich wusste dass es ne alte Schreibweise von "magic" im Englischen ist. Allerdings nicht, dass irgendein komischer Okkultist sich diese "angeeignet" hat, und es für nötig hielt daraus ein neues Wort mit leicht anderer Bedeutung zu machen.

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at
knivil
Mitglied

Benutzerprofil
Anmeldungsdatum: 11.02.2009
Beiträge: 7325
Beitrag knivil Mitglied 17:02:39 06.08.2010   Titel:              Zitieren

conj erzeugt ein temporaeres Objekt, auch wenn es nur auf dem Stack ist, der Konstruktor wird immer aufgerufen. Der macht sich gegenueber von wenigen arithmetischen Operationen schon bemerkbar. Bei Variante 2 eben nicht. Deswegen ist das kein Vergleich zwischen zwei Implementationen fuer std::complex sondern ein Vergleich zwischen zwei Implementationen eines Skalarproduktes.

Wenn das der Flaschenhals ist, dann weiche doch auf MMX bzw. SSE aus. Besser ist wohl aber eine Strategie, die die Anzahl der Skalarprodukte/Complex irgendwas verringert.

_________________
If it were not for laughter, there would be no Tao.
Sie können einen Beitrag nicht so schnell nach Ihrem letzten absenden, bitte warten Sie einen Augenblick.


Zuletzt bearbeitet von knivil am 17:09:03 06.08.2010, insgesamt 1-mal bearbeitet
krümelkacker
Unregistrierter




Beitrag krümelkacker Unregistrierter 20:13:23 06.08.2010   Titel:   Hier gibt es keine ungelösten Probleme zu sehen. Weitergehen!            Zitieren

knivil schrieb:

conj erzeugt ein temporaeres Objekt, auch wenn es nur auf dem Stack ist, der Konstruktor wird immer aufgerufen. Der macht sich gegenueber von wenigen arithmetischen Operationen schon bemerkbar.

Die 4% wären es mir sogar wert für die hübschere Syntax. Der Übeltäter sitzt aber ganz woanders und heißt __muldc3. Dieser Implementierung der Berechnung eines Produktes zweier komplexen Zahlen habe ich es zu verdanken, dass die Performance dermaßen in den Keller geht, dass das, worauf Du Dich beziehst, nicht ins Gewicht fällt.

kk
manni66
Unregistrierter




Beitrag manni66 Unregistrierter 20:56:26 06.08.2010   Titel:              Zitieren

Interessant finde ich, dass bei mir die 64-Bit Version mit std::complex deutlich schneller ist als die 32-Bit:

Code:
               32 Bit  64 Bit
-------------+-------+---------
std::complex | 1,67  | 0,44
eigenbau     | 0,21  | 0,19



OpenSuese 11.3 mit gcc4.5

Lars
C++ Forum :: C++ (alle ISO-Standards) ::  std::complex vs. Eigenbau   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.net ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.