Freigeben über


Exemplarische Vorgehensweise: Starten des MPI-Clusterdebuggers in Visual Studio 2010

Diese exemplarische Vorgehensweise zeigt, wie Sie eine MPI-Clusterdebugger-Sitzung auf Ihrem lokalen Computer und auf einem Microsoft Windows HPC Server 2008-Cluster einrichten und starten. Diese exemplarische Vorgehensweise umfasst die Schritte und den Beispielcode, die Sie zum Erstellen einer Anwendung benötigen, die die Anwendungsprogrammierschnittstellen (Application Programming Interfaces, APIs) MPI (Message Passing Interface) und OpenMP (Open Multi-Processing) verwendet.

Inhalt dieser Anleitung:

  • Anforderungen für die Verwendung des MPI-Clusterdebuggers

  • Erstellen eines C++-MPI-Beispielprojekts in Visual Studio 2010

  • Konfigurieren und Starten des MPI-Clusterdebuggers

  • Anhang: Von Visual Studio zusätzlich zu den Anwendungsbinärdateien (und CRT, falls erforderlich) bereitgestellte Dateien

Anforderungen für die Verwendung des MPI-Clusterdebuggers

  • Es muss Visual Studio 2010 Professional Edition oder höher (einschließlich Remotedebugger) auf dem Entwicklungscomputer installiert sein.

  • Sie müssen Administratorrechte für das Cluster besitzen.

  • Visual Studio muss auf die Berechnungsknoten zugreifen können, auf denen Sie die Debugsitzung ausführen möchten. Die folgenden Szenarios bieten den erforderlichen Zugriff:

    • Sie entwickeln Ihre Anwendung auf dem Cluster-Hauptknoten oder auf einem dedizierten Anmeldeknoten.

    • Sie verwenden einen Cluster, bei dem die Berechnungsknoten mit dem Unternehmensnetzwerk (Topologie 2, 4 oder 5) verbunden sind, und der Entwicklungscomputer ist mit derselben Domäne verbunden oder mit einer Domäne, die eine Vertrauensstellung mit der Clusterdomäne hat.

  • Um die Anwendung von einem Clientcomputer an einen HPC-Cluster zu senden, muss Microsoft HPC Pack 2008 installiert sein.

  • Zum Erstellen von MPI-Programmen mithilfe von Microsoft Message Passing Interface muss Windows HPC Server 2008 SDK auf dem Entwicklungscomputer installiert sein.

Erstellen eines C++-MPI-Beispielprojekts in Visual Studio 2010

Der Beispielcode in diesem Abschnitt gilt für eine Parallelanwendung, die dem Wert von Pi unter Verwendung einer Monte Carlo-Simulation angenähert ist.

Der Beispielcode durchläuft bei jedem MPI-Prozess 50.000.000 Iterationen. Bei jeder Iteration generiert der Beispielcode Zufallszahlen im Intervall [0,1], um einen Satz von x- und y-Koordinaten bestimmen. Die Koordinaten werden ausgewertet, um zu ermitteln, ob der Punkt unter die Linie x2 + y2 = 1 fällt. Wenn der Punkt unter der Linie liegt, wird die Variable count um eins erhöht. Der Wert von count der einzelnen MPI-Prozesse wird in der Variable result summiert. Die Gesamtzahl der Punkte, die unter der Linie liegen (result) wird mit vier multipliziert und dann durch die Gesamtzahl der Iterationen dividiert, um sie dem Wert von Pi anzunähern.

Das folgende Verfahren umfasst zwei Implementierungen der Monte Carlo-Simulation.

  • Das erste Beispiel verwendet MPI und OpenMP. Weitere Informationen zu OpenMP finden Sie unter OpenMP in Visual C++.

  • Das zweite Beispiel verwendet MPI und PPL (Parallel Patterns Library). Weitere Informationen zu PPL finden Sie unter Parallel Patterns Library (PLL).

