Presentation is loading. Please wait.

Presentation is loading. Please wait.

NUIST HPC使用讲座 ——代码调试 刘建宇 2015-04-28.

Similar presentations


Presentation on theme: "NUIST HPC使用讲座 ——代码调试 刘建宇 2015-04-28."— Presentation transcript:

1 NUIST HPC使用讲座 ——代码调试 刘建宇

2 !!!声明!!! ftp://202.195.238.13/Public/debugging.pdf 仅校内可访问
这里讨论的用户环境设置是基于目前(2014年)的NUIST HPC的配置上进行的 相关的用法、设置方式等有一定的普遍性,也有本地局限性 这里讨论的用法、设置方式,在不同的系统及配置下可能不适用 这里讨论的用法、设置方式,可能有不全面或不足之处 仅供参考,谨慎使用 ftp:// /Public/debugging.pdf 仅校内可访问

3 脚本调试 使用shell的执行选项 在shell中输出调试信息 使用“调试钩子” 脚本调试器bashdb

4 脚本调试 ——使用shell的执行选项(-n)
读取脚本但不执行 测试脚本是否存在语法错误 bash -n script.sh ksh -n script.sh csh/tcsh -n script.sh #!/bin/bash if [ "$#" != "1" ]; then echo "usage : $0 filename" elif [ ! -f $1 ] then echo "$1 not exists" else tail $1 fi bash -n ./exp01.bash exp02.bash: line 8: syntax error near unexpected token `else' exp02.bash: line 8: `else'

5 脚本调试 ——使用shell的执行选项(-x)
进入跟踪方式,显示所执行的每一条命令 全局调试 bash -x script.sh ksh -x script.sh csh/tcsh -x script.sh 局部调试(仅bash/ksh) set -x 打开调试信息 set +x 关闭调试信息

6 脚本调试 ——使用shell的执行选项(-x)
#!/bin/bash echo "Hello $USER," echo Today is `date +"%Y-%m-%d"` echo bye-bye bash -x ./exp02.bash + echo 'Hello jliu' Hello jliu + echo Today is `date +%Y-%m-%d` Today is + echo bye-bye bye-bye #!/bin/bash echo "Hello $USER," set -x echo Today is `date +"%Y-%m-%d"` set +x echo bye ./exp03.bash Hello jliu + echo Today is `date +%Y-%m-%d` Today is + set +x bye-bye

7 脚本调试 ——对“-x”的增强选项 BASH KSH
PS4='+${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]}:' KSH PS4='+${LINENO}:'

8 脚本调试 ——对“-x”的增强选项 #!/bin/bash isRoot () { if [ $UID -ne 0 ]; then
return 1 else return 0 fi } isRoot if ["$?" -ne 0 ]; then echo "Must be root to run this script" exit 1 echo "welcome root user"

