author |
---|
Vedran Miletić, Kristijan Lenković |
Jednostavno otklanjanje grešaka ("debuggiranje") smo već radili ispisivanjem vrijednosti varijabli korištenjem funkcije printf()
. Sofisticiraniji način za istu stvar je korištenjeme makro naredbe, primjerice INFUNIRI_DEBUG
na način
#include <stdio.h>
#define INFUNIRI_DEBUG
__global__ void funkcija (...)
{
...
#ifdef INFUNIRI_DEBUG
printf ("Varijabla 1 ima vrijednost %d, varijabla 2 ima vrijednost %2.3f\n", var1, var2);
#endif
...
}
Prednost ovog pristupa je što kod završne verzije alata nije potrebno brisati čitav niz poziva funkcije printf()
, već je dovoljno maknuti ili zakomentirati liniju #define INFUNIRI_DEBUG
. Naime, to će učiniti da sve makro naredbe #ifdef INFUNIRI_DEBUG
vrate false
, i do prevođenja koda koji sadrži printf()
neće ni doći.
Primjerice, uzmemo li jednostavan C++ program nazvan program1.cpp
čiji je kod oblika:
#include <iostream>
using namespace std;
void ispis (int &var1, float &var2)
{
var1 = 3;
var2 = 8.3;
cout << "Funkcija ispis" << endl;
}
int main ()
{
int a = 5;
float b = 2.7;
cout << "Pocetak" << endl;
ispis (a, b);
cout << "Kraj" << endl;
return 0;
}
Prevođenje i pokretanje izvodimo na način
$ g++ program1.cpp -o program1
$ ./program1
Program za pronalaženje pogrešaka (engl. debugger) je alat koji pomaže programeru u pronalaženju semantičkih grešaka u kodu. Sam po sebi, on ne ispravlja kod.
Radi tako da pokreće instancu programa u kontroliranom okruženju i time omogućuje programeru da:
- pokreće program u koracima na razini programskog jezika,
- ispiše vrijednosti varijabli i izraza za vrijeme pokretanja,
- promijeni tok programa kod pokretanja,
- (neki debuggeri) obrnuto pronalaženje grešaka, odnosno odlazak unatrag i poništavanje destruktivnih operacija spremanjem serije stanja.
Koristit ćemo GNU Debugger (gdb
), koji radi na operacijskim sustavima sličnim Unixu i Windowsima. Nema vlastito grafičko sučelje, ali postoji niz alata koji nude korisniku prijateljsko sučelje (primjerice, ddd
te IDE-i kao što su Eclipse i NetBeans).
gdb
je simbolički debugger, odnosno radi na razini izvornog koda, pa je sposoban analizirati program na razini programskog jezika (ne samo asemblerskoj). Simbolički debuggeri su specifični za programski jezik s kojim rade i zahtijevaju dodatne informacije (debug simbole) kako bi preslikali asemblerske instrukcije na izvorni kod.
Debug simboli proizvode se kod prevođenja programa (primjerice, parametar -g
kod gcc
-a) i:
- integrirani u izvršnu datoteku (u tom slučaju su izvršne datoteke mnogo veće), ili
- odvojeni od izvršne datoteke (primjerice, kod .deb/.rpm paketa u -dbg/-debug paketima).
Debug simboli sadrže informacije o:
- koje linije izvornog koda stvaraju koje asemblerske instrukcije,
- imenima varijabli.
Dakle, pokretanje pomoću alata gdb
vršimo na način
$ g++ -g program1.cpp -o program1_debug
$ gdb program1_debug
Koristit ćemo iduće naredbe
-
quit
-- izlaz iz alata -
break <broj linije ili ime funkcije>
-- postavljanje točke prekida izvođenja programa; dvije mogućnosti- broj linije na kojoj postavljamo breakpoint
- ime funkcije na kojoj postavljamo breakpoint
-
run
-- pokretanje programa do prvog breakpointa -
continue
-- nastavak izvođenja nakon stajanja na breakpointu -
print <ime varijable>
-- ispis podataka o varijabli (trenutna adresa i vrijednost) -
info locals
-- ispis podataka o lokalnim varijablama unutar trenutnog dosega -
info args
-- ispis podataka o argumentima trenutne funkcije -
help <naredba>
-- pomoć o naredbi -
next
,step
,finish
, ...
!!! admonition "Zadatak"
- Unutar funkcije ispis dodajte još jednu promjenu varijabli, a zatim još jedan ispis teksta po vlastitom izboru. Izvršite prevođenje koda s debug simbolima i pokrenite ga u alatu gdb
.
- Postavite tri breakpointa: funkcija ispis, postojeća linija koja sadrži `cout` unutar funkcije i linija koja sadrži `cout` koju ste sami dodali.
- Izvršite pokretanje. Kod svakog breakpointa ispišite stanje obje varijable.
Specifične naredbe alata cuda-gdb
su
cuda kernel
-- ispis podataka o trenutnom CUDA zrnu ili odabir zrnacuda grid
-- ispis podataka o trenutnoj CUDA rešetci ili odabir rešetkecuda block
-- ispis podataka o trenutnom CUDA bloku ili odabir blokacuda thread
-- ispis podataka o trenutnoj CUDA niti ili odabir niticuda device
-- ispis podataka o trenutnom CUDA uređaju ili odabir uređajacuda sm
-- ispis podataka o trenutnom CUDA streaming multiprocesoru ili odabir streaming multiprocesoracuda warp
-- ispis podataka o trenutnoj CUDA osnovi ili odabir osnovecuda lane
-- ispis podataka o trenutnoj CUDA stazi ili odabir staze
Modul PyCUDA se može koristiti u kombinaciji s alatom cuda-gdb
prema službenim uputama. Iskoristimo primjer koji vrši zbrajanje vektora; alat pokrećemo naredbom
$ cuda-gdb --args python -m pycuda.debug zbrajanje_vektora.py
...
(cuda-gdb) break vector_sum
... (zanemarite grešku da funkcija nije definirana) ...
(cuda-gdb) run
!!! admonition "Zadatak"
Na primjeru za zbroj vektora isprobajte ovdje navedene specifične naredbe alata cuda-gdb
.
!!! todo Ovaj dio treba napisati u cijelosti.