2008-11-30 189 views
100

我有一個編譯和運行的MPI程序,但我想通過它來確保沒有奇怪的事情發生。理想情況下,我想要一個簡單的方法將GDB附加到任何特定的進程,但我不確定這是可能的還是如何去做。另一種方法是讓每個進程將調試輸出寫入一個單獨的日誌文件,但這並沒有給調試器帶來同樣的自由。如何調試MPI程序?

有沒有更好的方法?你如何調試MPI程序?

回答

48

正如別人所說,TotalView是這個標準。但它會讓你胳膊和腿。

該OpenMPI網站有一個偉大的FAQ on MPI debugging。 FAQ中的項目#6描述瞭如何將GDB附加到MPI流程。閱讀整個事情,有一些很棒的提示。

如果您發現您有太多過程需要跟蹤,請查看Stack Trace Analysis Tool (STAT)。我們在Livermore使用它來從潛在的數十萬個正在運行的流程中收集堆棧跟蹤信息,並向用戶智能地呈現它們。這不是一個全功能的調試器(一個全功能的調試器永遠不會擴展到208k內核),但它會告訴你哪些進程組正在做同樣的事情。然後,您可以在標準調試器中遍歷每個組的代表。

+10

截至2010年[Allinea DDT](http://www.olcf.ornl.gov/2010/07/12/upgrade-adds-muscle-to-debugger/)是一個全功能的調試器, 208k核心 – Mark 2012-05-31 12:00:10

+0

因此,我會繼續努力,並且在這裏提高Mark @的答案。滴滴涕很好。試試看吧。 TotalView現在也與STAT集成,所以如果你的站點有一個TotalView安裝,你也可以嘗試。 LLNL保留了TotalView和DDT,TotalView終於有了一些激烈的競爭。 – tgamblin 2012-06-07 00:13:27

+0

我想再次鏈接到關於MPI調試的常見問題(http://www.open-mpi.org/faq/?category=debugging#serial-debuggers)。具體來說,子彈6是一個很好,快速和簡單的(即使是我也足夠了!)瞭解至少調試單個進程的方法。 – Jeff 2012-08-19 18:30:26

3

調試MPI程序的「標準」方法是使用支持該執行模型的調試器。

在UNIX上,TotalView據說對MPI有很好的支持。

5

http://github.com/jimktrains/pgdb/tree/master是我寫的用來做這件事情的工具。有一些文檔,請隨時向我提問。

你基本上調用一個perl程序來封裝GDB,並將它的IO引導到中央服務器。這允許GDB在每臺主機上運行,​​並讓您在終端上的每臺主機上訪問它。

+0

謝謝!下次我在MPI工作時,我一定會檢查一下。 – 2009-04-09 03:45:27

1

我使用這個小小的homebrewn方法將調試器附加到MPI進程 - 在代碼中的MPI_Init()之後立即調用以下函數DebugWait()。現在,當進程正在等待鍵盤輸入時,您有時間將調試器附加到它們並添加斷點。完成後,提供單個字符輸入,然後就可以開始了。

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); 
} 

當然,你只想編譯這個函數來調試構建只。

+0

即使是簡單的代碼,MPI也需要最多的調試語句。 (哈哈)這可能非常有幫助。 – Troggy 2009-07-02 16:38:54

+2