9 脚本调试 ——对“-x”的增强选项 bash -n ./exp04.bash ./exp04.bash
exp04.bash: line 10: [1: command not found welcome root user export PS4='+${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]}:' bash -x ./exp04.bash +exp04.bash:9::isRoot +exp04.bash:3:isRoot:'[' 502 -ne 0 ']' +exp04.bash:4:isRoot:return 1 +exp04.bash:10::'[1' -ne 0 ']' exp04.bash: line 10: [1: command not found +exp04.bash:14::echo 'welcome root user' welcome root user

10 脚本调试 ——使用shell的执行选项(-e)
如果产生错误立即退出 全局影响 bash -e script.sh ksh -e script.sh csh/tcsh -e script.sh 局部影响(仅bash/ksh) set -e 打开退出陷阱 set +e 关闭退出陷阱

11 脚本调试 ——使用shell的执行选项(-e)
#!/bin/bash ls dummy_$$ echo "Hello $USER" echo Today is `date +"%Y-%m-%d"` echo bye-bye bash ./exp05.bash ls: cannot access dummy_25097: No such file or directory Hello jliu Today is bye-bye bash -e ./exp05.bash ls: cannot access dummy_25107: No such file or directory

12 脚本调试 ——在shell中输出调试信息 使用echo输出调试信息 使用 trap命令 echo '|var='$var'|'
其基本的语法是: trap 'command' signal shell伪信号 EXIT 从一个函数中退出或整个脚本执行完毕 ERR 当一条命令返回非零状态时(代表命令执行不成功) DEBUG 脚本中每一条命令执行之前

13 脚本调试 ——使用 trap命令 #!/bin/bash ERRTRAP() {
echo "[LINE:$1] Error: Command or function exited with status $?" } foo() { return 1 trap 'ERRTRAP $LINENO' ERR abc foo echo "End" bash ./exp07.bash exp07.bash: line 11: abc: command not found [LINE:11] Error: Command or function exited with status 127 [LINE:8] Error: Command or function exited with status 1 End

14 脚本调试 ——使用 trap命令 #!/bin/bash
trap 'echo "before execute line:$LINENO, a=$a,b=$b,c=$c"' DEBUG a=1 if [ "$a" -eq 1 ]; then b=2 else b=1 fi c=3 bash ./exp08.bash before execute line:3, a=,b=,c= before execute line:4, a=1,b=,c= before execute line:5, a=1,b=,c= before execute line:9, a=1,b=2,c= before execute line:10, a=1,b=2,c=3 end

15 脚本调试 ——使用“调试钩子” 使用if块 使用命令序列
if [ “$DEBUG” = “true” ]; then #此处可以输出调试信息 fi 使用命令序列 namelist=`ls -l namelist.input` || { echo Error; exit 1; } 使用DEBUG函数 _DEBUG=“on" DEBUG() { [ "$_DEBUG" == "on" ] && } DEBUG echo "hello"

16 脚本调试 ——使用“调试钩子” #!/bin/bash _DEBUG="on" function DEBUG () {
} fun01 () { echo "BUT HERE I am inside the function fun01() body" echo "HERE I am outside the function fun01() body!" sleep 2 debug fun01 echo "End" bash ./exp09.bash HERE I am outside the function fun01() body! BUT HERE I am inside the function fun01() body End

17 程序调试 程序出错了!!!

18 程序调试 ——系统的相关文件 标准输入/标准输出/标准错误 stdin/stdout/stderr 文件描述符 stdin stdout
程序调试 ——系统的相关文件 标准输入/标准输出/标准错误 stdin/stdout/stderr 文件描述符 stdin stdout stderr Unix 1 2 Fortran 通常约定 5 6 F2003 ISO_FORTRAN_ENV INPUT_UNIT OUPUT_UNIT ERROR_UNIT C

19 程序调试 ——输出重定向 PROGRAM TEST WRITE(0,*) "Error" WRITE(6,*) "Good"
WRITE(*,*) "Error Good" END PROGRAM TEST #include <stdio.h> int main() { fprintf(stderr,"Error\n"); fprintf(stdout,"Good\n"); printf("Error Good\n"); return 0; }

20 程序调试 ——输出重定向 ./a.out bash & ksh Error ./a.out 1>out.log Good Error
Error Good a.out > out.log ./a.out >& out.log bash & ksh ./a.out 1>out.log Error ./a.out 2>error.log Good Error Good ./a.out > out.log 2>&1 ./a.out >out.log 2>err.log csh/tcsh (a.out > out.log) >& err.log sh -c 'a.out > out' 2>& err.log

21 程序调试 ——错误信息的查找 应用程序自己输出的日志文件 运行时重定向输出的日志文件 作业调度系统的标准输出和标准错误文件
WRF :rsl 文件 运行时重定向输出的日志文件 >& out.log 作业调度系统的标准输出和标准错误文件 PBS O 文件(标准输出)和E文件(标准错误) 或由 #PBS -j,#PBS -o, #PBS -e 指定的文件 错误的诊断需要综合查看所有的日志文件

22 程序调试 ——错误信息的查找(示例) PBS O 文件 任务脚本中没有重定向的标准输出的内容 并行环境的标准输出的内容
作业调度系统自己的标准输出的内容 =================================================================================== = BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES = EXIT CODE: 9 = CLEANING UP REMAINING PROCESSES = YOU CAN IGNORE THE BELOW CLEANUP MESSAGES

23 程序调试 ——错误信息的查找(示例) PBS E文件 任务脚本中没有重定向的标准错误的内容 并行环境的标准错误的内容
作业调度系统自己的标准错误的内容 HYD_pmcd_pmip_control_cmd_cb (pm/pmiserv/pmip_cb.c:902): assert (!closed) failed HYDT_dmxu_poll_wait_for_event (tools/demux/demux_poll.c:76): callback returned error status main (pm/pmiserv/pmip.c:206): demux engine error waiting for event HYDT_bscu_wait_for_completion (tools/bootstrap/utils/bscu_wait.c:75): one of the processes terminated badly; aborting … … …

24 程序调试 ——错误信息的查找(示例) 应用程序自己的输出文件 WRF RSL文件 rsl.out :WRF输出到标准输出的内容
rsl.err :WRF输出到标准错误的内容 Timing for main: time _11:48:00 on domain   1:   elapsed …             1  points exceeded cfl=2 in domain d01 at time _11:48:00 hours   MAX AT i,j,k:           39          16           2  vert_cfl,w,d(eta)=         … … …             6  points exceeded cfl=2 in domain d01 at time _11:48:00 hours   MAX AT i,j,k:           39          16           3  vert_cfl,w,d(eta)=          … … … Timing for main: time _11:49:00 on domain   2:    elapsed …

25 程序调试 ——异常终止常见错误信息 Signal 11 or Signal 9 Signal 10 Singal 15
通常都是内存访问问题,例如数组下标越界、非法使用指针 或非正常结束并行程序 Singal 11(segmentation fault),多数访问了程序空间以外的地址 Singal 9 ,多数访问了程序内部不该访问的地址 Signal 10 ‘bus error’,不常见,通常由糟糕的代码编写引起或用不正确的方式进行的编译 Singal 15 Killed,进程被强制终止

26 程序调试 ——编译器的调试选项 PGI INTEL GFORTRAN -g -O0 -traceback
-Mbounds -Mchkfpstk  -Mchkstk  -Mchkptr  -Ktrap=fp -Minfo=all INTEL -check all -check bounds -check pointers -check uninit -ftrapuv -warn all GFORTRAN -g -O0 -fbacktrace -ffpe-trap=list -fbounds-check -fcheck-array-temporaries -Wall

27 程序调试 ——定位错误 异常终止运行 去掉所有优化选项 加入调试编译选项进行编译 打开程序编译时的调试代码宏开关 打开程序运行时的调试开关
根据程序输出信息,在代码中添加相应调试输出信息 测试时使相同错误能在3-5分钟内就能触发 如果是并行程序,仅可能先测试串行运行的情况

28 程序调试 ——定位错误 运行异常/结果有问题 去掉所有优化选项,仅使用 加上浮点运算约束编译选项 PGI : -Kieee
-g -O0 加上浮点运算约束编译选项 PGI : -Kieee Intel : -fp-model precise -no-fma GNU : -ffloat-store -fno-fast-math 根据程序输出信息,在代码中添加相应调试输出信息 如果是并行程序,尽可能先测试串行运行的情况

29 程序调试 ——定位错误(示例一) program loop 不加边界检查编译选项 implicit none
real, allocatable :: u(:) integer i allocate(u(10)) do i=1,11 ! off-by-one error u(i)= i * 1.0 enddo print *,"i=",i, "u=",u(i) deallocate(u) end 不加边界检查编译选项 PGI无运行时错误,给出不正确结果 i= u= Intel、Gfotran产生运行时错误 *** glibc detected *** ./a.out: free(): invalid next size (fast): 0x ec5b40 *** 添加边界检查编译选项后的运行情况 At line 6 of file loop.f90 Fortran runtime error: Array reference out of bounds for array 'u', upper bound of dimension 1 exceeded (11 > 10)

30 程序调试 ——定位错误(示例二) 添加-traceback选项编译运行情况 无-traceback选项编译运行情况
interpolation_grib_api]$ ./test.sh Interpolate product number forrtl: severe (174): SIGSEGV, segmentation fault occurred 添加-traceback选项编译运行情况 interpolation_grib_api]$ ./test.sh Interpolate product number forrtl: severe (174): SIGSEGV, segmentation fault occurred Image PC Routine Line Source interpolation_exa AE6 hntfauh_ hntfauh.F interpolation_exa C6 hntfau_ hntfau.F interpolation_exa intf_ intf.F interpolation_exa BD0 Unknown Unknown Unknown interpolation_exa D8 Unknown Unknown Unknown interpolation_exa B37 MAIN__ interpolation_example.F interpolation_exa FC Unknown Unknown Unknown libc.so AE61ECDD Unknown Unknown Unknown interpolation_exa F9 Unknown Unknown Unknown

