답변:
다른 사람이 말했듯이 TotalView 가 이에 대한 표준입니다. 그러나 팔과 다리가 필요합니다.
OpenMPI 사이트에는 MPI 디버깅에 대한 훌륭한 FAQ가 있습니다. FAQ의 6 번 항목은 GDB를 MPI 프로세스에 연결하는 방법을 설명합니다. 모든 것을 읽으십시오. 좋은 팁이 있습니다.
추적 할 프로세스가 너무 많으면 스택 추적 분석 도구 (STAT)를 확인하십시오 . Livermore에서는이를 사용하여 잠재적으로 수십만 개의 실행중인 프로세스에서 스택 추적을 수집하고이를 사용자에게 지능적으로 표현합니다. 완전한 기능을 갖춘 디버거는 아니지만 (모든 기능을 갖춘 디버거는 208k 코어로 확장되지 않음) 어떤 프로세스 그룹이 동일한 작업을 수행하는지 알려줍니다. 그런 다음 표준 디버거에서 각 그룹의 담당자를 단계별로 안내 할 수 있습니다.
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] [...]
<file>
하고 -x <file>
gdb에 전달 하면됩니다.
여기의 많은 게시물은 GDB에 관한 것이지만 시작에서 프로세스에 연결하는 방법은 언급하지 않았습니다. 분명히 모든 프로세스에 연결할 수 있습니다.
mpiexec -n X gdb ./a.out
그러나 모든 프로세스를 시작하려면 바운스해야하기 때문에 이는 비효율적입니다. 하나 (또는 소수의) MPI 프로세스 만 디버그하려는 경우 :
연산자를 사용하여 명령 행에서 별도의 실행 파일로 추가 할 수 있습니다 .
mpiexec -n 1 gdb ./a.out : -n X-1 ./a.out
이제 프로세스 중 하나만 GDB를 얻습니다.
다른 사람들이 언급했듯이, 소수 의 MPI 프로세스 로만 작업 하는 경우 여러 gdb 세션 , 중복 가능 valgrind 또는 자체 printf / logging 솔루션 을 사용하려고 시도 할 수 있습니다 .
그보다 많은 프로세스를 사용하고 있다면 실제로 적절한 디버거가 필요합니다. 는 OpenMPI 자주 묻는 질문은 모두 권장 Allinea DDT 와 TotalView을 .
나는 Allinea DDT에서 일한다 . 완전한 기능을 갖춘 그래픽 소스 코드 디버거이므로 다음과 같이 할 수 있습니다.
...등등. Eclipse 또는 Visual Studio를 사용했다면 집에있을 것입니다.
병렬 코드 디버깅을 위해 특별히 흥미로운 기능을 추가 했습니다 (MPI, 멀티 스레드 또는 CUDA 등).
스칼라 변수는 모든 프로세스에서 자동으로 비교됩니다 :
(source : allinea.com )
프로세스 및 시간에 따른 변수 및 표현식의 값을 추적하고 필터링 할 수도 있습니다.
ORNL , NCSA , LLNL , Jülich 등과 같은 상위 500 HPC 사이트 에서 널리 사용됩니다 . 알.
인터페이스는 매우 빠릅니다. 우리는 Oak Ridge의 Jaguar 클러스터에 대한 승인 테스트의 일환으로 0.1 초에 220,000 개의 프로세스 스택과 변수를 스테핑하고 병합하는 시간을 정했습니다.
@tgamblin 은 몇 가지 다른 인기있는 오픈 소스 프로젝트 와 마찬가지로 Allinea DDT 와 통합 된 우수한 STAT를 언급 했습니다.
당신이 tmux
사용자라면 Benedikt Morbach 의 스크립트를 사용하는 것이 매우 편할 것입니다 .tmpi
원본 출처 : https://github.com/moben/scripts/blob/master/tmpi
포크 : https://github.com/Azrael3000/tmpi
그것으로 여러 개의 패널 (프로세스 수)이 모두 동기화됩니다 (모든 명령은 모든 패널 또는 프로세스에서 동시에 복사되므로 xterm -e
접근 방식 과 비교하여 많은 시간을 절약 할 수 있습니다 ). 또한 원하는 프로세스에서 변수 값을 알 수 있습니다.print
다른 패널로 이동하지 않고 그러면 각 프로세스의 변수 값이 각 패널에 인쇄됩니다.
당신이 tmux
사용자 가 아닌 경우 나는 그것을 시도하고 참조하는 것이 좋습니다.
http://github.com/jimktrains/pgdb/tree/master 는이 작업을 수행하기 위해 작성한 유틸리티입니다. 몇 가지 문서가 있으며 궁금한 점이 있으시면 언제든지 저를 찾으십시오.
기본적으로 GDB를 감싸고 IO를 중앙 서버로 퍼널 링하는 perl 프로그램을 호출합니다. 이를 통해 각 호스트에서 GDB를 실행할 수 있으며 터미널의 각 호스트에서 GDB에 액세스 할 수 있습니다.
MPI 응용 프로그램을 디버깅 screen
하는 gdb
데 함께 사용하면 특히 xterm
사용할 수 없거나 몇 개 이상의 프로세서를 처리하는 경우에 효과적입니다. 스택 오버 플로우 검색과 함께 많은 함정이 있었으므로 솔루션을 완전히 재현 할 것입니다.
먼저 MPI_Init 뒤에 코드를 추가하여 PID를 인쇄하고 연결을 기다리는 프로그램을 중지하십시오. 표준 솔루션은 무한 루프 인 것 같습니다. 결국에 정착했습니다 .gdb 내에서 탈출하기 위해 raise(SIGSTOP);
추가 호출이 필요합니다 continue
.
}
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을 잡으십시오. 그런 다음 grep
키워드 (여기서는 리터럴 PID)에 대한 stderr 파일을 사용하여 각 프로세스의 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"
나중에 쉽게 액세스 할 수 있도록 화면 이름을 지정할 수 있으며, -l
bash 옵션은 대화식 모드에서 화면을 시작하고 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 세션으로 전송 될 수 있습니다.
병렬 프로그래밍에 도움이되는 오픈 소스 도구 인 padb도 있습니다. 디버거뿐만 아니라 프로그램과 같은 병렬 상단 기능도 수행 할 수있을뿐 아니라 "작업 검사 도구"라고합니다. "전체 보고서"모드에서 실행하면 응용 프로그램 내 모든 프로세스의 추적을 모든 순위에 대한 모든 함수에 대한 로컬 변수와 함께 표시합니다 (-g로 컴파일 한 것으로 가정). 또한 "MPI 메시지 대기열", 즉 작업 내 각 순위에 대한 미해결 전송 및 수신 목록이 표시됩니다.
전체 보고서를 표시 할뿐만 아니라 작업 내에서 개별 비트 정보를 확대하도록 padb에 지시 할 수 있으며, 표시되는 정보를 제어하기위한 다양한 옵션 및 구성 항목이 있습니다. 자세한 내용은 웹 페이지를 참조하십시오.
이 작은 자체 양조 방법을 사용하여 디버거를 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);
}
물론 디버그 빌드를 위해서만이 함수를 컴파일하고 싶을 것입니다.
gethostname(hostname, sizeof(hostname)); printf("PID %d on host %s ready for attach\n", getpid(), hostname);
. 그런 다음을 입력 rsh <hostname_from_print_statement>
하고 마지막 으로을 입력하여 프로세스에 연결합니다 gdb --pid=<PID_from_print_statement>
.
로그 추적으로 일부 MPI 관련 디버깅을 수행하지만 mpich2를 사용하는 경우 gdb를 실행할 수도 있습니다 : MPICH2 및 gdb . 이 기술은 일반적으로 디버거에서 시작하기 까다로운 프로세스를 처리 할 때 좋은 방법입니다.