此解決方案與此處的第6項類似(http://www.open-mpi.org/faq/?category=debugging#serial-debuggers)。你可以通過添加`gethostname(hostname,sizeof(hostname))來改善你的代碼。 printf(「主機%s上的PID%d準備掛載\ n」,getpid(),hostname);`。然後,通過鍵入`rsh `,最後`gdb --pid = `來附加進程。 – Jeff 2012-08-19 18:35:32

1

我使用日誌跟蹤進行了一些與MPI相關的調試,但是如果您使用的是mpich2,也可以運行gdb:MPICH2 and gdb。在處理從調試器啓動時很棘手的進程時,這種技術通常是一種很好的做法。

+0

鏈接已損壞。 – 2015-11-21 02:08:49

2

還有我的開源工具padb,它旨在幫助並行編程。我稱它爲「工作檢查工具」,因爲它的功能不僅僅是因爲調試器也可以用作例如程序之類的平行頂端。以「完整報告」模式運行,它將向您顯示應用程序中每個進程的堆棧跟蹤以及每個級別的每個函數的本地變量(假設您使用-g編譯)。它還會顯示「MPI消息隊列」,即作業中每個等級的未完成發送和接收列表。

除了顯示完整的報告,還可以告訴padb放大作業中各個位的信息,有大量的選項和配置項來控制顯示的信息,請參閱網頁更多細節。

Padb

62

我發現GDB非常有用。我用它作爲

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

這將啓動的xterm窗口中,我可以做

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

平時工作正常

您也可以打包這些命令一起使用:

mpirun -n <NP> xterm -hold -e gdb -ex run --args ./program [arg1] [arg2] [...] 
1

附着GDB到MPI過程的命令是不完整的,它應該是

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

MPI和gdb的簡要討論可參見here

16

正如其他人所提到的,如果您只使用MPI流程的少數您可以嘗試使用multiple gdb sessions,可怕的valgrind或推出自己的printf/logging解決方案。

如果您使用的是更多的進程,那麼您確實需要一個適當的調試器。 OpenMPI FAQ推薦使用Allinea DDTTotalView

我在Allinea DDT上工作。這是一個全功能的,圖形化的源代碼調試所以是的,你可以:

  • 調試或附着(超過20萬)MPI進程
  • 步驟,並暫停它們在羣體或個別
  • 添加斷點,手錶和跟蹤點
  • 捕捉內存錯誤和泄漏

...等等。如果你已經使用Eclipse或Visual Studio,那麼你就會在家。

我們添加了一些有趣的特徵專門用於調試並行代碼(無論是MPI,多線程或CUDA):

  • 標量變量自動跨所有工藝相比: Sparklines showing values across processes

  • 您還可以跟蹤和過濾變量和表達式在整個過程和時間上的值: Tracepoints log values over time

它廣泛應用於之中top500 HPC網站,如ORNLNCSALLNLJülich等。人。

界面非常活潑;我們在0.1秒時間內逐步合併了220,000個過程的堆棧和變量,作爲Oak Ridge捷豹集羣驗收測試的一部分。

@tgamblin提到了優秀的STAT,它與Allinea DDT集成在一起,就像幾個其他流行的開源項目一樣。

17

這裏的很多帖子都是關於廣發行,但沒有提到如何從啓動時連接到進程。很明顯,你可以連接到所有進程:

mpiexec -n X gdb ./a.out 

但是,這是瘋狂無效的,因爲你必須反彈,啓動所有進程。

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

現在只有你的程序將獲得廣發行的一個:如果你只是想調試一個(或少數)MPI過程中,可以使用:操作者補充說,在命令行上一個單獨的可執行文件。

4

使用screengdb一起調試MPI應用程序很好,特別是如果xterm不可用或者您處理的處理器超過幾個。伴隨着stackoverflow搜索,一路上有許多陷阱,所以我將全面重現我的解決方案。

首先,在MPI_Init之後添加代碼以打印PID並暫停程序以等待您附加。標準解決方案似乎是一個無限循環;我最終解決了raise(SIGSTOP);,這需要額外撥打continue才能在gdb中轉義。

} 
    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); 
} 

編譯後,在後臺運行可執行文件,並捕獲stderr。然後您可以爲某個關鍵字(這裏是文字PID)的stderr文件grep獲取每個進程的PID和排名。

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`) 

gdb會話可以附加到每個進程gdb $MDRUN_EXE $PID。在屏幕會話中這樣做可以輕鬆訪問任何gdb會話。-d -m以分離模式啓動屏幕,-S "P$RANK"允許您命名屏幕以便以後輕鬆訪問,而bash的-l選項以交互模式啓動它並使gdb不會立即退出。

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 

一旦GDB的屏幕已經開始,你可以使用腳本輸入到屏幕(這樣你就不必每次都輸入屏幕,然後鍵入同樣的事情),使用屏幕的-X stuff命令。命令末尾需要換行符。這裏的屏幕可以通過-S "P$i"使用之前給出的名稱進行訪問。 -p 0選項非常重要,否則該命令會間歇性地失敗(根據您以前是否連接到屏幕)。

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 

在這一點上,你可以使用screen -rS "P$i"附加到任何屏幕並使用Ctrl+A+D分離。類似於前面的代碼段,可以將命令發送到所有的gdb會話。

0

另一種解決方案是在模擬MPI SMPI內運行代碼。這是一個我參與其中的開源項目。每個MPI等級都將被轉換爲同一個UNIX進程的線程。然後,您可以輕鬆使用gdb來執行MPI等級。 SMPI提出了MPI應用研究的其他優點:clairevoyance(你可以觀察系統的每個部分),再現性(幾次運行導致完全相同的行爲,除非你指定),缺少heisenbugs(如模擬平臺保持不同於主機)等。

欲瞭解更多信息,請參閱this presentationrelated answer

0

如果你是一個tmux用戶,你會覺得很舒服使用貝內迪克特摩擦產品有限公司的腳本:tmpi

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

有了它,你有多個面板(進程數)的所有同步(每一個命令被同時複製到所有面板或進程上,因此與xterm -e方法相比,您可以節省大量時間)。此外,您可以在不需要移動到另一個面板的情況下知道變量的值,只需執行print,這將在每個面板上打印每個過程的變量值。

如果您不是tmux用戶,我強烈建議您嘗試一下並查看。