====== 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.*