it-swarm.com.de

Wie kann ich C++ - Code erstellen, der unter Linux läuft?

Ich habe eine C++ - Anwendung, die unter Linux läuft und gerade optimiert wird. Wie kann ich feststellen, welche Bereiche meines Codes langsam laufen?

1601

Wenn Sie einen Profiler verwenden möchten, verwenden Sie einen der vorgeschlagenen.

Wenn Sie es jedoch eilig haben und Ihr Programm unter dem Debugger manuell unterbrechen können, während es subjektiv langsam ist, gibt es eine einfache Möglichkeit, Leistungsprobleme zu finden.

Halten Sie es einfach mehrere Male an und schauen Sie sich jedes Mal den Aufrufstapel an. Wenn es einen Code gibt, der einen bestimmten Prozentsatz der Zeit verschwendet, 20% oder 50% oder was auch immer, ist dies die Wahrscheinlichkeit, dass Sie ihn bei jedem Sample auf frischer Tat ertappen. Das ist ungefähr der Prozentsatz der Proben, auf denen Sie es sehen werden. Es ist kein fundiertes Rätselraten erforderlich. Wenn Sie eine Vermutung über das Problem haben, wird dies beweisen oder widerlegen.

Möglicherweise haben Sie mehrere Leistungsprobleme unterschiedlicher Größe. Wenn Sie einen von ihnen entfernen, nehmen die verbleibenden einen größeren Prozentsatz ein und sind bei nachfolgenden Durchläufen leichter zu erkennen. Dieser Vergrößerungseffekt kann, wenn er über mehrere Probleme addiert wird, zu wirklich massiven Beschleunigungsfaktoren führen.

Vorsichtsmaßnahme: Programmierer stehen dieser Technik eher skeptisch gegenüber, wenn sie sie nicht selbst angewendet haben. Sie werden sagen, dass Profiler Ihnen diese Informationen geben, aber das ist nur wahr, wenn sie den gesamten Aufrufstapel abtasten und Sie dann einen zufälligen Satz von Beispielen untersuchen lassen. (In den Zusammenfassungen geht der Einblick verloren.) Anrufdiagramme geben Ihnen nicht die gleichen Informationen, weil

  1. sie fassen nicht auf Anweisungsebene zusammen, und
  2. sie geben verwirrende Zusammenfassungen in Gegenwart von Rekursionen.

Sie werden auch sagen, dass es nur bei Spielzeugprogrammen funktioniert, wenn es tatsächlich bei jedem Programm funktioniert, und dass es bei größeren Programmen besser zu funktionieren scheint, da sie tendenziell mehr Probleme haben, diese zu finden. Sie werden sagen, es findet manchmal Dinge, die keine Probleme sind, aber das ist nur wahr, wenn Sie etwas einmal sehen. Wenn Sie ein Problem bei mehr als einer Stichprobe feststellen, handelt es sich um ein echtes Problem.

P.S. Dies kann auch in Multithread-Programmen durchgeführt werden, wenn es eine Möglichkeit gibt, Call-Stack-Beispiele des Thread-Pools zu einem bestimmten Zeitpunkt zu erfassen, wie dies in Java der Fall ist.

Allgemein gilt: Je mehr Abstraktionsebenen in Ihrer Software vorhanden sind, desto wahrscheinlicher ist es, dass dies die Ursache für Leistungsprobleme (und die Möglichkeit zur Beschleunigung) ist.

Hinzugefügt: Es ist möglicherweise nicht offensichtlich, aber die Stapelabtasttechnik funktioniert bei vorhandener Rekursion genauso gut. Der Grund dafür ist, dass die Zeit, die durch das Entfernen eines Befehls eingespart werden würde, durch den Bruchteil der ihn enthaltenden Stichproben angenähert wird, unabhängig davon, wie oft er in einer Stichprobe auftreten kann.

Ein weiterer Einwand, den ich oft höre, ist: " Es wird irgendwo zufällig aufhören und das eigentliche Problem übersehen ". Dies ergibt sich aus einer vorherigen Vorstellung, was das eigentliche Problem ist. Eine wichtige Eigenschaft von Leistungsproblemen ist, dass sie den Erwartungen trotzen. Die Probenahme sagt Ihnen, dass etwas ein Problem ist und Ihre erste Reaktion ist Unglaube. Das ist natürlich, aber Sie können sicher sein, dass es real ist, wenn es ein Problem findet, und umgekehrt.

