Linux下MPI (Message Passage Interface) 的程序不太好調試,在windows下vs2005以上的IDE有集成的簡便MPI調試工具,沒有用過,有興趣的可以試驗一下。下面總結了一些最近在用MPI和c語言寫程序時的調試經驗(Ubuntu環境,c語言, mpich 1.2.7)。
需要注意的幾個小問題
在編譯程序的時候 –g 是一定要加的,不然在gdb調試的時候可能會報類似“source is not available”的錯誤。開始我調程序的時候我都把我的程序的每個調試版本,分別發送到集群中的每台機器上面,然後在mpirun –machinefile host –np 3 myprogram 運行我的程序,這種方法沒有效率,只能在最後記錄實驗結果的時候或者最後調試階段才能用。有效率的方式是 mpirun –np 3 myprogram 在本機直接運行程序,這樣mpi就會在本機開3個myprogram的進程,這樣不接網線都可以方便的調試mpi的程序。這是幾個小問題,下面切入關鍵部分。
用gdb來調試mpi的程序
首先,本文所用的mpich版本為1.2.7,可能跟其他版本有一定的差異,RTFM,看看自己所用版本的使用手冊來解決版本上的差異。
Mpi程序運行的時候都是通過mpirun 後接參數和你的程序,gdb也是類似的過程,所以你不可以直接 gdb mpirun –np 3 myprogram,但你可以直接mpirun –gdb –np 3 myprogram。這樣你就可以再gdb中調試你的程序了。
不過,這樣有個問題,你可以調試在主節點運行的部分,也就是相對於集群而言,你本機所運行的部分,程序運行到子各個節點部分以後,你的gdb就不能繼續調下去了,這個就是個問題。Gdb其實可以在程序已經執行了以後,再掛載你的程序,這樣你可以在程序執行的期間把gdb掛載進來。簡而言之就是把程序暫停起來(比如讀個鍵盤輸入getchar()之類的),用gdb myprogram pid (myprogram是你程序的進程名, pid是你程序進程的pid號)如何查看pid號呢? 在終端裡面運行 ps –a 就可以了,這樣就可以找到你自己程序的進程名和PID號,gdb myprogram 1234 這樣就可以掛載到你要調試的位置了。
但子節點有兩種情況,一種情況是子節點運行的那部分程序運行在集群中其他的計算機上面;另一種情況是都在本機運行。第一種情況較容易解決,只要在程序運行後,暫停子節點運行的那部分程序(在子節點就不可以用getchar()了,我用sleep()函數來解決這個問題),ssh上去子節點計算機上面,在子節點上面ps –a查進程信息 gdb mp 1234 掛載進去調試,不過要確保子節點上面也安裝了GDB。第二種情況,因為在本機運行上面開了多個你自己程序的進程,這樣會同時出現 3個myprogram,雖然pid各不相同,不過程序名完全一樣,占用內存不是有內存洩露也幾乎一樣,其中一個是主節點的進程,另外幾個是子節點的進程,這樣要知道哪個進程是子節點部分的,就要在子節點部分獲取所對應的進程的pid,很簡單,只要在代碼中加入:
#include <sys/types.h>
#include <unistd.h>
//…
int pid;
pid = getpid();
printf ( “\n%d\n”, pid );
//…
這樣就可以根據獲取的pid信息來確定要掛載到哪個進程裡面