Wie debugge ich ein MPI-Programm?

129

Ich habe ein MPI-Programm, das kompiliert und ausgeführt wird, aber ich möchte es durchgehen, um sicherzustellen, dass nichts Seltsames passiert. Im Idealfall möchte ich eine einfache Möglichkeit, GDB an einen bestimmten Prozess anzuhängen, bin mir jedoch nicht sicher, ob dies möglich ist oder wie dies zu tun ist. Eine Alternative wäre, dass jeder Prozess die Debug-Ausgabe in eine separate Protokolldatei schreibt. Dies bietet jedoch nicht die gleiche Freiheit wie ein Debugger.

Gibt es bessere Ansätze? Wie debuggen Sie MPI-Programme?

Jay Conrod
quelle

Antworten:

62

Wie jemand anderes sagte, ist TotalView der Standard dafür. Aber es kostet dich einen Arm und ein Bein.

Die OpenMPI-Site bietet eine großartige FAQ zum MPI-Debugging . Punkt 6 in den FAQ beschreibt, wie GDB an MPI-Prozesse angehängt wird. Lesen Sie das Ganze, es gibt einige tolle Tipps.

Wenn Sie jedoch feststellen, dass Sie viel zu viele Prozesse haben, um den Überblick zu behalten, lesen Sie das Stack Trace Analysis Tool (STAT) . Wir verwenden dies bei Livermore, um Stack-Traces von potenziell Hunderttausenden laufenden Prozessen zu sammeln und diese für Benutzer intelligent darzustellen. Es ist kein Debugger mit vollem Funktionsumfang (ein Debugger mit vollem Funktionsumfang würde niemals auf 208.000 Kerne skaliert werden), aber es zeigt Ihnen, welche Gruppen von Prozessen dasselbe tun. Sie können dann einen Vertreter aus jeder Gruppe in einem Standard-Debugger durchlaufen.

Todd Gamblin
quelle
14
Ab 2010 ist Allinea DDT ein voll ausgestatteter Debugger, der auf über 208.000 Kerne skaliert
Mark
1
Also werde ich @ Marks Antwort hier positiv bewerten. DDT ist nett. Probieren Sie es auch aus. TotalView lässt sich jetzt auch in STAT integrieren. Wenn Ihre Site über eine TotalView-Installation verfügt, können Sie dies ebenfalls versuchen. LLNL hält TotalView und DDT in der Nähe, und es ist schön, dass TotalView endlich eine harte Konkurrenz hat.
Todd Gamblin
Ich möchte den Link zu den häufig gestellten Fragen zum MPI-Debugging ( open-mpi.org/faq/?category=debugging#serial-debuggers ) unterstützen. Insbesondere ist Bullet 6 eine gute, schnelle und einfache Methode (genug für mich!), Um zumindest einen einzelnen Prozess zu debuggen.
Jeff
Die Schritte in # 6 der FAQ-Seite haben für mich hervorragend funktioniert und mir geholfen, mein Problem herauszufinden. Vielen Dank dafür.
Jon Deaton
86

Ich habe gdb sehr nützlich gefunden. Ich benutze es als

mpirun -np <NP> xterm -e gdb ./program 

Dies startet xterm Windows, in dem ich tun kann

run <arg1> <arg2> ... <argN>

funktioniert normalerweise gut

Sie können diese Befehle auch zusammen packen, indem Sie:

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...]
Messenjah
quelle
Wie kann ich den gleichen Eingang an alle NP gdb xterms senden? Zum Beispiel möchte ich jedem Prozess zwei Haltepunkte hinzufügen, und es gibt 16 Prozesse. Gibt es eine Alternative zu xterm, um dies zu tun? Können wir Sitzungen zu einer einzelnen Instanz von screen, tmux oder Chris Jones 'Terminator verbinden?
Osgx
@osgx Sie können dies tun, indem Sie die Befehle ("break xxx", "break yyy", "run") in gdb speichern <file>und -x <file>an gdb übergeben.
Eush77
aber ich treffe einen Fehler, die Fehlermeldung ist "execvp Fehler auf Datei xterm (keine solche Datei oder Verzeichnis)"
hitwlh
Wenn ich dies mit jdb & OpenMPI versuche, funktioniert es nicht, dh jede jdb-Instanz sieht num_ranks von 1 anstelle dessen, was dem Argument -np gegeben wird. Irgendeine Idee warum?
Michel Müller
26

Viele der Beiträge hier befassen sich mit GDB, erwähnen jedoch nicht, wie Sie einen Prozess vom Start an anhängen können. Natürlich können Sie an alle Prozesse anhängen:

mpiexec -n X gdb ./a.out