31 程序调试 ——定位错误(示例二) interpolation_example.F 122 INLEN = IREC
IRET = INTF2(INGRIB,INLEN,NEWFLD,NEWLEN) intf.F IF( LUSEHIR ) THEN IRET = HNTFAU(FLDIN,INLEN) ELSE IRET = INTFAU(FLDIN,INLEN) hntfau.F IRET = HNTFAUH(INGRIB,INLEN) hntfauh.F DO LOOP = 1, INLEN ZNFELDI( LOOP ) = FLDIN( LOOP ) ENDDO

32 程序调试 ——定位错误(示例三) 我已经设置了debug_level=0,为什么生成的rsl.out文件还是这么大,这样我的程序跑不完就断掉了!有没有方法可以继续接着跑么

33 程序调试 ——定位错误(示例三) 使用head/tail查看rsl.out的头/尾信息
包含大量的‘Error in mapping flagsoap to start_ind’ 信息 使用grep在chem中查找包含“mapping flagsoap”的代码 grep -i "mapping flagsoap" chem/*.F 5081 ! acd_alma_bugfix start do iv = start_ind, ngas_ioa + ngas_soa if (flagsoap(iv-start_ind+1).eq.2) then xsumfresh(ibin)= xsumfresh(ibin)+aer(iv,jtotal,ibin) elseif (flagsoap(iv-start_ind+1).eq.1) then xsumaged(ibin)= xsumaged(ibin)+aer(iv,jtotal,ibin) elseif (flagsoap(iv-start_ind+1).eq.0) then < print *, 'Error in mapping flagsoap to start_ind' endif enddo

34 程序调试 ——错误的修正 不要简单的在‘代码层面’做修正 在没有确切弄清楚相关代码的‘实际意义’时 修改前先备份原来的代码
向代码开发人员寻求帮助 或尽量做一些安全、保守的修改 修改前先备份原来的代码 注释掉原来的代码而不是直接修改或删除 修改后做相应注释

35 程序调试 ——错误的修正(示例) 示例三中,假设数据就是会有这种情况,能不能简单注释掉行5088的print语句? 不能
一种安全、保守的修改方式为 elseif (flagsoap(iv-start_ind+1).eq.0) then if ( err_sum .lt. 10 ) & print * ' Error in mapping flagsoap to start_ind ' err_sum = err_sum +1 endif endo if ( err_sum .gt. 10 ) & print * ' Too many errors in mapping flagsoap to start_ind '

36 程序调试 ——其他调试工具 TotalView idb pgdbg gdb 使用版本控制管理
IBM Graphical Symbolic Debugger idb Intel Debugger for Linux pgdbg PGI Graphical Symbolic Debugger gdb GNU Debugger 使用版本控制管理 SVN,CVS等

37 问题或建议


Download ppt "NUIST HPC使用讲座 ——代码调试 刘建宇 2015-04-28."

Similar presentations


Ads by Google