Python modul PyCUDA: otklanjanje grešaka i curenja memorije
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.
Program za otklanjanje grešaka
Podsjetnik: prevođenje C++ programa
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
Rad s alatom gdb
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 breakpointuprint <ime varijable>
-- ispis podataka o varijabli (trenutna adresa i vrijednost)info locals
-- ispis podataka o lokalnim varijablama unutar trenutnog dosegainfo args
-- ispis podataka o argumentima trenutne funkcijehelp <naredba>
-- pomoć o naredbinext
,step
,finish
, ...
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žicout
koju ste sami dodali. - Izvršite pokretanje. Kod svakog breakpointa ispišite stanje obje varijable.
- Postavite tri breakpointa: funkcija ispis, postojeća linija koja sadrži
Specifičnosti alata cuda-gdb
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
Zadatak
Na primjeru za zbroj vektora isprobajte ovdje navedene specifične naredbe alata cuda-gdb
.
Otklanjanje curenja memorije
ToDo
Ovaj dio treba napisati u cijelosti.
Author: Vedran Miletić, Kristijan Lenković