ADDED: Lassen Sie mich Bayes erklären, wie es funktioniert. Angenommen, es gibt eine Anweisung I (call oder anderweitig), die auf dem Call-Stack einen Bruchteil f der Zeit enthält (und daher so viel kostet). Nehmen wir der Einfachheit halber an, wir wissen nicht, was f ist, aber nehmen wir an, dass es entweder 0,1, 0,2, 0,3, ... 0,9, 1,0 ist und die vorherige Wahrscheinlichkeit für jede dieser Möglichkeiten 0,1 ist, also für alle Diese Kosten sind ebenfalls von vornherein wahrscheinlich.

Nehmen wir dann an, wir nehmen nur 2 Stapelproben und sehen die Anweisung I für beide Proben, die als Beobachtung o=2/2 bezeichnet wird. Dies gibt uns neue Schätzungen der Häufigkeit f von I, entsprechend diesem:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&&f=x)  P(o=2/2&&f >= x)  P(f >= x | o=2/2)

0.1    1     1             0.1          0.1            0.25974026
0.1    0.9   0.81          0.081        0.181          0.47012987
0.1    0.8   0.64          0.064        0.245          0.636363636
0.1    0.7   0.49          0.049        0.294          0.763636364
0.1    0.6   0.36          0.036        0.33           0.857142857
0.1    0.5   0.25          0.025        0.355          0.922077922
0.1    0.4   0.16          0.016        0.371          0.963636364
0.1    0.3   0.09          0.009        0.38           0.987012987
0.1    0.2   0.04          0.004        0.384          0.997402597
0.1    0.1   0.01          0.001        0.385          1

                  P(o=2/2) 0.385                

Die letzte Spalte besagt, dass beispielsweise die Wahrscheinlichkeit, dass f> = 0,5 ist, 92% beträgt, verglichen mit der vorherigen Annahme von 60%.

Angenommen, die vorherigen Annahmen sind unterschiedlich. Angenommen, P (f = 0,1) ist 0,991 (fast sicher), und alle anderen Möglichkeiten sind fast unmöglich (0,001). Mit anderen Worten, unsere vorherige Gewissheit ist, dass I billig ist. Dann bekommen wir:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&& f=x)  P(o=2/2&&f >= x)  P(f >= x | o=2/2)

0.001  1    1              0.001        0.001          0.072727273
0.001  0.9  0.81           0.00081      0.00181        0.131636364
0.001  0.8  0.64           0.00064      0.00245        0.178181818
0.001  0.7  0.49           0.00049      0.00294        0.213818182
0.001  0.6  0.36           0.00036      0.0033         0.24
0.001  0.5  0.25           0.00025      0.00355        0.258181818
0.001  0.4  0.16           0.00016      0.00371        0.269818182
0.001  0.3  0.09           0.00009      0.0038         0.276363636
0.001  0.2  0.04           0.00004      0.00384        0.279272727
0.991  0.1  0.01           0.00991      0.01375        1

                  P(o=2/2) 0.01375                

Jetzt heißt es, dass P (f> = 0,5) 26% ist, verglichen mit der vorherigen Annahme von 0,6%. Mit Bayes können wir also unsere Schätzung der wahrscheinlichen Kosten von I aktualisieren. Wenn die Datenmenge klein ist, werden die Kosten nicht genau angegeben, nur, dass sie groß genug sind, um repariert werden zu können.

Eine weitere Betrachtungsweise nennt sich Regel der Nachfolge . Wenn Sie eine Münze zweimal werfen und beide Male auftauchen, was sagt Ihnen das über die wahrscheinliche Gewichtung der Münze? Die respektierte Antwort lautet, dass es sich um eine Beta-Distribution mit einem Durchschnittswert (Anzahl der Treffer + 1)/(Anzahl der Versuche + 2) = (2 + 1)/(2 + 2) = 75% handelt.

(Der Schlüssel ist, dass wir I mehr als einmal sehen. Wenn wir es nur einmal sehen, sagt uns das nicht viel, außer dass f> 0.)

Selbst eine sehr kleine Anzahl von Mustern kann uns viel über die Kosten der angezeigten Anweisungen erzählen. (Und es werden sie mit einer Frequenz angezeigt, die im Durchschnitt proportional zu ihren Kosten ist. Wenn n Stichproben genommen werden und f die Kosten sind, dann erscheint I auf nf+/-sqrt(nf(1-f)) Stichproben. Beispiel, n=10, f=0.3, das sind 3+/-1.4 Beispiele.)