Dies ist jedoch äußerst ineffektiv, da Sie herumspringen müssen, um alle Ihre Prozesse zu starten. Wenn Sie nur einen (oder eine kleine Anzahl) MPI-Prozess debuggen möchten, können Sie diesen mithilfe des :Operators als separate ausführbare Datei in der Befehlszeile hinzufügen :

mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out

Jetzt erhält nur einer Ihrer Prozesse GDB.

Wesley Bland
quelle
Ich kann "mpiexec -n X gdb ./a.out" verwenden, aber gibt es eine Möglichkeit, den gdb -tui-Modus zu verwenden?
Hitwlh
16

Wie andere erwähnt haben, sind , wenn Sie mit einem Arbeitshandvoll von MPI Prozesse , die Sie verwenden können versuchen , mehrere GDB - Sitzungen , die gefürchtete valgrind oder rollen Sie Ihre eigenen printf / Logging - Lösung.

Wenn Sie mehr Prozesse verwenden, benötigen Sie wirklich einen geeigneten Debugger. In den OpenMPI-FAQ werden sowohl Allinea DDT als auch TotalView empfohlen .

Ich arbeite an Allinea DDT . Es ist ein grafischer Quellcode-Debugger mit vollem Funktionsumfang. Ja, Sie können:

  • Debuggen oder Anhängen an (über 200.000) MPI-Prozesse
  • Treten Sie ein und halten Sie sie in Gruppen oder einzeln an
  • Fügen Sie Haltepunkte, Uhren und Tracepoints hinzu
  • Speicherfehler und Lecks abfangen

...und so weiter. Wenn Sie Eclipse oder Visual Studio verwendet haben, sind Sie hier genau richtig.

Wir haben einige interessante Funktionen speziell für das Debuggen von parallelem Code hinzugefügt (sei es MPI, Multithread oder CUDA):

  • Skalare Variablen werden automatisch über alle Prozesse hinweg verglichen: (Quelle: allinea.com )Sparklines, die Werte prozessübergreifend anzeigen

  • Sie können auch die Werte von Variablen und Ausdrücken über Prozesse und Zeit verfolgen und filtern: Tracepoints protokollieren Werte im Zeitverlauf

Es ist weit verbreitet unter Top500 HPC-Standorten wie ORNL , NCSA , LLNL , Jülich et. al.

Die Oberfläche ist ziemlich bissig; Im Rahmen der Abnahmetests für den Jaguar-Cluster von Oak Ridge haben wir die Stapel und Variablen von 220.000 Prozessen bei 0,1 Sekunden zeitlich festgelegt und zusammengeführt.

@tgamblin erwähnte den exzellenten STAT , der in Allinea DDT integriert ist , ebenso wie einige andere beliebte Open Source-Projekte.

Kennzeichen
quelle
7

Wenn Sie ein tmuxBenutzer sind, werden Sie sich mit dem Skript von Benedikt Morbach sehr wohl fühlen :tmpi

Originalquelle: https://github.com/moben/scripts/blob/master/tmpi

Gabel: https://github.com/Azrael3000/tmpi

Damit haben Sie mehrere Panels (Anzahl der Prozesse) synchronisiert (jeder Befehl wird gleichzeitig auf alle Panels oder Prozesse kopiert, sodass Sie im Vergleich zum xterm -eAnsatz viel Zeit sparen ). Darüber hinaus können Sie die Werte der Variablen in dem Prozess kennen, den Sie gerade ausführen möchten, printohne in ein anderes Fenster wechseln zu müssen. Dadurch werden auf jedem Feld die Werte der Variablen für jeden Prozess gedruckt.

Wenn Sie kein tmuxBenutzer sind, empfehle ich dringend, es zu versuchen und zu sehen.

GG1991
quelle
2
Da tmpi wirklich fantastisch ist und genau das ist, wonach ich gesucht habe, habe ich es auf meinem Github-Konto gegabelt: github.com/Azrael3000/tmpi, da der ursprüngliche Autor es entfernt hat
Azrael3000
6

http://github.com/jimktrains/pgdb/tree/master ist ein Dienstprogramm, das ich geschrieben habe, um genau dies zu tun. Es gibt einige Dokumente und Sie können mich gerne bei Fragen kontaktieren.

Sie rufen im Grunde ein Perl-Programm auf, das GDB umschließt und dessen E / A an einen zentralen Server überträgt. Auf diese Weise kann GDB auf jedem Host ausgeführt werden und Sie können auf jedem Host am Terminal darauf zugreifen.

Jim Keener
quelle
Vielen Dank! Ich werde das auf jeden Fall überprüfen, wenn ich das nächste Mal im MPI arbeite.
Jay Conrod
5

