Profiling von CFD-Code mit Callgrind

16

Ich benutze Valgrind + Callgrind, um einen von mir geschriebenen Solver zu profilieren. Wie im Valgrind-Benutzerhandbuch angegeben, habe ich meinen Code mit den Debugging-Optionen für den Compiler kompiliert:

"Ohne Debugging-Informationen können die Valgrind-Tools nur raten, zu welcher Funktion ein bestimmter Code gehört, was sowohl Fehlermeldungen als auch die Ausgabe von Profilen nahezu unbrauchbar macht. Mit -g erhalten Sie Meldungen, die direkt auf diesen Code verweisen die entsprechenden Quelltextzeilen. "

Valgrind Handbuch

Bei der Kompilierung mit der Debugging-Option werden die Codes viel langsamer ausgeführt. CFD-Code wird WIRKLICH langsam, auch in kleinen Fällen, wenn er mit Debugging-Flags kompiliert wird. Valgrind macht es 40x langsamer (siehe Handbuch 1 ).

  1. Welche Tools verwenden Sie für das Code-Profiling (Profiling, nicht Benchmarking)?

  2. Wie lange lässt du den Code laufen (Statistik: wie viele Zeitschritte)?

  3. Wie groß sind die Fälle (wenn der Fall in den Cache passt, ist der Solver um Größenordnungen schneller, aber dann werde ich die speicherbezogenen Prozesse vermissen)?

tmaric
quelle
3
Sie können den Code sowohl mit aktivierten Debugging-Symbolen als auch mit aktivierter Optimierung kompilieren. Dennoch ist 40x durch Valgrind (das den gesamten Speicherzugriff simuliert) nicht unangemessen.
Aron Ahmadia
Danke, das habe ich auch gelesen ... Was ich gerne wissen möchte, sind Infos über die alltäglichen Erfahrungen beim Profiling (vorzugsweise mit Valgrind): Wie viel Zeit ist normal, um auf die Berichte zu warten, wie viele Iterationen
Zählimpulse
Ihre Frage ist auch ein bisschen breit. Ich empfehle, Ihre Frage nach unten zu bearbeiten, um sich auf Q2.1 und Q2.2 zu konzentrieren, da Q1 eine völlig andere Frage ist (ich freue mich, dass Sie sie separat stellen, es ist eine gute Frage, aber formulieren Sie sie als "Welche Tools würden Sie" verwenden, um das Problem X "zu lösen, in dem X gut beschrieben ist!), während Q2 allein zu allgemein ist.
Aron Ahmadia
Können Sie auch auf Namen bearbeiten callgrind, cachegrindoder massif. Viele Leute verbinden Valgrind nur mit dem Standardwerkzeug ( memcheck). Als emulationsbasiertes (anstatt interruptbasiertes) Profilsystem sollten Sie nicht lange laufen müssen.
Jed Brown
@Aron & Jed: danke für die tipps, ich habe die frage bearbeitet. :)
tmaric

Antworten:

11

F1: Welche Tools verwenden Sie für das Code-Profiling (Profiling, nicht Benchmarking)?

F2: Wie lange lässt du den Code laufen (Statistik: wie viele Zeitschritte)?

F3: Wie groß sind die Fälle (wenn der Fall in den Cache passt, ist der Solver um Größenordnungen schneller, aber dann werde ich die speicherbezogenen Prozesse vermissen)?

Hier ist ein Beispiel, wie ich es mache.

Ich trenne das Benchmarking (wie lange es dauert) vom Profiling (wie man es schneller macht). Es ist nicht wichtig, dass der Profiler schnell ist. Es ist wichtig, dass Sie wissen, was Sie beheben müssen.

Ich mag das Wort "Profiling" nicht einmal, weil es ein Bild wie ein Histogramm erzeugt, bei dem es für jede Routine eine Kostenleiste gibt, oder "Engpass", weil es impliziert, dass es nur einen kleinen Platz im Code gibt, der sein muss Fest. Beides setzt eine Art Timing und Statistik voraus, für die Sie Genauigkeit für wichtig halten. Es lohnt sich nicht, die Einsicht für die Genauigkeit des Timings aufzugeben.