ADDED, um ein intuitives Gefühl für den Unterschied zwischen Mess- und Zufallsstapelabtastung zu vermitteln:
Es gibt jetzt Profiler, die den Stapel abtasten, sogar zur Zeit der Wanduhr, aber was herauskommt sind Messungen (oder heißer Pfad, oder Hotspot, vor dem sich leicht ein "Flaschenhals" verstecken kann). Was sie Ihnen nicht zeigen (und sie könnten es leicht), sind die tatsächlichen Proben selbst. Und wenn es Ihr Ziel ist, den Engpass zu finden , müssen Sie im Durchschnitt anzeigen , 2 geteilt durch den Zeitanteil. Wenn also 30% der Zeit benötigt werden, wird dies bei 2/.3 = 6.7 Proben im Durchschnitt angezeigt, und die Wahrscheinlichkeit, dass 20 Proben dies anzeigen, beträgt 99,2%.

Hier sehen Sie den Unterschied zwischen der Untersuchung von Messungen und der Untersuchung von Stapelproben von der Stange. Der Flaschenhals kann ein einziger großer Fleck sein, oder eine Vielzahl kleiner, es macht keinen Unterschied.

enter image description here

Das Maß ist horizontal; Hier erfahren Sie, wie viel Zeit bestimmte Routinen in Anspruch nehmen. Die Probenahme erfolgt vertikal. Wenn Sie vermeiden können, was das gesamte Programm in diesem Moment tut , und wenn Sie es in einem zweiten Beispiel sehen , haben Sie das gefunden Engpass. Das ist es, was den Unterschied ausmacht - den gesamten Grund für die aufgewendete Zeit zu sehen, nicht nur, wie viel.

1331
Mike Dunlavey

Sie können Valgrind mit den folgenden Optionen verwenden

valgrind --tool=callgrind ./(Your binary)

Es wird eine Datei mit dem Namen callgrind.out.x generiert. Sie können dann das kcachegrind-Tool verwenden, um diese Datei zu lesen. Sie erhalten eine grafische Analyse von Dingen mit Ergebnissen, z. B. welche Linien wie viel kosten. 

505
Ajay

Ich gehe davon aus, dass Sie GCC verwenden. Die Standardlösung wäre das Profil mit gprof .

Stellen Sie sicher, dass Sie -pg zur Kompilierung hinzufügen, bevor Sie ein Profil erstellen:

cc -o myprog myprog.c utils.c -g -pg

Ich habe es noch nicht ausprobiert, aber ich habe Gutes über google-perftools gehört. Es ist definitiv einen Versuch wert.

Verwandte Frage hier .

Ein paar andere Schlagworte, wenn gprof die Arbeit nicht für Sie erledigt: Valgrind , Intel VTune , Sun DTrace .

316
Nazgob

Neuere Kernel (z. B. die neuesten Ubuntu-Kernel) werden mit den neuen "perf" -Tools (apt-get install linux-tools) AKA perf_events geliefert.

Diese sind mit klassischen Sampling-Profilern ( man-page ) sowie dem fantastischen timechart !

Das Wichtigste ist, dass diese Tools system profiling und nicht nur Process profileing sein können. Sie können die Interaktion zwischen Threads, Prozessen und dem Kernel darstellen und Ihnen das Verständnis der Zeitplanung und E/A-Abhängigkeiten zwischen Prozessen vermitteln.

Alt text

234
Will

Ich würde Valgrind und Callgrind als Basis für meine Profiling-Tool-Suite verwenden. Wichtig ist zu wissen, dass Valgrind im Grunde eine virtuelle Maschine ist:

(wikipedia) Valgrind ist im Wesentlichen ein virtueller Maschine mit Just-in-Time (JIT) Kompilierungstechniken, einschließlich dynamische Neukompilierung. Nichts von Das Originalprogramm wird immer ausgeführt direkt auf dem Hostprozessor . Stattdessen übersetzt Valgrind zuerst die Programm in eine temporäre, einfachere Form Intermediate Representation genannt (IR), was ein Prozessorneutral ist, SSA-basiertes Formular. Nach der Konvertierung ein Werkzeug (siehe unten) steht zur freien Verfügung welche Transformationen es auch wünschen würde auf der IR, bevor Valgrind übersetzt die IR zurück in den Maschinencode und lässt Der Host-Prozessor führt es aus. 