So erstellen Sie das Beispielprojekt

  1. Führen Sie Visual Studio 2010 aus.

  2. Erstellen Sie eine neue C++-Win32-Konsolenanwendung mit dem Namen ParallelPI. Verwenden Sie ein Projekt ohne vorkompilierte Header.

    1. Zeigen Sie im Menü Datei auf Neu, und klicken Sie dann auf Projekt.

    2. Klicken Sie im Dialogfeld Neues Projekt auf Installierte Vorlagen, und wählen Sie Visual C++. (Je nachdem, wie Sie Visual Studio einrichten, kann sich Visual C++ im Knoten Weitere Sprachen befinden.)

    3. Klicken Sie in der Liste der Vorlagen auf Win32-Konsolenanwendung.

    4. Geben Sie als Projektnamen Folgendes ein: ParallelPI.

    5. Klicken Sie auf OK. Damit wird der Assistent für die Win32-Konsolenanwendung gestartet.

    6. Klicken Sie auf Weiter.

    7. Deaktivieren Sie unter Anwendungseinstellungen unter Zusätzliche Optionen das Kontrollkästchen Vorkompilierte Headerdatei.

    8. Klicken Sie auf Fertig stellen, um den Assistenten zu schließen und das Projekt zu erstellen.

  3. Geben Sie zusätzliche Eigenschaften für das Projekt an.

    1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Parallel PI, und klicken Sie dann auf Eigenschaften. Das Dialogfeld Eigenschaftenseiten wird geöffnet.

    2. Erweitern Sie Konfigurationseigenschaften, und wählen Sie anschließend VC++-Verzeichnisse aus.

      Platzieren Sie den Cursor unter Includeverzeichnisse an den Anfang der Liste, die im Textfeld angezeigt wird. Geben Sie dann den Speicherort der MS MPI-C-Headerdateien an, gefolgt von einem Semikolon (;). Beispiel:

      C:\Program Files\Microsoft HPC Pack 2008 SDK\Include;
      
    3. Platzieren Sie den Cursor unter Bibliotheksverzeichnisse an den Anfang der Liste, die im Textfeld angezeigt wird. Geben Sie dann den Speicherort der Microsoft HPC Pack 2008 SDK-Bibliotheksdatei an, gefolgt von einem Semikolon (;).

      Wenn Sie z. B. eine 32-Bit-Anwendung erstellen und debuggen möchten:

      C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\i386;
      

      Wenn Sie eine 64-Bit-Anwendung erstellen und debuggen möchten:

      C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\amd64;
      
    4. Klicken Sie unter Linker auf Eingabe.

      Platzieren Sie den Cursor in Zusätzliche Abhängigkeiten an den Anfang der Liste, die im Textfeld angezeigt wird. Geben Sie dann Folgendes ein:

      msmpi.lib;

    5. Wenn Sie das Codebeispiel mit OpenMP verwenden:

      Erweitern Sie in Konfigurationseigenschaften den Knoten C/C++, und wählen Sie dann Sprache aus.

      Wählen Sie in der Eigenschaft OpenMP-Unterstützung die Option Ja (/openmp) aus, um die Compilerunterstützung für OpenMP zu aktivieren.

    6. Klicken Sie auf OK, um die Eigenschaftenseiten zu schließen.

  4. Wählen Sie in der Hauptquelldatei den gesamten Code aus, und löschen Sie ihn.

  5. Fügen Sie eins der folgenden Codebeispiele in die leere Quelldatei ein. Das erste Beispiel verwendet MPI und OpenMP, das zweite verwendet MPI und PPL (Parallel Patterns Library).

    Das folgende Codebeispiel verwendet MPI und OpenMP. Die Funktion ThrowDarts verwendet eine parallele OpenMP-for-Schleife, um ggf. vorhandene Multicorehardware zu nutzen.

    // ParallelPI.cpp : Defines the entry point for the MPI application.
    //
    #include "mpi.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "limits.h"
    #include "omp.h"
    #include <random>
    
    int ThrowDarts(int iterations)
    {
    std::tr1::uniform_real<double> MyRandom;
    std::tr1::minstd_rand0 MyEngine;
    
    
    double RandMax = MyRandom.max();
    int count = 0;
    omp_lock_t MyOmpLock;
    
    omp_init_lock(&MyOmpLock);
    //Compute approximation of pi on each node
    #pragma omp parallel for
    for(int i = 0; i < iterations; ++i)
    {
    double x, y;
    x = MyRandom(MyEngine)/RandMax;
    y = MyRandom(MyEngine)/RandMax;
    
    if(x*x + y*y < 1.0)
    {
    omp_set_lock(&MyOmpLock);
    count++;
    omp_unset_lock(&MyOmpLock);
    }
    }
    
    omp_destroy_lock(&MyOmpLock);
    
    return count;
    }
    
    int main(int argc, char* argv[])
    {
    int rank;
    int size;
    int iterations;
    int count;
    int result;
    double time;
    MPI_Status s;
    
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    
    if(rank == 0)
    {
    //Rank 0 asks the number of iterations from the user.
    iterations = 50000000;
    if(argc > 1)
    {
    iterations = atoi(argv[1]);
    }
    printf("Executing %d iterations.\n", iterations);
    fflush(stdout);
    }
    //Broadcast the number of iterations to execute.
    if(rank == 0)
    {
    for(int i = 1; i < size; ++i)
    {
    MPI_Ssend(&iterations, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
    }
    }
    else
    {
    MPI_Recv(&iterations, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &s);
    }
    
    //MPI_Bcast(&iterations, 1, MPI_INT, 0, MPI_COMM_WORLD);
    
    count = ThrowDarts(iterations);
    
    //Gather and sum results
    if(rank != 0)
    {
    MPI_Ssend(&count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
    }
    else
    {
    for(int i = 1; i < size; ++i)
    {
    int TempCount = 0;
    MPI_Recv(&TempCount, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &s);
    count += TempCount;
    }
    }
    result = count;
    
    //MPI_Reduce(&count, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
    
    if(rank == 0)
    {
    printf("The value of PI is approximated to be: %16f", 4*((float)result/(float)(iterations*size)));
    }
    
    MPI_Barrier(MPI_COMM_WORLD);
    
    MPI_Finalize();
    return 0;
    }
    

     

    Das folgende Codebeispiel verwendet PPL (Parallel Patterns Library) anstelle von OpenMP und die kollektiven Operationen von MPI anstelle von Punkt-zu-Punkt-Operationen:

     

    // ParallelPI.cpp : Defines the entry point for the MPI application.
    //
    #include "mpi.h"
    #include "stdio.h"
    #include "stdlib.h"
    #include "limits.h"
    #include <ppl.h>
    #include <random>
    #include <time.h>
    
    using namespace Concurrency;
    
    int ThrowDarts(int iterations)
    {
    
    combinable<int> count;
    
    int result = 0;
    
    
    parallel_for(0, iterations, [&](int i){
    
    std::tr1::uniform_real<double> MyRandom;
    double RandMax = MyRandom.max();
    std::tr1::minstd_rand0 MyEngine;
    double x, y;
    
    MyEngine.seed((unsigned int)time(NULL));
    
    x = MyRandom(MyEngine)/RandMax;
    y = MyRandom(MyEngine)/RandMax;
    
    if(x*x + y*y < 1.0)
    {
    count.local() += 1;
    }
    });
    
    result = count.combine([](int left, int right) { return left + right; });
    
    return result;
    }
    
    void main(int argc, char* argv[])
    {
    int rank;
    int size;
    int iterations;
    int count;
    int result;
    
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    
    if(rank == 0)
    {
    //Rank 0 reads the number of iterations from the command line.
    //50M iterations is the default.
    iterations = 50000000;
    if(argc > 1)
    {
    iterations = atoi(argv[argc-1]);
    }
    printf("Executing %d iterations on %d nodes.\n", iterations, size);
    fflush(stdout);
    }
    //Broadcast the number of iterations to execute.
    MPI_Bcast(&iterations, 1, MPI_INT, 0, MPI_COMM_WORLD);
    
    count = ThrowDarts(iterations);
    
    //Gather and sum results
    MPI_Reduce(&count, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
    
    if(rank == 0)
    {
    printf("The value of PI is approximated to be: %16f", 4*((double)result/(double)(iterations*size)));
    }
    
    MPI_Barrier(MPI_COMM_WORLD);
    
    MPI_Finalize();
    
    }
    
  6. Klicken Sie im Menü Datei auf Alle speichern.

  7. Klicken Sie im Menü Build auf Projektmappe neu erstellen.

Konfigurieren und Starten des MPI-Clusterdebuggers

Nachdem Sie die Anwendung erstellt haben, können Sie den Debugger konfigurieren und starten. In diesem Abschnitt werden drei Optionen für das Debugging beschrieben:

  • Debuggen eines MPI-Prozesses auf dem lokalen Computer

  • Debuggen mehrerer MPI-Prozesse auf dem lokalen Computer

  • Debuggen eines oder mehrerer MPI-Prozesse auf einem Cluster

Tipp

Im MPI-Clusterdebugger können Sie nicht ohne Debugging starten. Auch bei Verwendung der Tastenkombination STRG+F5 (oder der Option Starten ohne Debuggen aus dem Menü Debuggen) wird das Debuggen gestartet.

Debuggen eines MPI-Prozesses auf dem lokalen Computer

Zum Debuggen auf einem lokalen Computer mit nur einem MPI-Prozess gehen Sie genauso vor wie beim Debuggen anderer Anwendungen. Setzen Sie einen Haltepunkt an der gewünschten Stelle im Programm, und drücken Sie F5, um den Debugger zu starten.

MPI-Programme kommunizieren per IP über Ports. Beim ersten Starten eines MPI-Programms wird möglicherweise eine Sicherheitswarnung der Firewall angezeigt, die angibt, dass ein Port geöffnet wird. Lesen Sie die Warnmeldung, und stellen Sie sicher, dass Sie die Änderungen verstehen, die Sie an Ihrem System vornehmen. Sie müssen die Blockierung der Firewall aufheben, um das Debuggen auf dem lokalen Computer fortzusetzen.

Debuggen mehrerer MPI-Prozesse auf dem lokalen Computer

Das folgende Verfahren beschreibt, wie Sie eine lokale Debugsitzung für ParallelPI starten.

So starten Sie den MPI-Clusterdebugger mit vier MPI-Prozessen, die auf dem lokalen Computer ausgeführt werden

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Parallel PI, und klicken Sie dann auf Eigenschaften. Das Dialogfeld Eigenschaftenseiten wird geöffnet.

  2. Erweitern Sie Konfigurationseigenschaften, und klicken Sie anschließend auf Debuggen.

  3. Unter Zu startender Debugger: wählen Sie MPI-Clusterdebugger.

  4. Wählen Sie in Umgebung ausführen aus der Dropdown-Liste HPC-Knoten bearbeiten. Das Dialogfeld Knotenauswahl wird geöffnet.

  5. Wählen Sie in der Dropdown-Liste Hauptknoten die Option localhost aus.

  6. Geben Sie unter Anzahl der Prozesse 4 an.

  7. Klicken Sie auf OK, um die Änderungen zu speichern und das Dialogfeld Knotenauswahl zu schließen.

  8. ParallelPI akzeptiert ein Argument, das die Anzahl der auszuführenden Iterationen angibt. Der Standardwert ist auf 50.000.000 festgelegt. Für die lokale Debugsitzung verringern Sie die Anzahl der Iterationen wie folgt auf 5.000:

    Geben Sie unter Anwendungsargumente 5000 ein.

  9. Klicken Sie auf OK, um die Änderungen zu speichern, und schließen Sie die Eigenschaftenseiten.

  10. Setzen Sie einen Haltepunkt innerhalb der parallelen for-Schleife.

  11. Drücken Sie F5, um den Debugger zu starten.

  12. Es sollten fünf Konsolenfenster angezeigt werden: ein cmd.exe-Fenster und vier ParallelPI.exe-Fenster (eins für jeden gestarteten Prozess). Das Konsolenfenster für den Prozess mit dem Rang 0 zeigt die Anzahl der Iterationen und die berechnete Annäherung an Pi an.

  13. Klicken Sie im Menü Debuggen auf Fenster und dann auf Prozesse.

  14. Legen Sie den aktiven Prozess fest, den Sie debuggen möchten, indem Sie im Fenster Prozesse auf einen Prozess doppelklicken.

Tipp

Beim Debuggen mehrerer Prozesse betrifft ein Haltepunkt standardmäßig alle Prozesse, für die das Debuggen durchgeführt wird. Deaktivieren Sie die Option Alle Prozesse anhalten, wenn ein Prozess anhält, um das Anhalten von Prozessen an unbeabsichtigten Stellen zu vermeiden. (Klicken Sie im Menü Extras auf Optionen, und dann auf Debuggen). Weitere Informationen zum Ändern des Anhalteverhaltens finden Sie unter Gewusst wie: Ausführung unterbrechen.

Debuggen eines oder mehrerer MPI-Prozesse auf einem Cluster

Wenn Sie den MPI-Debugger auf einem Cluster starten, sendet der Debugger die Anwendung als Auftrag an den Cluster. Die Visual C-Laufzeiten, die Ihrem Projekt entsprechen (x86 oder x64, Debug oder Version) müssen im Arbeitsverzeichnis auf den Berechnungsknoten vorhanden sein. Wenn die richtigen Laufzeiten nicht bereits auf den Berechnungsknoten vorhanden sind, müssen Sie diese in die Debuggerbereitstellung einschließen, indem Sie die Eigenschaft Zusätzlich bereitzustellende Dateien festlegen. Das folgende Verfahren umfasst einen Schritt für die Bereitstellung der OpenMP-Debug-Laufzeit-DLL. Standardmäßig wird die C-Laufzeitbibliothek (C Runtime, CRT) bereitgestellt, wenn Sie den MPI-Clusterdebugger starten. Wenn die richtigen Laufzeiten nicht vorhanden sind, werden beim Ausführen der Anwendung gleichzeitige Fehler angezeigt. Wenn die OpenMP-Laufzeit nicht eingeschlossen ist, werden die Haltepunkte nicht getroffen.

So starten Sie den MPI-Debugger auf einem Cluster

  1. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Parallel PI, und klicken Sie dann auf Eigenschaften. Das Dialogfeld Eigenschaftenseiten wird geöffnet.

  2. Erweitern Sie Konfigurationseigenschaften, und klicken Sie anschließend auf Debuggen.

  3. Unter Zu startender Debugger: wählen Sie MPI-Clusterdebugger.

  4. Wählen Sie in Umgebung ausführen aus der Dropdown-Liste HPC-Knoten bearbeiten. Das Dialogfeld Knotenauswahl wird geöffnet.

  5. Wählen Sie in der Dropdown-Liste Hauptknoten den Namen des Hauptknotens für den Cluster aus, den Sie verwenden möchten.

    Die Liste der Hauptknoten wird aus dem Active Directory-Domänencontroller gefüllt. Nur Clusters in Ihrer Domäne werden in der Liste angezeigt. Wenn Ihr Hauptknoten nicht angezeigt wird, geben Sie den Namen oder die IPv4-Adresse des Hauptknotens im Eigenschaftenfeld ein.

  6. Geben Sie unter Anzahl der Prozesse 4 an.

  7. Wählen Sie unter Prozess planen: einen je aus, wie die Prozesse zugeordnet werden sollen. Sie können einen Prozess je Core, Socket oder Knoten zuordnen.

  8. Klicken Sie auf OK, um die Änderungen zu speichern und das Dialogfeld Knotenauswahl zu schließen.

  9. Geben Sie in Bereitstellungsverzeichnis ein freigegebenes Verzeichnis auf dem Hauptknoten an. Wenn kein Bereitstellungsverzeichnis vorhanden ist und Sie im angegebenen Stammverzeichnis über eine Schreibberechtigung verfügen, wird das Bereitstellungsverzeichnis automatisch erstellt.

    Die freigegebene Verzeichnisressource CcpSpoolDir wird erstellt, wenn HPC Pack 2008 auf dem Hauptknoten installiert ist. Geben Sie beispielsweise Folgendes ein, wobei <myHeadNode> der Name des verwendeten Clusters ist:

    \\<myHeadNode>\CcpSpoolDir\

  10. Geben Sie in Arbeitsverzeichnis ein lokales Arbeitsverzeichnis auf jedem Berechnungsknoten an. Geben Sie beispielsweise Folgendes ein, wobei <myUserName> Ihr Benutzername ist:

    C:\Users\<myUserName>\ParallelPI

  11. Wenn Sie den Beispielcode mit OpenMP verwenden, fügen Sie die OpenMP-Debug-Laufzeit-DLL (Microsoft.VC100.DebugOpenMP\vcomp100d.dll) hinzu:

    1. Wählen Sie in Zusätzlich bereitzustellende Dateien die Option <Datei bearbeiten…>. Das Dialogfeld Datei- und Ordnerauswahl wird geöffnet.

    2. Klicken Sie auf Datei hinzufügen, navigieren Sie zu Microsoft.VC100.DebugOpenMP\vcomp100d.dll, markieren Sie die Datei, und klicken Sie dann auf Öffnen.

      Bei einem x86-basierten Computer lautet der Standardspeicherort auf einer 64-Bit-Edition des Windows Server 2008-Betriebssystems beispielsweise:

      C:\Programme (x86)\Microsoft Visual Studio 10.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC100.DebugOpenMP\ vcomp100d.dll

    3. Klicken Sie auf OK, um die Datei hinzuzufügen, und schließen Sie das Dialogfeld Datei- und Ordnerauswahl.

  12. Klicken Sie auf OK, um Änderungen zu speichern und Eigenschaftenseiten zu schließen.

  13. Setzen Sie einen Haltepunkt innerhalb der parallelen for-Schleife.

  14. Drücken Sie F5, um den Debugger zu starten.

  15. Da Sie einen Auftrag an den Cluster senden, werden Sie zur Eingabe Ihres Kennworts aufgefordert, um eine Verbindung zum Cluster herzustellen. Geben Sie das Kennwort ein, und drücken Sie die EINGABETASTE.

  16. Nachdem Sie den Debugger gestartet haben, überprüfen Sie im Prozessfenster die Platzierung der Prozesse. Überprüfen Sie bei jedem Prozess die Spalte Transportqualifizierer, um den Berechnungsknoten zu sehen, auf dem der Prozess ausgeführt wird.

Anhang: Von Visual Studio zusätzlich zu den Anwendungsbinärdateien (und CRT, falls erforderlich) bereitgestellte Dateien

  • DebuggerProxy.dll

  • DebuggerProxy.dll.manifest

  • Delete_from_workdir.bat: Skript zum Löschen der bereitgestellten Dateien

  • Delete_from_workdir.bat: Skript zum Kopieren der Dateien aus dem Bereitstellungs- ins Arbeitsverzeichnis

  • dbghelp.dll

  • mcee.dll

  • Mpishim.bat: Skript zum Starten des Remotedebuggers

  • Mpishim.exe: Programm, das die Kommunikation zwischen IDE und "Msvsmon.exe" koordiniert

  • Msvsmon.exe: Remotedebugger

  • Msvsmon.exe.config

  • PfxTaskProvider.dll

  • symsrv.dll

  • symsrv.yes

  • vbdebug.dll

  • 1031\msdbgui.dll

  • 1031\vbdebugui.dll

Siehe auch

Konzepte

Konfigurationseigenschaften für den MPI-Clusterdebugger
Debuggen von MPI-Anwendungen auf einem HPC-Cluster

Weitere Ressourcen

Debugger-Wegweiser
mpiexec Command Reference