Die Methode , die ich verwenden ist zufällig Pausieren, und es gibt eine vollständige Fallstudie und Dia - Show hier . Ein Teil der Weltanschauung zum Profiler-Engpass ist, dass man, wenn man nichts findet, nichts zu finden hat, und wenn man etwas findet und eine gewisse prozentuale Beschleunigung erreicht, erklärt man den Sieg und gibt auf. Profiler-Fans geben fast nie an, wie viel Geschwindigkeit sie erreichen, und die Anzeigen zeigen nur künstlich erfundene Probleme, die so gestaltet sind, dass sie leicht zu finden sind. Beim zufälligen Anhalten treten Probleme auf, unabhängig davon, ob sie einfach oder schwer sind. Wenn Sie dann ein Problem beheben, werden andere offengelegt, sodass der Vorgang wiederholt werden kann, um eine höhere Geschwindigkeit zu erzielen.

Nach meiner Erfahrung aus zahlreichen Beispielen funktioniert das folgendermaßen: Ich kann ein Problem finden (durch zufälliges Anhalten) und es beheben, indem ich eine Beschleunigung von einigen Prozent erhalte, z. B. 30% oder 1,3x. Dann kann ich es wieder tun, ein anderes Problem finden und es beheben, eine weitere Beschleunigung erzielen, vielleicht weniger als 30%, vielleicht mehr. Dann kann ich es mehrmals wiederholen, bis ich wirklich nichts mehr zu reparieren finde. Der ultimative Beschleunigungsfaktor ist das laufende Produkt der einzelnen Faktoren und kann in einigen Fällen erstaunlich groß sein - Größenordnungen.

INSERTED: Nur um diesen letzten Punkt zu veranschaulichen. Es gibt ein ausführliches Beispiel hier , mit Dia - Show und alle Dateien, die zeigen , wie ein Speedup von 730x wurde in einer Reihe von Problem Umzüge erreicht. Die erste Version benötigte 2700 Mikrosekunden pro Arbeitseinheit. Problem A wurde entfernt, wodurch die Zeit auf 1800 gesenkt und der Prozentsatz der verbleibenden Probleme um das 1,5-fache (2700/1800) vergrößert wurde. Dann wurde B entfernt. Dieser Prozess wurde durch sechs Iterationen fortgesetzt, was zu einer Beschleunigung um fast drei Größenordnungen führte. Die Profiling-Technik muss jedoch sehr effektiv sein. Wenn eines dieser Probleme nicht gefunden wird, dh wenn Sie einen Punkt erreichen, an dem Sie fälschlicherweise glauben, dass nichts mehr getan werden kann, wird der Prozess unterbrochen.

Beschreibung des Entfernens mehrerer Probleme, um eine hohe Geschwindigkeit zu erzielen

INSERTED: Um es anders auszudrücken, hier ist ein Diagramm des Gesamtbeschleunigungsfaktors, wenn aufeinanderfolgende Probleme beseitigt werden:

Bildbeschreibung hier eingeben

Für das Benchmarking von Q1 reicht also ein einfacher Timer aus. Für das "Profiling" verwende ich zufällige Pausen.

F2: Ich gebe ihm genug Arbeitslast (oder lege einfach eine Schleife darum), damit es lange genug läuft, um anzuhalten.

F3: Stellen Sie auf jeden Fall eine realistisch hohe Arbeitslast zur Verfügung, damit Sie keine Cache-Probleme verpassen. Diese werden als Beispiele im Code angezeigt, der die Speicherabrufe ausführt.