Callgrind ist ein darauf aufbauender Profiler. Der Hauptvorteil ist, dass Sie Ihre Anwendung nicht stundenlang ausführen müssen, um ein zuverlässiges Ergebnis zu erhalten. Schon ein zweiter Durchlauf reicht aus, um absolut zuverlässige Ergebnisse zu erzielen, da Callgrind ein Nicht-SondierungsProfiler ist. 

Ein weiteres Werkzeug, das auf Valgrind aufbaut, ist Massif. Ich benutze es, um die Speicherbelegung des Heap-Speichers zu profilieren. Es funktioniert super Was es macht, ist, dass es Ihnen Momentaufnahmen der Speichernutzung gibt - detaillierte Informationen, WAS WENIGER Prozentsatz des Speichers ist und von der WHO dort gespeichert wurde. Diese Informationen sind zu verschiedenen Zeitpunkten des Anwendungslaufs verfügbar.

68
anon

Die Antwort zum Ausführen von valgrind --tool=callgrind ist ohne einige Optionen nicht vollständig. Normalerweise möchten wir unter Valgrind keine 10 Minuten langsame Startzeit erstellen und unser Programm für bestimmte Aufgaben profilieren.

Das empfehle ich also. Programm zuerst ausführen:

valgrind --tool=callgrind --dump-instr=yes -v --instr-atstart=no ./binary > tmp

Wenn es jetzt funktioniert und wir mit dem Profiling beginnen wollen, sollten wir in einem anderen Fenster laufen:

callgrind_control -i on

Dies aktiviert die Profilerstellung. Um es auszuschalten und die gesamte Aufgabe zu stoppen, verwenden wir möglicherweise:

callgrind_control -k

Jetzt haben wir einige Dateien mit dem Namen callgrind.out. * Im aktuellen Verzeichnis. Um die Ergebnisse der Profilerstellung anzuzeigen, verwenden Sie:

kcachegrind callgrind.out.*

Ich empfehle im nächsten Fenster, auf die Spaltenüberschrift "Selbst" zu klicken, ansonsten wird "main ()" als zeitaufwändigste Aufgabe angesehen. "Selbst" zeigt, wie viel Zeit jede Funktion selbst benötigt hat, nicht zusammen mit abhängigen Personen. 

55
Tõnu Samuel

Dies ist eine Antwort auf die Antwort von Nazgob Gprof .

Ich habe Gprof in den letzten Tagen verwendet und habe bereits drei wesentliche Einschränkungen gefunden, von denen ich bisher noch nirgendwo anders dokumentiert bin:

  1. Bei Multithread-Code funktioniert es nicht richtig, es sei denn, Sie verwenden eine Workaround

  2. Der Aufrufgraph wird durch Funktionszeiger verwirrt. Beispiel: Ich habe eine Funktion namens multithread(), die es mir ermöglicht, eine angegebene Funktion über ein angegebenes Array (beide werden als Argumente übergeben) Multithreading. Gprof betrachtet jedoch alle Aufrufe von multithread() als gleichwertig für die Berechnung der in Kindern verbrachten Zeit. Da einige Funktionen, die ich an multithread() übergeben, viel länger dauern als andere, sind meine Anrufdiagramme meist unbrauchbar. (An diejenigen, die sich fragen, ob das Threading hier das Problem ist: Nein, multithread() kann optional und in diesem Fall nur nacheinander den aufrufenden Thread ausführen).

  3. hier dass "... die Anzahl der Anrufzahlen durch Zählen und nicht durch Sampling abgeleitet wird. Sie sind völlig genau ...". Trotzdem finde ich in meiner Anrufgrafik 5345859132 + 784984078 als Anrufstatistik für meine meistgerufene Funktion, bei der die erste Nummer direkte Anrufe sein soll und die zweiten rekursiven Anrufe (die alle von sich selbst stammen). Da dies implizierte, dass ich einen Fehler hatte, habe ich lange (64-Bit-) Zähler in den Code eingefügt und den gleichen Lauf erneut ausgeführt. Meine Zahlen: 5345859132 direkte und 78094395406 selbstrekursive Aufrufe. Es gibt viele Ziffern dort, deshalb möchte ich darauf hinweisen, dass die rekursiven Aufrufe, die ich messe, 78 Mrd. statt 784 m von Gprof sind: ein Faktor von 100, der unterschiedlich ist. Bei beiden Läufen handelte es sich um Single-Thread-Code und nicht optimierten Code, der eine -g und der andere -pg.

