C Leistung und Kompilierungsoptionen

9

Ich habe zwei ähnliche Implementierungen (java und c ++) für einen trivialen Algorithmus wie die Auswahl sort.

%Vor%

und die c eins:

%Vor%

Nun habe ich versucht, sie auf einem großen Array (100000 random int) zu testen. Die Ergebnisse waren zuerst Java: ~ 17 Sek. (kompiliert und ausgeführt mit Orakel jdk / jvm) c: ~ 22 Sekunden (kompiliert mit gcc v4.8 ohne Optimierung)

Natürlich habe ich dann versucht, meine c-Version durch cflags zu optimieren. Die Ergebnisse sind (ich melde nur cflags): -O1: ~ 18.4

-O2: ~ 18.4

-O {3-9}: ~ 20.9

Nun, meine erste Frage ist, welche cflacs ich zum kompilieren verwenden soll?

Also habe ich das Gnu-Handbuch über Optimierungen gelesen. Das Hinzufügen von -march = native hat nicht geholfen. Nachdem ich einige Zeit damit verbracht hatte, andere Optionen auszuprobieren, kam ich in die Option -fprofile-arcs. Das Hinzufügen zu meinen Flags hat dazu geführt, dass mein Code seinen Test in ungefähr 11 Sekunden beendet hat! Einige Dateien sind jedoch in meinen Ordnern erschienen: die Ergebnisse der Profilerstellung. Wie ich es verstehe, sollte ich sie mit -fbranch-Wahrscheinlichkeiten verwenden und den Code neu kompilieren. Erneutes Kompilieren der Ergebnisse in ~ 18,5 Sekunden. Und das möchte ich wirklich fragen.

Wie ist es möglich, dass mein Programm so schnell ausgeführt wird, wenn es Dateien schreiben und Profiling-Informationen sammeln muss und stattdessen 1,5 Mal langsamer läuft, wenn nicht?

Ich habe vergessen zu erwähnen, dass ich auf einem alten PC mit einem Intel Celeron @ 2.8GHz Prozessor und Linux (Fedora 20 mit xfce) installiert bin. Wenn Sie weitere Informationen über die Hardware benötigen, fragen Sie einfach nach! ;)

Bearbeiten: Der Code, den ich für den Test verwende, ist:

Java:

%Vor%

Und das c:

%Vor%

Der Code enthält Verweise auf eine Einfügesortierfunktion, die ich nicht in den Rest der Frage einbezogen habe, weil (wie erwartet) Java langsamer ausgeführt wird als c.

    
marco6 10.01.2014, 17:00
quelle

4 Antworten

2
  

Und das ist, was ich wirklich fragen möchte.

     

Wie ist es möglich, dass mein Programm so schnell läuft, wenn es schreiben muss?   Dateien und sammelt Profilinformationen und stattdessen läuft es 1,5 mal   langsamer, wenn nicht?

Ja, das ist die wirkliche Frage hier. Die Erwähnung all dieser Java-Vergleichssachen fügt nur Rauschen hinzu.

Ich könnte das seltsame Verhalten auf meinem Rechner mit gcc 4.7.2 reproduzieren. Es ist nicht überraschend, dass der heiße Pfad des Codes die innere for-Schleife ist:

%Vor%

Der einzige relevante Unterschied im entsprechenden generierten Assembly-Code ist:

Schneller Fall:

%Vor%

Langsamer Fall:

%Vor%

Der erste Fall (schnell) kann sehr von der Verzweigungsvorhersage profitieren, aber der andere (langsame Fall) kann das offenbar nicht. Sortierte oder zufällig gemischte Arrays verursachen nicht zu viele Fehler bei Zweigstellen . Das erste Code-Snippet ist in diesem Fall optimal.

Wie sich herausstellt, ist es in der Tat schwierig, ein Dataset zu erstellen, das bei der Auswahlsortierung eine Menge von Verzweigungsfehlvorhersagen verursacht. (Darauf wurde von Yakk Siehe auch meine Versuche um einen bösen Datensatz zu erstellen, bisher konnte ich keinen erstellen.)

Das -fprofile-arcs schaltet die Baumvektorisierung ab, die für die Erzeugung des langsamen Codes verantwortlich zu sein scheint. Eine bessere Möglichkeit, die Vektorisierung von Bäumen zu deaktivieren, besteht darin, das Flag -fno-tree-vectorize zu übergeben.

clang 3.4 erzeugt auch den schnellen case code, ohne irgendein spezielles Flag. Der Java-Code ohne Aufwärmen läuft 2.4x langsamer als der C-Code. (Da es nicht die Frage war, habe ich mich nicht damit beschäftigt, die Java-Code-Leistung zu verbessern.)

    
Ali 10.01.2014, 19:19
quelle
2

Nicht wirklich eine Antwort, aber zu lang für einen Kommentar.

Ihr Java-Benchmark ist weit davon entfernt, optimal zu sein - insbesondere erlauben Sie nicht, dass sich die JVM ausreichend aufwärmt. Bei richtiger Aufwärmung sinkt die Zeit auf meiner Maschine um 50% (4s vs 8s). Mein vorgeschlagener Code (mit nur dem SelectionSort):

%Vor%

Ausgabe:

  

Vor dem Aufwärmen 7.851840908
  In der Schleife 4.055204123
  In der Schleife 3.878436395
  In der Schleife 3.880136077
  In Schleife 3.882814287

    
assylias 10.01.2014 17:49
quelle
0

Hier sind die Ergebnisse, die ich bekomme. Für mich (gcc 4.6.3) -O3 -funroll-loops gewinnt.

%Vor%

(Hinweis: Die Zeile "Abgelaufene Zeit" schließt die Zeit aus, die für die Erstellung des Testarrays benötigt wird - aber es ist vernachlässigbar).

    
lbolla 10.01.2014 17:39
quelle
-1

Ich bekomme eine 100% ige Beschleunigung (Aufbau mit gcc -O2 ) im C-Programm, wenn ich die Bedingung aus der Swap-Funktion entferne. d.h.:

%Vor%

Der generierte Code ist wahrscheinlich sehr sensitiv für die Verzweigungsprädiktion oder das Pre-Fetching von Caches. Es scheint also nur ein kleiner Unterschied im generierten Code (zB beeinflusst durch verschiedene Compiler-Flags) einen großen Einfluss zu haben.

>

Beachten Sie, dass der Overhead von -fprofile-arcs in diesem Programm klein ist. Zu den eigenen Zeitmessungen gehört auch das Schreiben der Profiling-Datei nicht, aber selbst das Schreiben dieser Daten dauert im Vergleich zu den Ausführungszeiten von 5 oder 10+ Sekunden eine unbedeutende Zeit.

    
nos 10.01.2014 18:52
quelle

Tags und Links