Das Fazit hier:
Wie viel besser sind Fortran-Compiler wirklich?
ist, dass gfortran und gcc für einfachen Code genauso schnell sind. Also wollte ich etwas komplizierteres ausprobieren. Ich nahm das Spektralnorm-Shootout-Beispiel. Ich berechne zuerst die 2D-Matrix A (:, :) und dann die Norm. (Ich denke, diese Lösung ist im Shootout nicht zulässig.) Ich habe die Fortran- und C-Version implementiert. Hier ist der Code:
https://github.com/certik/spectral_norm
Die schnellsten Gfortran-Versionen sind spectral_norm2.f90 und spectral_norm6.f90 (eine verwendet das in Fortran integrierte matmul und dot_product, die andere implementiert diese beiden Funktionen im Code - ohne Geschwindigkeitsunterschied). Der schnellste C / C ++ - Code, den ich schreiben konnte, ist spectral_norm7.cpp. Timings ab der Git-Version 457d9d9 auf meinem Laptop sind:
$ time ./spectral_norm6 5500
1.274224153
real 0m2.675s
user 0m2.520s
sys 0m0.132s
$ time ./spectral_norm7 5500
1.274224153
real 0m2.871s
user 0m2.724s
sys 0m0.124s
Gfortrans Version ist also etwas schneller. Warum das? Wenn Sie eine Pull-Anfrage mit einer schnelleren C-Implementierung senden (oder einfach einen Code einfügen), aktualisiere ich das Repository.
In Fortran lasse ich ein 2D-Array herumlaufen, während ich in CI ein 1D-Array verwende. Fühlen Sie sich frei, ein 2D-Array oder eine andere Weise zu verwenden, die Sie für richtig halten.
In Bezug auf Compiler vergleichen wir gcc mit gfortran, icc mit ifort und so weiter. (Im Gegensatz zur Shootout-Seite, die ifort mit gcc vergleicht.)
Update : Mit der Version 179dae2, die matmul3 () in meiner C-Version verbessert, sind sie jetzt so schnell:
$ time ./spectral_norm6 5500
1.274224153
real 0m2.669s
user 0m2.500s
sys 0m0.144s
$ time ./spectral_norm7 5500
1.274224153
real 0m2.665s
user 0m2.472s
sys 0m0.168s
Die vektorisierte Version von Pedro unten ist schneller:
$ time ./spectral_norm8 5500
1.274224153
real 0m2.523s
user 0m2.336s
sys 0m0.156s
Wie Laxxy weiter unten für Intel-Compiler berichtet, scheint es keinen großen Unterschied zu geben, und selbst der einfachste Fortran-Code (spectral_norm1) gehört zu den schnellsten.
Antworten:
Zunächst einmal vielen Dank für das Posten dieser Frage / Herausforderung! Als Haftungsausschluss bin ich ein gebürtiger C-Programmierer mit Fortran-Erfahrung und fühle mich in C am wohlsten. Daher werde ich mich nur auf die Verbesserung der C-Version konzentrieren. Ich lade alle Fortran-Hacks ein, mitzumachen!
Nur um Neulinge daran zu erinnern, worum es geht: Die Grundvoraussetzung in diesem Thread war, dass gcc / fortran und icc / ifort, da sie jeweils die gleichen Backends haben, für dasselbe (semantisch identische) Programm einen entsprechenden Code erzeugen sollten, unabhängig davon davon in C oder Fortran. Die Qualität des Ergebnisses hängt nur von der Qualität der jeweiligen Implementierungen ab.
Ich habe ein wenig mit dem Code herumgespielt und auf meinem Computer (ThinkPad 201x, Intel Core i5 M560, 2,67 GHz) mit
gcc
4.6.1 und den folgenden Compiler-Flags gearbeitet:Ich habe auch eine SIMD-vektorisierte C-Sprachversion des C ++ - Codes geschrieben
spectral_norm_vec.c
:Alle drei Versionen wurden mit denselben Flags und derselben
gcc
Version kompiliert . Beachten Sie, dass ich den Hauptfunktionsaufruf von 0..9 in eine Schleife eingebunden habe, um genauere Timings zu erhalten.Mit "besseren" Compiler-Flags übertrifft die C ++ - Version die Fortran-Version, und handcodierte vektorisierte Schleifen bieten nur eine marginale Verbesserung. Ein kurzer Blick auf den Assembler für die C ++ - Version zeigt, dass die Hauptschleifen ebenfalls vektorisiert wurden, wenn auch aggressiver abgewickelt.
Ich habe mir auch den Assembler von angeschaut
gfortran
und hier ist die große Überraschung: keine Vektorisierung. Ich schreibe die Tatsache zu, dass es nur unwesentlich langsamer ist, wenn die Bandbreite begrenzt ist, zumindest in meiner Architektur. Für jede der Matrixmultiplikationen werden 230 MB Daten durchlaufen, wodurch praktisch alle Cache-Ebenen überlastet werden. Wenn Sie beispielsweise einen kleineren Eingabewert verwenden100
, nehmen die Leistungsunterschiede erheblich zu.Anstatt von Vektorisierung, Ausrichtung und Compiler-Flags besessen zu sein, besteht die offensichtlichste Optimierung darin, die ersten paar Iterationen in Arithmetik mit einfacher Genauigkeit zu berechnen, bis wir ~ 8 Ziffern des Ergebnisses haben. Die Befehle mit einfacher Genauigkeit sind nicht nur schneller, sondern die Menge an Speicher, die verschoben werden muss, halbiert sich auch.
quelle
gcc
/ verwendengfortran
Sie aus Neugier ? In den vorherigen Threads ergaben verschiedene Versionen signifikant unterschiedliche Ergebnisse.matmul2
in der Fortran-Version semantischmatmul3
in meiner C-Version entspricht. Die beiden Versionen sind wirklich jetzt gleich und somitgcc
/gfortran
sollte die gleichen Ergebnisse für beide produziert, zB keine Front-End / Sprache ist besser als die andere in diesem Fall.gcc
hat nur den Vorteil, dass wir vektorisierte Anweisungen ausnutzen können, wenn wir dies wünschen.vector_size
Attribut entschieden, um den Code plattformunabhängig zu machen, dh mit dieser Syntaxgcc
sollte es möglich sein, vektorisierten Code für andere Plattformen zu generieren, z. B. mit AltiVec in der IBM Power-Architektur.Die Antwort von user389 wurde gelöscht, aber lassen Sie mich feststellen, dass ich fest in seinem Lager bin: Ich sehe nicht, was wir lernen, indem ich Mikro-Benchmarks in verschiedenen Sprachen vergleiche. Es ist für mich keine große Überraschung, dass C und Fortran auf diesem Benchmark in Anbetracht der kurzen Zeit ungefähr die gleiche Leistung erbringen. Der Benchmark ist aber auch langweilig, da er problemlos in zwei Sprachen in ein paar Dutzend Zeilen geschrieben werden kann. Aus Sicht der Software ist dies kein repräsentativer Fall: Wir sollten uns mit Software befassen, die 10.000 oder 100.000 Codezeilen enthält, und wie Compiler dies tun. Auf dieser Skala wird man natürlich schnell andere Dinge herausfinden: Für Sprache A sind 10.000 Zeilen erforderlich, für Sprache B sind 50.000. Oder umgekehrt, je nachdem, was Sie tun möchten. Und plötzlich ist es
Mit anderen Worten, es spielt für mich keine Rolle, dass meine Anwendung möglicherweise 50% schneller wäre, wenn ich sie in Fortran 77 entwickeln würde. Stattdessen würde ich nur 1 Monat brauchen, um sie ordnungsgemäß auszuführen, während ich 3 Monate brauchen würde in F77. Das Problem bei dieser Frage ist, dass sie sich auf einen Aspekt (einzelne Kernel) konzentriert, der aus meiner Sicht in der Praxis nicht relevant ist.
quelle
Es stellt sich heraus, dass ich einen Python-Code (mit numpy, um die BLAS-Operationen auszuführen) schneller schreiben kann als den Fortran-Code, der mit dem Gfortran-Compiler meines Systems kompiliert wurde.
foo1.py:
und sn6a.f90, ein sehr leicht modifizierter spectral_norm6.f90:
quelle
Dies wurde mit Intel-Compilern überprüft. Mit 11.1 (-fast, impliziert -O3) und mit 12.0 (-O2) sind die schnellsten 1,2,6,7 und 8 (dh die "einfachsten" Fortran- und C-Codes und das handvektorisierte C) - diese sind bei ~ 1,5s nicht voneinander zu unterscheiden. Die Tests 3 und 5 (mit Array als Funktion) sind langsamer. # 4 Ich konnte nicht kompilieren.
Bemerkenswerterweise verlangsamen beim Kompilieren mit 12.0 und -O3 anstelle von -O2 die ersten 2 ("einfachsten") Fortran-Codes VIEL (1,5 -> 10,2 Sek.) - dies ist nicht das erste Mal, dass ich so etwas sehe dies, aber dies kann das dramatischste Beispiel sein. Wenn dies in der aktuellen Version immer noch der Fall ist, ist es meiner Meinung nach eine gute Idee, dies Intel zu melden, da in diesem eher einfachen Fall eindeutig etwas mit den Optimierungen nicht stimmt.
Ansonsten stimme ich Jonathan zu, dass dies keine besonders informative Übung ist :)
quelle