Dies war GNU Gprof (GNU Binutils für Debian) 2.18.0.20080103 unter 64-Bit-Debian Lenny, falls dies jemandem hilft.

53

Benutze Valgrind, Callgrind und Kcachegrind:  

valgrind --tool=callgrind ./(Your binary)

erzeugt callgrind.out.x. Lesen Sie es mit kcachegrind.

Benutze gprof (add -pg):  

cc -o myprog myprog.c utils.c -g -pg 

(nicht so gut für Multi-Threads, Funktionszeiger)

Benutze Google-Perftools:  

Verwendet Zeitabtastungen, E/A- und CPU-Engpässe werden aufgedeckt.

Intel VTune ist das Beste (kostenlos für Bildungszwecke).

Andere: AMD Codeanalyst (seitdem durch AMD CodeXL ersetzt), OProfile, 'perf' tools (apt-get install linux-tools)

14
Ehsan

Für Singlethread-Programme können Sie igprof, The Ignominous Profiler: https://igprof.org/ verwenden.

Es handelt sich hierbei um einen Sampling-Profiler, der sich an die ... long ... Antwort von Mike Dunlavey anlehnt, die die Ergebnisse in einen durchsuchbaren Aufrufstapelbaum packen wird, der mit der Zeit oder dem Speicher, die in jeder Funktion verbraucht werden, entweder kumulativ oder pro Funktion.

4
fwyzard

Dies sind die zwei Methoden, mit denen ich meinen Code beschleunigen kann:

Für CPU-gebundene Anwendungen:

  1. Verwenden Sie einen Profiler im DEBUG-Modus, um fragwürdige Teile Ihres Codes zu identifizieren
  2. Wechseln Sie dann in den RELEASE-Modus und kommentieren Sie die fragwürdigen Abschnitte Ihres Codes aus (stubben Sie ihn mit nichts), bis Sie Änderungen in der Leistung feststellen.

Für E/A-gebundene Anwendungen:

  1. Verwenden Sie im RELEASE-Modus einen Profiler, um fragwürdige Teile Ihres Codes zu identifizieren.

N.B.

Wenn Sie keinen Profiler haben, verwenden Sie den Profiler des armen Mannes. Drücken Sie beim Debuggen Ihrer Anwendung auf Pause. Die meisten Entwickler-Suites werden mit kommentierten Zeilennummern in Assembly eingebrochen. Sie landen statistisch wahrscheinlich in einer Region, die die meisten Ihrer CPU-Zyklen beansprucht.

Für CPU ist der Grund für die Profilerstellung im ModusDEBUGder Fall, weil der Compiler, wenn Sie imRELEASEModus versucht haben, die Mathematik zu reduzieren, Schleifen und Inline-Funktionen zu vektorisieren Ihr Code wird zu einem nicht zuordenbaren Chaos, wenn er zusammengestellt wird. Ein nicht zuordenbares Chaos bedeutet, dass Ihr Profiler nicht eindeutig erkennen kann, was so lange dauert, da die Assembly möglicherweise nicht dem Quellcode unter Optimierung entspricht . Wenn Sie die Leistung desRELEASE- Modus benötigen (beispielsweise zeitabhängig), deaktivieren Sie die Debugger-Funktionen nach Bedarf, um eine nutzbare Leistung zu erhalten.

Für E/A-gebunden kann der Profiler immer noch E/A-Vorgänge im ModusRELEASEidentifizieren, da E/A-Vorgänge entweder extern (meistens) mit einer gemeinsam genutzten Bibliothek oder im schlimmsten Fall verknüpft sind. führt zu einem Sys-Call-Interrupt-Vektor (der auch vom Profiler leicht zu identifizieren ist).

2
seo

