逐步解說:在 Visual Studio 2010 啟動 MPI 叢集偵錯工具
在此逐步解說中,您將了解如何在本機電腦和 Microsoft Windows HPC Server 2008 叢集上設定並啟動 MPI 叢集偵錯工具工作階段。此逐步解說包含使用「訊息傳遞介面」(MPI) 與「開放式多重處理」(OpenMP) 應用程式開發介面 (API) 建立應用程式所需的步驟與程式碼範例。
本指南內容:
使用 MPI 叢集偵錯工具的需求
在 Visual Studio 2010 中建立 C++ MPI 專案範例
設定和啟動 MPI 叢集偵錯工具
附錄:除了應用程式二進位檔之外,Visual Studio 所部署的檔案 (與 CRT,若有要求)
使用 MPI 叢集偵錯工具的需求
您必須在開發電腦上安裝 Visual Studio 2010 Professional Edition 或更新版本 (包括遠端偵錯工具)。
您必須有叢集的系統管理權限。
Visual Studio 必須能夠存取您要執行偵錯工作階段的運算節點。下列案例提供所需的存取權:
您正在叢集前端節點或專用登入節點上開發應用程式。
您正使用其中的運算節點已連接至企業網路 (拓撲 2、4 或 5) 的叢集,且您的開發電腦已加入相同網域或與該叢集網域具有信任關係的網域。
若要將您的應用程式從用戶端電腦送出至 HPC 叢集,您必須安裝 Microsoft HPC Pack 2008。
若要使用 Microsoft 訊息傳遞介面建置 MPI 程式,您的開發電腦上必須安裝 Windows HPC Server 2008 SDK。
在 Visual Studio 2010 中建立 C++ MPI 專案範例
本節中的範例程式碼適用於使用蒙地卡羅模擬法 (Monte Carlo Simulation) 計算 pi 近似值的平行應用程式。
範例程式碼會在每個 MPI 處理序執行 50,000,000 次反覆運算。在每次反覆運算中,範例程式碼都會產生間隔 [0,1] 中的隨機數字,以決定 x 與 y 座標的組合。範例程式碼會評估座標組以判斷點是否落在 x2 + y2 = 1 線下方。若點落在該線下方,則變數 count 會加一。來自每個 MPI 處理序的 count 值會加總至變數 result。落在線 (result) 下方的總點數會乘以四然後除以反覆運算總數,以求得 pi 的近似值。
下列程序包括蒙地卡羅模擬法的兩個實作。
第一個範例使用 MPI 和 OpenMP。如需 OpenMP 的相關資訊,請參閱 OpenMP in Visual C++。
第二個範例使用 MPI 和平行樣式程式庫 (PPL)。如需 PPL 的相關資訊,請參閱 Parallel Patterns Library (PLL)。
建立範例專案
執行 Visual Studio 2010。
建立新的 C++ Win32 主控台應用程式,並將它命名為 ParallelPI。使用不含先行編譯標頭檔的專案。
在 [檔案] 功能表上,指向 [新增],然後按一下 [專案]。
在 [新增專案] 對話方塊中,按一下 [安裝的樣板],然後選取 [Visual C++] (視安裝 Visual Studio 的方式而定,[Visual C++] 可能位於 [其他語言] 節點下)。
在樣板清單中,按一下 [Win32 主控台應用程式]。
對於專案名稱,請輸入:ParallelPI。
按一下 [確定]。這樣會開啟 [Win32 主控台應用程式精靈]。
按一下 [下一步]。
在 [應用程式設定] 的 [其他選項] 下,清除 [先行編譯標頭檔] 核取方塊。
按一下 [完成] 關閉精靈並建立專案。
指定專案的其他屬性。
在 [方案總管] 中,於 [Parallel PI] 上按一下滑鼠右鍵,然後按一下 [屬性]。這樣會開啟 [屬性頁] 對話方塊。
展開 [組態屬性],然後選取 [VC++ 目錄]。
在 [Include 目錄] 中,將游標放在文字方塊中出現之清單的開頭,然後指定 MS MPI C 標頭檔的位置,後面接一個分號 (;)。例如:
C:\Program Files\Microsoft HPC Pack 2008 SDK\Include;
在 [程式庫目錄] 中,將游標放在文字方塊中出現之清單的開頭,然後指定Microsoft HPC Pack 2008 SDK 程式庫檔的位置,後面接一個分號 (;)。
例如,如果您想要建置並偵錯 32 位元應用程式:
C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\i386;
如果您想要建置並偵錯 64 位元應用程式:
C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\amd64;
在 [連結器] 下,選取 [輸入]。
在 [其他相依性] 下,將游標放在文字方塊中出現之清單的開頭,然後輸入下列:
msmpi.lib;
如果您使用的是 OpenMP 的程式碼範例:
在 [組態屬性] 中,展開 [C/C++] 節點,然後選取 [語言]。
在 [Open MP 支援] 中,選取 [是 (/openmp)] 以啟用 OpenMP 的編譯器支援。
按一下 [確定] 以關閉屬性頁。
在主原始程式檔中,選取所有程式碼然後將它刪除。
將下列其中一個程式碼範例貼到空的原始程式檔中。第一個範例使用 MPI 與 OpenMP,而第二個範例使用 MPI 與「平行樣式程式庫」(Parallel Patterns Library,PPL)。
下列程式碼範例使用 MPI 與 OpenMP。
ThrowDarts
函式使用 OpenMP 平行for
迴圈,以利用可用的多核心硬體):// 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; }
下列程式碼範例使用「平行樣式程式庫」(PPL) 而不使用 OpenMP,並使用 MPI 集體作業而不使用點對點作業:
// 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(); }
在 [檔案] 功能表上,按一下 [全部儲存]。
在 [建置] 功能表上,按一下 [重建方案]。
設定和啟動 MPI 叢集偵錯工具
建置應用程式之後,您便可準備設定和啟動偵錯工具。本節說明可用於偵錯的三個選項:
在本機電腦上針對一個 MPI 處理序進行偵錯
在本機電腦上針對多個 MPI 處理序進行偵錯
針對叢集上的一或多個 MPI 處理序進行偵錯
注意: |
---|
在 MPI 叢集偵錯工具中,您無法啟動但不進行偵錯。按下 Ctrl+F5 (或 [偵錯] 功能表上的 [啟動但不偵錯]),也會開始進行偵錯。 |
在本機電腦上針對一個 MPI 處理序進行偵錯
若要針對只使用一個 MPI 處理序的本機電腦進行偵錯,所使用的程序和您用以偵錯任何應用程式的程序相同。在程式中的適當位置設定中斷點,然後按下 F5 啟動偵錯工具。
MPI 程式在連接埠上透過 IP 進行通訊。首次啟動 MPI 程式時,可能會看到來自防火牆的安全性警告,表示正在開啟連接埠。請閱讀該警告訊息,並確定您了解您正在對系統進行的變更。您必須解除封鎖防火牆,以繼續在本機電腦上進行偵錯。
在本機電腦上針對多個 MPI 處理序進行偵錯
下列程序說明如何啟動 ParallelPI 的本機偵錯工作階段。
針對在本機電腦上執行的四個 MPI 處理序啟動 MPI 叢集偵錯工具
在 [方案總管] 中,於 [Parallel PI] 上按一下滑鼠右鍵,然後按一下 [屬性]。這樣會開啟 [屬性頁] 對話方塊。
展開 [組態屬性],然後選取 [偵錯]。
在 [要啟動的偵錯工具] 下,選取 [MPI 叢集偵錯工具]。
在 [執行環境] 中,從下拉式清單中選取 [編輯 Hpc 節點]。這樣會開啟 [節點選取器] 對話方塊。
在 [前端節點] 下拉式清單中,選取 [localhost]。
在 [處理序數目] 中,選取 [4]。
按一下 [確定] 以儲存變更,然後關閉 [節點選取器] 對話方塊。
ParallelPI 接受一個可決定反覆運算執行次數的引數。預設值是 50,000,000。對於本機偵錯工作階段,請按下列方式將反覆運算降低至 5,000:
在 [應用程式引數] 中,輸入 5000。
按一下 [確定] 儲存變更,然後關閉 [屬性頁]。
在平行
for
迴圈主體中設定中斷點。按下 F5 以啟動偵錯工具。
應該會顯示五個主控台視窗:一個 cmd.exe 視窗以及四個 ParallelPI.exe 視窗 (您啟動的每個處理序各一個視窗)。對應至順序 0 處理序的主控台視窗表示反覆運算次數與計算的 pi 近似值。
在 [偵錯] 功能表上,按一下 [視窗],然後按一下 [處理序]。
按兩下 [處理序] 視窗中的處理序,設定要進行偵錯的作用中處理序。
注意: |
---|
針對多個處理序進行偵錯時,中斷點預設會影響正在偵錯的所有處理序。若要避免意外中斷處理序,請取消選取 [如果其中一個處理序中斷,就中斷所有處理序] 選項。(在 [工具] 功能表中,按一下 [選項],然後選取 [偵錯]。)如需關於變更中斷行為的資訊,請參閱作法:中斷執行。 |
針對叢集上的一或多個 MPI 處理序進行偵錯
當您在叢集上啟動 MPI 偵錯工具時,偵錯工具會將您的應用程式送出給叢集做為工作。符合您專案 (x86 或 x64、偵錯或發行) 的 Visual C 執行階段必須存在於運算節點的工作目錄。若運算節點上沒有正確的執行階段,您需要指定指定「要部署的其他檔案」屬性,將它們包含在偵錯工具開發中。以下程序包含部署 OpenMP 偵錯執行階段 DLL 的步驟。根據預設,當您啟動 MPI 叢集偵錯工具時,會部署 C 執行階段 (CRT) 程式庫。若沒有正確的執行階段存在,嘗試執行應用程式時會看到並存錯誤。若未包含 OpenMP 執行階段,將不會觸發中斷點。
在叢集上啟動 MPI 偵錯工具
在 [方案總管] 中,於 [Parallel PI] 上按一下滑鼠右鍵,然後按一下 [屬性]。這樣會開啟 [屬性頁] 對話方塊。
展開 [組態屬性],然後選取 [偵錯]。
在 [要啟動的偵錯工具] 下,選取 [MPI 叢集偵錯工具]。
在 [執行環境] 中,從下拉式清單中選取 [編輯 Hpc 節點]。這樣會開啟 [節點選取器] 對話方塊。
在 [前端節點] 下拉式清單中,選取要使用之叢集的前端節點名稱。
前端節點清單是從 Active Directory 網域控制站填入。只有在您網域中的叢集會出現在該清單中。若沒有看到您的前端節點,請在屬性欄位中輸入前端節點的名稱或 IPv4 位址。
在 [處理序數目] 中,選取 [4]。
在 [排程一個處理序於每個] 中,選取如何配置您的處理序。您可以每個 [核心]、[通訊端] 或 [節點] 都配置一個處理序。
按一下 [確定] 以儲存變更,然後關閉 [節點選取器] 對話方塊。
在 [部署目錄] 中,指定前端節點上的共用目錄。若部署目錄不存在,而您具有所指定根目錄的寫入權限,便會自動建立部署目錄。
在前端節點上安裝 HPC Pack 2008 時,會建立 CcpSpoolDir 目錄共用資源。例如,輸入下列資訊,其中 <myHeadNode> 是您要使用的叢集名稱:
\\<myHeadNode>\CcpSpoolDir\
在 [工作目錄] 中,指定每個運算節點上的本機工作目錄。例如,輸入下列資訊,其中 <myUserName> 是您的使用者名稱:
C:\Users\<myUserName>\ParallelPI
若要使用範例程式碼來搭配 OpenMP,請加入 OpenMP 偵錯執行階段 DLL 檔案 (Microsoft.VC100.DebugOpenMP\vcomp100d.dll):
在 [要部署的其他檔案] 中,選取 [編輯檔案]。這樣會開啟 [檔案及資料夾選取器] 對話方塊。
按一下 [加入檔案],瀏覽到 Microsoft.VC100.DebugOpenMP\vcomp100d.dll,選取該檔案,然後按一下 [開啟]。
例如,在 x86 型電腦上,64 位元版本 Windows Server 2008 作業系統的預設位置是:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\redist\Debug_NonRedist\x86\Microsoft.VC100.DebugOpenMP\ vcomp100d.dll
按一下 [確定] 以加入檔案,然後關閉 [檔案及資料夾選取器] 對話方塊。
按一下 [確定] 儲存變更,然後關閉 [屬性頁]。
在平行
for
迴圈主體中設定中斷點。按下 F5 以啟動偵錯工具。
因為您要將工作送至叢集,系統會提示您輸入密碼以連接到叢集。輸入您的密碼,然後按下 ENTER 鍵。
偵錯工具啟動之後,請檢視處理序視窗以確認處理序的位置。對於每個處理序,在 [傳輸限定詞] 欄檢視正在執行處理序的運算節點。
附錄:除了應用程式二進位檔之外,Visual Studio 所部署的檔案 (與 CRT,若有要求)
DebuggerProxy.dll
DebuggerProxy.dll.manifest
Delete_from_workdir.bat:用於刪除已部署之檔案的指令碼
Deploy_to_workdir.bat:用於將檔案從部署目錄複製到工作目錄的指令碼
dbghelp.dll
mcee.dll
Mpishim.bat:用於啟動遠端偵錯工具的指令碼
Mpishim.exe:在 IDE 和 Msvsmon.exe 之間協調通訊的程式
Msvsmon.exe:遠端偵錯工具
Msvsmon.exe.config
PfxTaskProvider.dll
symsrv.dll
symsrv.yes
vbdebug.dll
1028\msdbgui.dll
1028\vbdebugui.dll
請參閱
概念
MPI 叢集偵錯工具的組態屬性
針對 HPC 叢集上的 MPI 應用程式進行偵錯