Scenario: Avvio di Debugger cluster MPI in Visual Studio 2010
In questo scenario è spiegato come impostare e avviare una sessione di Debugger cluster MPI sul computer locale e su un cluster Microsoft Windows HPC Server 2008. Questo scenario contiene i passaggi e il codice di esempio necessari per creare un'applicazione che utilizza le interfacce di programmazione applicazioni (API) MPI (Message Passing Interface) e OpenMP (Open Multi-Processing).
In questa guida vengono trattati gli argomenti seguenti:
Requisiti per l'uso di Debugger cluster MPI
Creare un progetto MPI C++ di esempio in Visual Studio 2010
Configurare e avviare Debugger cluster MPI
Appendice: File distribuiti da Visual Studio oltre ai file binari dell'applicazione (e ai file CRT, se richiesti)
Requisiti per l'uso di Debugger cluster MPI
È necessario che sul computer utilizzato per lo sviluppo sia installata l'edizione Visual Studio 2010 Professional Edition o successiva (comprensiva del debugger remoto).
Sono necessarie le autorizzazioni di amministrazione sul cluster.
Visual Studio deve essere in grado di accedere ai compute node su cui eseguire la sessione di debug. Gli scenari riportati di seguito garantiscono il tipo di accesso necessario:
Si sta sviluppando l'applicazione sull'head node del cluster o su un nodo di accesso dedicato.
Si utilizza un cluster in cui i compute node sono connessi alla rete aziendale (topologia°2, 4 o 5) e il computer utilizzato per lo sviluppo è parte dello stesso dominio o di un dominio che ha una relazione di trust con il dominio del cluster.
Per inviare l'applicazione a un cluster HPC utilizzando un computer client, è necessario aver installato Microsoft HPC Pack°2008.
Per creare programmi MPI utilizzando Microsoft Message Passing Interface, è necessario installare Windows HPC Server 2008 SDK sul computer utilizzato per lo sviluppo.
Creare un progetto MPI C++ di esempio in Visual Studio 2010
Il codice di esempio in questa sezione riguarda un'applicazione in parallelo che approssima il valore di pi greco utilizzando una simulazione Monte Carlo.
Il codice di esempio esegue 50.000.000 iterazioni su ogni processo MPI. In ciascuna iterazione il codice di esempio genera numeri casuali nell'intervallo [0,1] per determinare un insieme di coordinate x e y. L'insieme di coordinate viene quindi valutato per determinare se il punto ricade sulla linea x2 + y2 = 1. Se il punto ricade sulla linea, la variabile count viene incrementata di uno. Il valore di count derivante da ogni processo MPI viene sommato nella variabile result. Il numero totale di punti che ricadevano sulla linea (result) viene moltiplicato per quattro e poi diviso per il numero totale di iterazioni per approssimare il valore di pi greco.
Nella seguente procedura sono incluse due implementazioni della simulazione Monte Carlo.
Il primo esempio utilizza MPI e OpenMP. Per ulteriori informazioni su OpenMP, vedere OpenMP in Visual C++.
Il secondo utilizza MPI e PPL (Parallel Patterns Library). Per ulteriori informazioni su PPL (Parallel Patterns Library), vedere Parallel Patterns Library (PLL).
Per creare il progetto di esempio
Eseguire Visual Studio 2010.
Creare una nuova applicazione console Win32 C++ chiamata ParallelPI. Utilizzare un progetto senza intestazioni precompilate.
Scegliere Nuovo dal menu File, quindi fare clic su Progetto.
Nella finestra di dialogo Nuovo progetto, fare clic su Modelli installati e selezionare Visual C++. In alcune installazioni di Visual Studio Visual C++ può trovarsi all'interno del nodo Altri linguaggi.
Nell'elenco di modelli, fare clic su Applicazione console Win32.
Per il nome del progetto, immettere ParallelPI.
Fare clic su OK. Viene aperta la procedura guidata Applicazione console Win32.
Fare clic su Avanti.
In Impostazioni applicazione, deselezionare la casella di controllo Intestazione precompilata sotto Opzioni aggiuntive.
Fare clic su Fine per chiudere la procedura guidata e creare il progetto.
Specificare ulteriori proprietà per il progetto.
In Esplora soluzioni, fare clic con il pulsante destro del mouse su ParallelPI e selezionare Proprietà. Viene visualizzata la finestra di dialogo Pagine delle proprietà.
Espandere Proprietà di configurazione, quindi selezionare Directory di VC++.
In Directory file di inclusione, posizionare il cursore all'inizio dell'elenco visualizzato nella casella di testo, quindi specificare il percorso dei file di intestazione C di MS MP seguito da un punto e virgola (;). Ad esempio:
C:\Program Files\Microsoft HPC Pack 2008 SDK\Include;
In Directory librerie, posizionare il cursore all'inizio dell'elenco visualizzato nella casella di testo, quindi specificare il percorso dei file della libreria Microsoft HPC Pack 2008 SDK seguito da un punto e virgola (;).
Ad esempio, se si desidera creare ed eseguire il debug di un'applicazione a 32 bit:
C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\i386;
Se si desidera creare ed eseguire il debug di un'applicazione a 64 bit:
C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\amd64;
Selezionare Input sotto il nodo Linker.
In Dipendenze aggiuntive posizionare il cursore all'inizio dell'elenco nella casella di testo, quindi digitare:
msmpi.lib;
Se si utilizza un codice di esempio con OpenMP:
In Proprietà di configurazione, espandere C/C++, quindi selezionare Linguaggio.
In Supporto OpenMP, selezionare Sì (/openmp) per abilitare il supporto del compilatore per OpenMP.
Fare clic su OK per chiudere la pagina delle proprietà.
Nel file sorgente principale, selezionare tutto il codice ed eliminarlo.
Incollare uno dei seguenti esempi di codice nel file sorgente vuoto. Il primo esempio utilizza MPI e OpenMP, il secondo utilizza MPI e PPL (Parallel Patterns Library).
Il seguente codice di esempio esempio utilizza MPI e OpenMP. La funzione
ThrowDarts
utilizza un OpenMP parallelofor
la ripetizione ciclica, in modo da utilizzare l'hardware multi-core, se disponibile.// 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; }
L'esempio di codice seguente utilizza PPL (Parallel Patterns Library) al posto di OpenMP e le operazioni MPI collettive al posto delle operazioni punto a punto.
// 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(); }
Scegliere Salva tutto dal menu File.
Scegliere Rigenera soluzione dal menu Genera.
Configurare e avviare Debugger cluster MPI
Una volta creata l'applicazione, è possibile configurare e avviare il debugger. In questa sezione sono descritte tre possibilità per eseguire i debug:
Eseguire il debug di un processo MPI sul computer locale
Eseguire il debug di più processi MPI sul computer locale
Eseguire il debug di uno o più processi MPI su un cluster
Nota
In Debugger cluster MPI non è possibile iniziare senza eseguire il debug. Per avviare il debug, è possibile anche premere Ctrl+F5 (o scegliere Avvia senza eseguire debug dal menu Debug).
Eseguire il debug di un processo MPI sul computer locale
Per eseguire il debug sul computer locale utilizzando un solo processo MPI, utilizzare la stessa procedura vista per il debug di qualsiasi altra applicazione. Impostare un punto di interruzione nella posizione desiderata del programma e premere F5 per avviare il debugger.
I programmi MPI comunicano tramite IP sulle porte. Al primo avvio di un programma MPI potrebbe essere visualizzato un avviso di protezione del firewall, che indica che sta per essere aperta una porta. Leggere il messaggio di avviso e valutare se sono state comprese le modifiche che si stanno apportando al sistema. È necessario sbloccare il firewall per continuare il debug sul computer locale.
Eseguire il debug di più processi MPI sul computer locale
Nella seguente procedura viene descritto come avviare una sessione di debug locale per ParallelPI.
Per avviare Debugger cluster MPI con quattro processi MPI in esecuzione sul computer locale
In Esplora soluzioni, fare clic con il pulsante destro del mouse su ParallelPI e selezionare Proprietà. Viene visualizzata la finestra di dialogo Pagine delle proprietà.
Espandere Proprietà di configurazione, quindi selezionare Debug.
Selezionare Debugger cluster MPI in Debugger da avviare.
Selezionare Modifica nodo HPC dall'elenco a discesa Ambiente di esecuzione. Viene visualizzata la finestra di dialogo Selettore nodo.
Selezionare localhost dall'elenco a discesa Head node.
Selezionare 4 in Numero di processi.
Fare clic su OK per salvare le modifiche e chiudere la finestra di dialogo Selettore nodo.
ParallelPI accetta un argomento che determina il numero di iterazioni da eseguire. L'impostazione predefinita è 50.000.000. Per la sessione di debug locale, ridurre le iterazioni a 5.000 nel modo seguente:
In Argomenti applicazione digitare 5000.
Fare clic su OK per salvare le modifiche e chiudere la finestra Pagine delle proprietà.
Impostare un punto di interruzione nel corpo del parallelo
for
la ripetizione ciclica.Premere F5 per avviare il debugger.
Vengono visualizzate cinque finestre della console: una finestra cmd.exe e quattro finestre ParallelPI.exe (una per ogni processo avviato). La finestra della console che corrisponde al processo con classificazione 0 indica il numero di iterazioni e l'approssimazione di pi greco calcolata.
Nel menu Debug, fare clic su Finestre,quindi selezionare Processi.
Impostare il processo attivo per il debug facendo doppio clic su un processo nella finestra Processi.
Nota
Durante il debug di più processi, per impostazione predefinita un punto di interruzione influisce su tutti i processi in fase di debug. Per evitare l'interruzione dei processi in punti non previsti, deselezionare l'opzione Quando si interrompe un processo, interrompi tutti i processi. (Nel menu Strumenti, fare clic suOpzioni, quindi selezionare Debug). Per ulteriori informazioni sulla modifica del comportamento di interruzione, vedere Procedure: Interrompere l'esecuzione.
Eseguire il debug di uno o più processi MPI su un cluster
Quando si avvia Debugger MPI su un cluster, il debugger invia l'applicazione al cluster come processo. I runtime di Visual C corrispondenti al progetto (x86 o x64, debug o release) devono essere presenti nella directory di lavoro sui compute node. Se i runtime corretti non sono già nei compute node, è necessario includerli nella distribuzione del debugger specificando la proprietà Ulteriori file da distribuire. Nella seguente procedura è incluso un passaggio per distribuire la DLL di runtime per il debug OpenMP. Per impostazione predefinita, la libreria C Runtime (CRT) viene distribuita all'avvio di Debugger cluster MPI. Se i runtime corretti non sono presenti, verranno visualizzati errori affiancati quando si tenta di eseguire l'applicazione. Se il runtime OpenMP non è incluso, i punti di interruzione non saranno attivati.
Per avviare Debugger MPI su un cluster
In Esplora soluzioni, fare clic con il pulsante destro del mouse su ParallelPI e selezionare Proprietà. Viene visualizzata la finestra di dialogo Pagine delle proprietà.
Espandere Proprietà di configurazione, quindi selezionare Debug.
Selezionare Debugger cluster MPI in Debugger da avviare.
Selezionare Modifica nodo HPC dall'elenco a discesa Ambiente di esecuzione. Viene visualizzata la finestra di dialogo Selettore nodo.
Selezionare il nome dell'head node per il cluster da utilizzare nell'elenco a discesa Head node.
L'elenco di head node viene compilato dal controller di dominio Active Directory. Nell'elenco saranno visualizzati solo i cluster nel proprio dominio. Se l'head node desiderato non è visualizzato, immettere il nome o l'indirizzo IPv4 dell'head node nel campo delle proprietà.
Selezionare 4 in Numero di processi.
In Pianifica un processo per, selezionare la modalità per allocare i processi. È possibile allocare un processo per Core, Socket o Nodo.
Fare clic su OK per salvare le modifiche e chiudere la finestra di dialogo Selettore nodo.
Specificare una directory condivisa sull'head node nel campo Directory di distribuzione. Se la directory di distribuzione non esiste ma si dispone di autorizzazioni in scrittura sulla directory principale specificata, la directory di distribuzione sarà creata automaticamente.
La directory di risorse condivise CcpSpoolDir viene creata all'installazione del pacchetto HPC Pack 2008 sull'head node. Ad esempio, digitare le informazioni seguenti, in cui <myHeadNode> corrisponde al nome del cluster in uso:
\\<myHeadNode>\CcpSpoolDir\
Specificare una directory di lavoro locale su ogni compute node nel campo Directory di lavoro. Ad esempio, digitare le informazioni seguenti, in cui <myUserName> corrisponde al proprio nome utente:
C:\Users\<myUserName>\ParallelPI
Se si utilizza il codice di esempio con OpenMP, aggiungere il file DLL di runtime per il debug OpenMP (Microsoft.VC100.DebugOpenMP\vcomp100d.dll):
Selezionare <Modifica file...> in Ulteriori file da distribuire. Viene visualizzata la finestra di dialogo Selettore file e cartelle.
Fare clic su Aggiungi file, andare a Microsoft.VC100.DebugOpenMP\vcomp100d.dll, selezionare il file, quindi fare clic suApri.
Ad esempio, in un computer con processore x86, il percorso predefinito nell'edizione a 64 bit del sistema operativo Windows Server 2008 è:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC100.DebugOpenMP\ vcomp100d.dll
Fare clic su OK per aggiungere il file e chiudere la finestra di dialogo Selettore file e cartelle.
Fare clic su OK per salvare le modifiche e chiudere la finestra Pagine delle proprietà.
Impostare un punto di interruzione nel corpo del parallelo
for
la ripetizione ciclica.Premere F5 per avviare il debugger.
Dal momento che si sta inviando un processo al cluster, viene richiesto di immettere la password per connettersi al cluster. Digitare la password e premere INVIO.
Dopo l'avvio del debugger, osservare la finestra del processo per verificare il posizionamento dei processi. Per ogni processo è possibile osservare la colonna Qualificatore di trasporto per visualizzare il compute node su cui è in esecuzione il processo.
Appendice: File distribuiti da Visual Studio oltre ai file binari dell'applicazione (e ai file CRT, se richiesti)
DebuggerProxy.dll
DebuggerProxy.dll.manifest
Delete_from_workdir.bat: Uno script per eliminare i file distribuiti
Deploy_to_workdir.bat: Uno script per copiare i file dalla directory di distribuzione a quella di lavoro
dbghelp.dll
mcee.dll
Mpishim.bat: Uno script per avviare il debugger remoto
Mpishim.exe: Un programma che gestisce la comunicazione tra IDE e Msvsmon.exe
Msvsmon.exe: Il debugger remoto
Msvsmon.exe.config
PfxTaskProvider.dll
symsrv.dll
symsrv.yes
vbdebug.dll
1040\msdbgui.dll
1040\vbdebugui.dll
Vedere anche
Concetti
Proprietà di configurazione per Debugger cluster MPI
Debug delle applicazioni MPI su un cluster HPC