32 Bit im Vergleich zu 64 Bit Fließkomma-Performance

8

Ich bin auf ein seltsames Problem gestoßen. Ein Algorithmus, an dem ich arbeite, besteht aus vielen Berechnungen wie dieser

%Vor%

wobei die Länge der Summe zwischen 4 und 7 liegt.

Die ursprünglichen Berechnungen werden alle mit 64-Bit-Genauigkeit durchgeführt. Zum Experimentieren habe ich versucht, 32-Bit-Genauigkeit für x, y, z-Eingabewerte zu verwenden (so dass Berechnungen mit 32-Bit ausgeführt werden) und das Endergebnis als 64-Bit-Wert zu speichern (direkte Umwandlung).

Ich habe erwartet, dass die 32-Bit-Leistung besser ist (Cachegröße, SIMD Größe usw.), aber für meine Überraschung gab es keinen Unterschied in der Leistung, vielleicht sogar abnehmen.

Die fragliche Architektur ist Intel 64, Linux und GCC . Beide Codes scheinen SSE zu verwenden, und Arrays sind in beiden Fällen auf 16-Byte-Grenze ausgerichtet.

Warum sollte es so sein? Meine Vermutung ist so weit, dass die 32-Bit-Genauigkeit SSE nur für die ersten vier Elemente verwenden kann, während der Rest seriell durch den Cast-Overhead ausgeführt wird.

    
Anycorn 29.06.2010, 01:40
quelle

3 Antworten

24

Auf x87 wird alles intern in 80-Bit-Genauigkeit ausgeführt. Die Genauigkeit bestimmt nur, wie viele dieser Bits im Speicher gespeichert sind. Dies ist einer der Gründe, warum verschiedene Optimierungseinstellungen die Ergebnisse leicht ändern können: Sie ändern die Anzahl der Runden von 80-Bit auf 32- oder 64-Bit.

In der Praxis ist die Verwendung von 80-Bit Gleitkommawerten ( long double in C und C ++, real in D) normalerweise langsam, da es keine effiziente Möglichkeit gibt, 80 Bits aus dem Speicher zu laden und zu speichern. 32- und 64-Bit sind normalerweise gleich schnell, vorausgesetzt, dass die Speicherbandbreite nicht der Flaschenhals ist, d. H. Wenn sich sowieso alles im Cache befindet. 64-Bit kann langsamer sein, wenn einer der folgenden Fälle eintritt:

  1. Speicherbandbreite ist der Flaschenhals.
  2. Die 64-Bit-Nummern sind nicht ordnungsgemäß auf 8-Byte-Grenzen ausgerichtet. 32-Bit-Nummern erfordern nur 4-Byte-Ausrichtung für optimale Effizienz, so dass sie weniger knifflig sind. Einige Compiler (der Digital-Mars-D-Compiler kommt mir in den Sinn) finden das nicht immer richtig für 64-Bit-Doubles, die auf dem Stack gespeichert sind. Dies führt dazu, dass doppelt so viele Speicheroperationen erforderlich sind, um einen zu laden, was in der Praxis zu einem etwa 2x höheren Performance-Treffer führt als bei korrekt ausgerichteten 64-Bit-Floats oder 32-Bit-Floats.

Soweit SIMD-Optimierungen gehen, sollte angemerkt werden, dass die meisten Compiler beim automatischen Vektorisieren von Code schrecklich sind. Wenn Sie nicht direkt in die Assemblersprache schreiben möchten, besteht die beste Möglichkeit, diese Anweisungen zu nutzen, darin, Dinge wie Array-artige Operationen zu verwenden, die beispielsweise in D verfügbar sind und in SSE-Anweisungen implementiert sind. Ähnlich, in C oder C ++, würden Sie wahrscheinlich eine High-Level-Bibliothek von Funktionen, die SSE-optimiert sind, verwenden wollen, obwohl ich nicht von einem guten von der Spitze meines Kopfes weiß, weil ich meist in D programmieren.

    
dsimcha 29.06.2010, 03:24
quelle
0

Wahrscheinlich liegt es daran, dass Ihr Prozessor immer noch die 64-Bit-Zählung durchführt und dann die Nummer abschneidet. Es gab einige CPU-Flags, die Sie ändern konnten, aber ich kann mich nicht erinnern ...

    
Alistra 06.07.2010 23:07
quelle
0

Überprüfen Sie zuerst das ASM, das produziert wird. Es kann nicht sein, was Sie erwarten.

Versuchen Sie es auch als Schleife zu schreiben:

%Vor%

Einige Compiler könnten die Schleife und nicht das abgerollte Formular bemerken.

Schließlich verwendete Ihr Code () und nicht [] . Wenn Ihr Code viele Funktionsaufrufe (12 bis 21) ausführt, werden die FP-Kosten überflutet, und selbst das Entfernen der fp-Berechnung insgesamt wird keinen großen Unterschied machen. Inline-OTOH könnte.

    
BCS 10.07.2010 01:54
quelle