====== 2. Profilování kódu ====== Na začátku cvičení se vrátíme k verzovacímu systému Git a vyzkoušíme si vytváření a spojování větví. Potřebné příkazy najdete třeba na stránce [[courses:b2b99ppc:howtos:git_commands|GIT (2/2) - přehled základních příkazů]] ===== Analýza volání funkcí ===== Pro analýzu volání funkcí použijeme následující kód: #include int add() { int val = 0; for(int i = 0; i < 800; ++i) val += i; return val; } int mult() { int val = 1; for(int i = 0; i < 800; ++i) val *= i; return val; } int foo() { return add() + add() + mult(); } int main(void) { int dum = 0; CALLGRIND_START_INSTRUMENTATION; for(int i = 0; i < 80000; ++i) dum += foo(); CALLGRIND_STOP_INSTRUMENTATION; return 0; } Jednoduchý nástroj na analýzu volání funkcí se jmenuje ''gprof'' a je součástí balíčku ''binutils''. Aby bylo možné nástroj využít, je třeba kompilovat zdrojový kód s volbou ''-pg''. Po spuštění takto kompilovaného prorgramu se vytvoří soubor ''gmon.out'', který obsahuje informace pro ''gprof''. gcc -Wall -pg call.c -o call ./call gprof call gmon.out > gpref_res Druhým nástrojem je ''callgrind'', součást ''valgrindu''. valgrind --tool=callgrind --dump-instr=yes --instr-atstart=no ./call Při volání vznikne log, který je možné analyzovat vhodným nástrojem, např. {{ :courses:b2b99ppc:tutorials:qcachegrind074-32bit-x86.zip |qcachegrind}}. ===== Analýza přístupu do paměti ===== Moderní procesory nepřistupují do operační paměti přímo, ale přes dočasné paměti (cache), díky kterým lze za příznivých podmínek významně urychlit získání dat. {{ :courses:b2b99ppc:tutorials:hierarchysb.jpeg?400 |}} Pro testy budeme používat program, který náhodně vybírá prvky předdefinovaného pole #include #include #include #define SIZE 10485763 #define NBR 10000 int main() { srand(time(NULL)); // array of data int* a = malloc(SIZE*sizeof(int)); for (int i = 0; i < SIZE; i++) a[i] = i; // array of random index int* index = malloc(NBR*sizeof(int)); for (int k = 0; k < NBR; ++k) index[k] = rand() % SIZE; int d = 0; for (int k = 0; k < 1000; ++k) { int c = 0; // random fashion access for (int n = 0; n < NBR; ++n) c += a[index[n]]; d += c; } printf("%i\n", d); free(a); free(index); return 0; } V Linuxu se tradičně používá nástroj ''perf'', který je součástí balíčku ''linux-tools''. Pokud používáte WSL, je třeba zkompilovat nástroj ze zdrojového kódu upraveného jádra Linuxu: sudo apt install build-essential flex bison libssl-dev libelf-dev git clone --depth=1 https://github.com/microsoft/WSL2-Linux-Kernel.git cd WSL2-Linux-Kernel/tools/perf make V prostředí WSL ale zdá se není analýza plně podporována :-( Proto vyzkoušíme nástroj ''cachegrind'', který je opět integrován ve ''valgrindu''. valgrind --tool=cachegrind --cache-sim=yes ./cache Pro urychlení práce můžete využít třeba následující makefile: call: call.c $(CC) -g call.c -o call cache: cache.c $(CC) -g cache.c -o cache callgrind: valgrind --tool=callgrind --dump-instr=yes --instr-atstart=no ./call cachegrind: valgrind --tool=cachegrind --cache-sim=yes ./cache perf: perf stat -ddd ./cache clean: rm -f call cache *grind.out.*