Die Verwendung screenzusammen mit gdbzum Debuggen von MPI-Anwendungen funktioniert gut, insbesondere wenn diese xtermnicht verfügbar sind oder Sie mit mehr als einigen Prozessoren arbeiten. Es gab viele Fallstricke auf dem Weg mit begleitenden Stackoverflow-Suchen, daher werde ich meine Lösung vollständig reproduzieren.

Fügen Sie zunächst nach MPI_Init Code hinzu, um die PID auszudrucken, und halten Sie das Programm an, um auf das Anhängen zu warten. Die Standardlösung scheint eine Endlosschleife zu sein; Ich habe mich schließlich entschieden raise(SIGSTOP);, was einen zusätzlichen Anruf erfordert continue, um innerhalb von GDB zu entkommen.

}
    int i, id, nid;
    MPI_Comm_rank(MPI_COMM_WORLD,&id);
    MPI_Comm_size(MPI_COMM_WORLD,&nid);
    for (i=0; i<nid; i++) {
        MPI_Barrier(MPI_COMM_WORLD);
        if (i==id) {
            fprintf(stderr,"PID %d rank %d\n",getpid(),id);
        }
        MPI_Barrier(MPI_COMM_WORLD);
    }
    raise(SIGSTOP);
}

Führen Sie nach dem Kompilieren die ausführbare Datei im Hintergrund aus und fangen Sie den stderr ab. Sie können dann grepdie stderr-Datei für ein Schlüsselwort (hier wörtliche PID) verwenden, um die PID und den Rang jedes Prozesses zu erhalten.

MDRUN_EXE=../../Your/Path/To/bin/executable
MDRUN_ARG="-a arg1 -f file1 -e etc"

mpiexec -n 1 $MDRUN_EXE $MDRUN_ARG >> output 2>> error &

sleep 2

PIDFILE=pid.dat
grep PID error > $PIDFILE
PIDs=(`awk '{print $2}' $PIDFILE`)
RANKs=(`awk '{print $4}' $PIDFILE`)

Mit jedem Prozess kann eine GDB-Sitzung verbunden werden gdb $MDRUN_EXE $PID. Dies innerhalb einer Bildschirmsitzung zu tun, ermöglicht den einfachen Zugriff auf jede GDB-Sitzung. -d -mStartet den Bildschirm im getrennten Modus, -S "P$RANK"ermöglicht es Ihnen, den Bildschirm für einen späteren einfachen Zugriff zu benennen, und die -lOption zum Bash startet ihn im interaktiven Modus und verhindert, dass gdb sofort beendet wird.

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    PID=${PIDs[$i]}
    RANK=${RANKs[$i]}
    screen -d -m -S "P$RANK" bash -l -c "gdb $MDRUN_EXE $PID"
done

Sobald gdb in den Bildschirmen gestartet wurde, können Sie mit dem -X stuffBefehl des Bildschirms Skripteingaben in die Bildschirme schreiben (damit Sie nicht jeden Bildschirm eingeben und dasselbe eingeben müssen) . Am Ende des Befehls ist eine neue Zeile erforderlich. Hier wird auf die Bildschirme unter -S "P$i"Verwendung der zuvor angegebenen Namen zugegriffen . Die -p 0Option ist kritisch, andernfalls schlägt der Befehl zeitweise fehl (je nachdem, ob Sie zuvor eine Verbindung zum Bildschirm hergestellt haben oder nicht).

for i in `awk 'BEGIN {for (i=0;i<'${#PIDs[@]}';i++) {print i}}'`
do
    screen -S "P$i" -p 0 -X stuff "set logging file debug.$i.log
"
    screen -S "P$i" -p 0 -X stuff "set logging overwrite on
"
    screen -S "P$i" -p 0 -X stuff "set logging on
"
    screen -S "P$i" -p 0 -X stuff "source debug.init
"
done

An dieser Stelle können Sie mit jedem Bildschirm anhängen screen -rS "P$i"und mit entfernen Ctrl+A+D. Befehle können analog zum vorherigen Codeabschnitt an alle GDB-Sitzungen gesendet werden.

user3788566
quelle
3

Es gibt auch mein Open-Source-Tool padb, das bei der parallelen Programmierung helfen soll. Ich nenne es ein "Job Inspection Tool", da es nicht nur als Debugger fungiert, sondern auch als paralleles Top-ähnliches Programm. Im Modus "Vollständiger Bericht" werden die Spuren jedes Prozesses in Ihrer Anwendung sowie lokale Variablen für jede Funktion über jeden Rang gestapelt (vorausgesetzt, Sie haben mit -g kompiliert). Außerdem werden die "MPI-Nachrichtenwarteschlangen" angezeigt, dh die Liste der ausstehenden Sende- und Empfangsvorgänge für jeden Rang innerhalb des Jobs.

