Brian W. Kernighan je nekoč napisal:
“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
Razhroščevanje
Prisanje programov ni natančna znanost. Napak je pri začetnikih lahko precej. Najtežje so tiste, ko program dela, vendar nepravilno. Obstajajo pa tudi napake, ki se dogajajo zelo poredko. Ob določenih pogojih, katere ni nujno, da jih lahko zaznamo. V ta namen lahko uporabimo "post-portem" razhroščevanjem tako, da pridobimo spominsko sliko programa v času, ko se je prekinil. Datoteka s spominsko sliko se imenuje core (kosti), ki jih nato uporabimo v razhroščevalniku, da najdemo mesto in razlog zakaj se je prekinil.
Najpomembnejša komercialna programa za razhroščevanje MPI programov sta Totalview in DDT. Poleg tega obstajajo še druga orodja za razhroščevanje spomina kot je Purify, dbx, gdb, DDD, ...
V skupini programov Intel Cluster Studio XE 2011 je na HPCFS nameščen tudi Intel Debugger, s katerim si lahko pomagamo pri razhroščevanu različnih aplikacij prevedenih s prevajalniki intel.
Program poženemo z ukazom:
[leon@prelog ~]$ module load intel
Loading intel/12.0
[leon@prelog ~]$ idb
Za lažje razumevanje vseh možnih načinov razhroščevanja programaje na voljo naslednja primerjava ukazov GDB in Visual studio
ukaz |
|
Visual Studio |
Primerjava ukazov GDB in Visual Studio
run program |
run [args] |
F5 Start Debugging |
start program |
start [args] |
F10 Step over |
pause |
Ctrl-C |
Ctrl-Alt-Break Break All |
continue running |
cont |
F5 Continue |
step-over |
next |
F10 Step over |
step-into |
step |
F11 Step into |
step-out |
finish |
Shift + F11 Step out |
breakpoint |
break file:lineno |
right-click Breakpoint/Insert Breakpoint |
tracepoint |
watch file:lineno |
right-click Debug/New |
watchpoint |
watch expr |
right-click Bkpt/New Data Breakpoint |
stack trace |
bt, where |
Call Stack |
print expression |
print expr |
ImmediateWindow |
display expression |
display expr |
Watch window |
set variable |
set var var=expr |
Variables window |
set environment variable |
set env var[=val] |
Properties/Debugging/Environment |
show machine code |
disassemble |
right-click Go to Disassembly |
step-over, machine code |
nexti |
F10 Step over |
step-into, machine code |
stepi |
F11 Step into |
conditional breakpoint |
condition bnum |
right-click Breakpoint/Condition |
event breakpoint |
handle, signal |
- |
exception breakpoint |
catch, throw |
Debug/Exceptions... |
function breakpoint |
break function |
Debug/New Bkpt/Break at Function |
temporary breakpoint |
tbreak |
F9 Debug/Toggle Breakpoint |
list all breakpoints |
info breakpoints |
Breakpoints window |
attach command to bkpt |
commands bnum |
right-click Breakpoint/When Hit |
print in command |
printf |
right-click Breakpoint/When Hit |
find functions |
info functions expr |
Debug/New Bkpt/Break at Function |
call function |
call expr |
ImmediateWindow |
change function return value |
return expr |
- |
print type |
whatis arg |
right-click Go To Declaration |
print type description |
ptype arg |
right-click Go To Definition |
print memory contents |
x arg |
ImmediateWindow |
select stack frame |
frame arg |
Call Stack right-click Switch to Frame |
print frame description |
info frame |
Call Stack |
Orodja za analizo
Razčlenitev (profiling)
Obstajajo različna orodja za časovno razčlenitev programa in iskanje hroščev. Običajne tehnike z izpisom so lahko uporabne za iskanje napak, težje pa je določiti, kje se največ časa v programu porabi.
Določanje delov kode po časovno osi in številu klicev. Standardna profilerja v Unixu sta prof in gprof. Pri prevajanju je potrebno podati dodatne označbe v kodo:
- f90 -p mycode.F90 -o myprog # za prof
- cc -pg mycode.c -o myprog # za gprof
kar ustvari ob pogonu programa datoteki mon.out ali gmon.out. Profiler poženemo z ukazom
gprof myprog # in ne gprof gmon.out
Bolj enostavno je seveda le merjenje časa programa z ukazom
time ./mojprog
ali uporabo funkcij za čas v samem programu.
Del izpisa programa gprof je
Call graph (explanation follows)
granularity: each sample hit covers 2 byte(s) for 0.03% of 30.83 seconds
index % time self children called name
18.18 12.65 1/1 main [2]
[1] 100.0 18.18 12.65 1 evolve [1]
10.21 0.00 503193600/503193600 force [3]
2.43 0.00 30/30 add_norm [4]
0.00 0.00 30/30 visc_force [5]
-----------------------------------------------
<spontaneous>
[2] 100.0 0.00 30.83 main [2]
18.18 12.65 1/1 evolve [1]
-----------------------------------------------
10.21 0.00 503193600/503193600 evolve [1]
[3] 33.1 10.21 0.00 503193600 force [3]
-----------------------------------------------
2.43 0.00 30/30 evolve [1]
[4] 7.9 2.43 0.00 30 add_norm [4]
-----------------------------------------------
0.00 0.00 30/30 evolve [1]
[5] 0.0 0.00 0.00 30 visc_force [5]
-----------------------------------------------
Grafično obliko omogočajo komercialni profilerji kot je npr pgprog (PGI), kar vidimo v naslednji sliki,