Mike Dunlavey
quelle
Mike, hast du eine Vorliebe dafür, wie man willkürlich pausiert, wenn keine visuelle IDE vorhanden ist? Kann dieser Prozess auf irgendeine Weise automatisiert werden?
Matthew Emmett
@Matthew: Ich verstehe, dass es Tools wie pstackund gibt lsstack, aber ich halte das für einen Prozess, der eher mit dem Debuggen zu tun hat. Selbst wenn der beste Debugger, den ich zum Tragen bringen kann, ist gdb, erledigt er die Arbeit. Mit einem Debugger können Sie Daten untersuchen, und das kann den Unterschied ausmachen, wenn der Stack alleine nicht genug aussagt.
Mike Dunlavey
9

Der Profiler des armen Mannes ist im Grunde ein gdbSkript, das den Aufrufstapel abtastet. Sie benötigen weiterhin Debugsymbole. Es ist immer noch langsam, aber da es keine virtuelle Maschine implementiert, auf der der Code ausgeführt wird, ist es häufig schneller callgrindund für die Aufgabe angemessen.

Ich habe in Analysatoren auf Teilchenphysik laufen mit mäßigem Erfolg (dh ich gezeigt , dass der Code habe nicht irgendwelche schrecklichen Hot Spots und Optimierung würde einen besseren Algorithmus verlangen).

dmckee
quelle
1
+ Das Fehlen von Beweisen ist kein Beweis für das Fehlen :) Was der Profiler dieses armen Mannes tun sollte, ist, weniger Spuren zu nehmen und sie nicht zu kollabieren, sondern sie zu sehen. Das menschliche Auge kann nützliche Muster weitaus besser erkennen als einfache Schätzungen der Funktionszeit, und wenn Sie etwas sehen, das Sie an nur 2 Proben verbessern könnten, hilft dies erheblich. Der Bruchteil X, den es speichert, ist eine Beta-Verteilung mit Modus 2 / N, wobei N die Anzahl der untersuchten Spuren ist und der Beschleunigungsfaktor 1 / (1-X) ist, was groß sein kann.
Mike Dunlavey
2

Um die verfügbaren großartigen Antworten zu ergänzen, gibt es ein bei Rice entwickeltes Tool, das die Stapelabtastung automatisiert und daher nur einen geringen Overhead verursacht:

http://hpctoolkit.org/

Reid. Atcheson
quelle
Das sieht aber gut aus (sorry) Ich habe hier meinen Flammenhut aufgesetzt. Ich stimme nicht auf Compiler-optimierten Code ab, weil es schwierig ist zu sehen, was in verstümmeltem Code vor sich geht. Die Dinge, die ich beschneide, sind keine Dinge, mit denen der Optimierer umgehen könnte - wie das Aufrufen expund logwiederholte Verwenden derselben Argumente oder Matrixoperationen, die ihre gesamte Zeit mit Decodierungsoptionen verbringen. Ich stimme so weit ich kann ab und schalte dann -O3 ein.
Mike Dunlavey
Werkzeuge sind Werkzeuge und nur dann nützlich, wenn der Benutzer ihre Grenzen kennt und versteht. Ich denke nicht, dass es jemals einen "perfekten Profiler" geben wird, der den Benutzer vollständig von der Gleichung entfernt, um seine Ausgabe zu verstehen und zu wissen, wie man die Informationen verwendet.
Reid.Atcheson
1

Allinea MAP ist ein kommerziell entwickelter und unterstützter Sampling-Profiler und kann daher - wie das in einer früheren Antwort vorgeschlagene HPC-Toolkit - auf Wunsch für produktionsgroße Jobs ausgeführt werden.

Diese Art von Tool weist auf CPU-Engpässe oder eine schlechte MPI-Kommunikation hin, aber auch die vollständige Überwachung der Profilerstellung für den gesamten Auftrag kann bei der Suche nach Überraschungsproblemen von unschätzbarem Wert sein.

In Bereichen, die nicht erwartet wurden, gibt es häufig niedrig hängende Performance-Früchte, die sich außerhalb des Kernkerns eines CFD-Codes befinden. Zufällige Stapelabtastung ist - ob manuell mit GDB oder mit Tools wie HPC Toolkit und Allinea MAP - der beste Weg, um sie zu finden. Wenn etwas für die Leistung wichtig ist, wird es angezeigt.

David
quelle