Neben der Anzeige des vollständigen Berichts ist es Padb auch möglich, einzelne Informationen innerhalb des Jobs zu vergrößern. Es gibt eine Vielzahl von Optionen und Konfigurationselementen, mit denen Sie steuern können, welche Informationen angezeigt werden. Weitere Informationen finden Sie auf der Webseite.

Padb


quelle
3

Die "Standard" -Methode zum Debuggen von MPI-Programmen ist die Verwendung eines Debuggers, der dieses Ausführungsmodell unterstützt.

Unter UNIX Totalview ist die gute suppoort für MPI haben.

Gemeinschaft
quelle
2

Ich verwende diese kleine Homebrewn-Methode, um den Debugger an MPI-Prozesse anzuhängen. Rufen Sie die folgende Funktion, DebugWait (), direkt nach MPI_Init () in Ihrem Code auf. Während die Prozesse auf Tastatureingaben warten, haben Sie jederzeit Zeit, den Debugger an sie anzuhängen und Haltepunkte hinzuzufügen. Wenn Sie fertig sind, geben Sie eine einzelne Zeicheneingabe ein und Sie können loslegen.

static void DebugWait(int rank) {
    char    a;

    if(rank == 0) {
        scanf("%c", &a);
        printf("%d: Starting now\n", rank);
    } 

    MPI_Bcast(&a, 1, MPI_BYTE, 0, MPI_COMM_WORLD);
    printf("%d: Starting now\n", rank);
}

Natürlich möchten Sie diese Funktion nur für Debug-Builds kompilieren.


quelle
MPI hat die meisten Debug-Anweisungen benötigt, die ich je für einfachen Code geschrieben habe. (lol) Das kann sehr hilfreich sein.
Troggy
3
Diese Lösung ähnelt Bullet 6 hier ( open-mpi.org/faq/?category=debugging#serial-debuggers ). Sie können Ihren Code ein wenig verbessern, indem Sie ihn hinzufügen gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);. Anschließend fügen Sie den Vorgang durch Eingabe von rsh <hostname_from_print_statement>und schließlich hinzu gdb --pid=<PID_from_print_statement>.
Jeff
2

Der Befehl zum Anhängen von gdb an einen mpi-Prozess ist unvollständig

mpirun -np <NP> xterm -e gdb ./program 

Eine kurze Diskussion über mpi und gdb finden Sie hier

akintayo
quelle
2

Eine ganz einfache Möglichkeit, ein MPI-Programm zu debuggen.

In der Funktion main () addiere sleep (some_seconds)

Führen Sie das Programm wie gewohnt aus

$ mpirun -np <num_of_proc> <prog> <prog_args>

Das Programm startet und geht in den Schlaf.

Sie haben also einige Sekunden Zeit, um Ihre Prozesse nach ps zu finden, gdb auszuführen und an sie anzuhängen.

Wenn Sie einen Editor wie QtCreator verwenden, können Sie diesen verwenden

Debug-> Debugging starten-> An laufende Anwendung anhängen

und finden Sie dort Prozesse.

Fremder
quelle
1

Ich führe ein MPI-bezogenes Debugging mit Protokollspuren durch, aber Sie können gdb auch ausführen, wenn Sie mpich2: MPICH2 und gdb verwenden . Diese Technik ist im Allgemeinen eine gute Vorgehensweise, wenn Sie mit einem Prozess arbeiten, dessen Start über einen Debugger schwierig ist.

Jim Hunziker
quelle
Zu einem anderen Link geändert, der nicht defekt ist, wurde ein Kommentar hinzugefügt.
Jim Hunziker
0

Eine andere Lösung besteht darin, Ihren Code in SMPI, dem simulierten MPI, auszuführen. Das ist ein Open Source Projekt, an dem ich beteiligt bin. Jeder MPI-Rang wird in Threads desselben UNIX-Prozesses konvertiert. Sie können dann einfach gdb verwenden, um die MPI-Ränge zu erhöhen.

SMPI bietet weitere Vorteile für die Untersuchung von MPI-Anwendungen: Hellsehen (Sie können alle Teile des Systems beobachten), Reproduzierbarkeit (mehrere Läufe führen zu genau demselben Verhalten, sofern Sie dies nicht angeben), Fehlen von Heisenbugs (da die simulierte Plattform unterschiedlich gehalten wird vom Gastgeber) usw.

Weitere Informationen finden Sie in dieser Präsentation oder in der entsprechenden Antwort .

Martin Quinson
quelle