Erwähnenswert sind auch

  1. HPCToolkit ( http://hpctoolkit.org/ ) - Open Source, arbeitet für parallele Programme und verfügt über eine grafische Benutzeroberfläche, mit der die Ergebnisse auf verschiedene Weise angezeigt werden können
  2. Intel VTune ( https://software.intel.com/en-us/vtune ) - Wenn Sie Intel Compiler haben, ist dies sehr gut 
  3. TAU ( http://www.cs.uoregon.edu/research/tau/home.php

Ich habe HPCToolkit und VTune verwendet, und sie sind sehr effektiv bei der Suche nach der langen Stange im Zelt und benötigen keine Neukompilierung Ihres Codes (außer dass Sie den Typ -g -O oder RelWithDebInfo-Typ in CMake verwenden müssen, um eine sinnvolle Ausgabe zu erhalten.) . Ich habe gehört, dass TAU in seinen Fähigkeiten ähnlich ist.

1
raovgarimella

Sie können ein Protokollierungsframework wie loguru verwenden, da es Zeitstempel und Gesamtverfügbarkeit enthält, die sich gut für die Profilerstellung eignen:

  

0
BullyWiiPlaza

Sie können die iprof-Bibliothek verwenden:

https://gitlab.com/Neurochrom/iprof

https://github.com/Neurochrom/iprof

Es ist plattformübergreifend und ermöglicht es Ihnen, die Leistung Ihrer Anwendung nicht auch in Echtzeit zu messen. Sie können es sogar mit einer Live-Grafik koppeln.

0
N3UR0CHR0M

Bei der Arbeit haben wir ein wirklich nettes Tool, mit dem wir überwachen können, was wir in Bezug auf die Planung wollen. Dies hat sich mehrfach bewährt.

Es ist in C++ und muss an Ihre Bedürfnisse angepasst werden. Leider kann ich keinen Code teilen, nur Konzepte. Sie verwenden einen "großen" volatile-Puffer mit Zeitstempeln und Ereignis-ID, den Sie post mortem oder nach dem Stoppen des Protokollierungssystems sichern können (und den Sie beispielsweise in eine Datei sichern können).

Sie rufen den sogenannten großen Puffer mit allen Daten ab und eine kleine Schnittstelle parst ihn und zeigt Ereignisse mit Namen (hoch/runter + Wert) wie ein Oszilloskop mit Farben (konfiguriert in der Datei .hpp).

Sie können die Anzahl der generierten Ereignisse so anpassen, dass Sie sich ausschließlich auf das konzentrieren, was Sie möchten. Es hat uns sehr geholfen, Probleme zu planen und gleichzeitig die Menge an CPU zu verbrauchen, die wir basierend auf der Anzahl der protokollierten Ereignisse pro Sekunde benötigen.

Sie benötigen 3 Dateien:

toolname.hpp // interface
toolname.cpp // code
tool_events_id.hpp // Events ID

Das Konzept besteht darin, Ereignisse in tool_events_id.hpp folgendermaßen zu definieren:

// EVENT_NAME                         ID      BEGIN_END BG_COLOR NAME
#define SOCK_PDU_RECV_D               0x0301  //@D00301 BGEEAAAA # TX_PDU_Recv
#define SOCK_PDU_RECV_F               0x0302  //@F00301 BGEEAAAA # TX_PDU_Recv

Sie definieren auch einige Funktionen in toolname.hpp:

#define LOG_LEVEL_ERROR 0
#define LOG_LEVEL_WARN 1
// ...

void init(void);
void probe(id,payload);
// etc

Wo auch immer Sie Code verwenden können:

toolname<LOG_LEVEL>::log(EVENT_NAME,VALUE);

Die Funktion probe verwendet einige Assembly-Zeilen, um den Zeitstempel der Uhr so ​​schnell wie möglich abzurufen, und setzt dann einen Eintrag in den Puffer. Wir haben auch ein atomares Inkrement, um sicher einen Index zu finden, in dem das Protokollereignis gespeichert werden kann. Natürlich ist der Puffer kreisförmig.

Hoffe, die Idee wird nicht durch das Fehlen von Beispielcode verschleiert.

0
SOKS

Da niemand Arm MAP erwähnte, würde ich es als persönlich hinzufügen. Ich habe Map erfolgreich verwendet, um ein wissenschaftliches C++ - Programm zu profilieren.

Arm MAP ist der Profiler für parallele, Multithread- oder Singlethread-C-, C++ -, Fortran- und F90-Codes. Es bietet eine detaillierte Analyse und eine Engpasserkennung für die Quelllinie. Im Gegensatz zu den meisten Profilern können hier PThreads, OpenMP oder MPI für parallelen und Thread-Code profiliert werden.

MAP ist kommerzielle Software.

0
Wei