Narzędzia do oceny wydajności kodu Narzędzia do oceny wydajności kodu 1/32
Narzędzia do oceny wydajności kodu 2/32 Błędy zarządzania pamięcią Typowe błędy wycieki pamięci niewłaściwe zarządzanie pamięcią przepełnienie bufora niezainicjalizowana pamięć
Narzędzia do oceny wydajności kodu 3/32 Debugery pamięci ang. memory debuggers Odnajdują: wycieki pamięci dostęp do uprzednio zwolnionej pamięci wielokrotne zwalnianie tego samego obszaru pamięci użycie delete zamiast delete[] dla tablic wyjście poza zakres tablicy dostęp do niezainicjalizowanej pamięci zapis lub odczyt wskaźnika NULL
Narzędzia do oceny wydajności kodu 4/32 Przykład programu z błędami (1) Kod źródłowy 1 #i n c l u de <s t d i o. h> 2 i n t main ( i n t argc, char argv ) { 3 const i n t s i z e =100; 4 i n t n, sum=0; 5 i n t A = ( i n t ) m a l l o c ( s i z e o f ( i n t ) s i z e ) ; 6 7 f o r ( n=s i z e ; n>0; n ) 8 A[ n ] = n ; 9 f o r ( n=0; n<s i z e ; n++) 10 sum += A[ n ] ; 11 p r i n t f ( "sum=%d\n", sum ) ; 12 return 0 ; 13 }
Narzędzia do oceny wydajności kodu 5/32 Przykład programu z błędami (2) Narzędzie do sprawdzania pamięci $ valgrind --tool=memcheck --leak-check=full./a.out Komunikaty Valgrinda ==6731== Memcheck, a memory error detector.... ==6731== Invalid write of size 4 ==6731== at 0x40056A: main (main1.c:8) ==6731== Address 0x51791c0 is 0 bytes after a block of size 400 ==6731== at 0x4C2260E: malloc (vg_replace_malloc.c:207) ==6731== by 0x40054A: main (main1.c:5) ==6731==
Narzędzia do oceny wydajności kodu 6/32 Przykład programu z błędami (3) ==6731== Conditional jump or move depends on uninitialised value ==6731== Conditional jump or move depends on uninitialised value ==6731== Use of uninitialised value of size 8 ==6731== at 0x4E69963: (within /lib/libc-2.7.so) ==6731== by 0x4E6C7CB: vfprintf (in /lib/libc-2.7.so) ==6731== by 0x4E73C69: printf (in /lib/libc-2.7.so) ==6731== by 0x4005AE: main (main1.c:11) ==6731== ==6731== at 0x4E6996D: (within /lib/libc-2.7.so) ==6731== by 0x4E6C7CB: vfprintf (in /lib/libc-2.7.so) ==6731== by 0x4E73C69: printf (in /lib/libc-2.7.so) ==6731== by 0x4005AE: main (main1.c:11) ==6731==... ==6731== at 0x4E6BDB1: vfprintf (in /lib/libc-2.7.so) ==6731== by 0x4E73C69: printf (in /lib/libc-2.7.so) ==6731== by 0x4005AE: main (main1.c:11) sum=4950
Narzędzia do oceny wydajności kodu 7/32 Przykład programu z błędami (4) ==6731== ERROR SUMMARY: 12 errors from 6 contexts (suppressed: 8 from 1) ==6731== malloc/free: in use at exit: 400 bytes in 1 blocks. ==6731== malloc/free: 1 allocs, 0 frees, 400 bytes allocated. ==6731== For counts of detected errors, rerun with: -v ==6731== searching for pointers to 1 not-freed blocks. ==6731== checked 76,816 bytes. ==6731== ==6731== ==6731== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==6731== at 0x4C2260E: malloc (vg_replace_malloc.c:207) ==6731== by 0x40054A: main (main1.c:5) ==6731== ==6731== LEAK SUMMARY: ==6731== definitely lost: 400 bytes in 1 blocks. ==6731== possibly lost: 0 bytes in 0 blocks. ==6731== still reachable: 0 bytes in 0 blocks. ==6731== suppressed: 0 bytes in 0 blocks.
Narzędzia do oceny wydajności kodu 8/32 Błędy przydziału/zwolnienia pamięci (1) Kod źródłowy 1 #i n c l u de <s t d i o. h> 2 #i n c l u de < s t d l i b. h> 3 #i n c l u de <s t r i n g. h> 4 i n t main ( i n t argc, char argv [ ] ) { 5 char mystr1=s t r d u p ( "test" ) ; 6 char mystr2=s t r d u p ( "TEST" ) ; 7 mystr1=mystr2 ; 8 9 p r i n t f ( "mystr1=%s\n", mystr1 ) ; 10 f r e e ( mystr1 ) ; 11 12 p r i n t f ( "mystr2=%s\n", mystr2 ) ; 13 f r e e ( mystr2 ) ; 14 return 0 ; 15 }
Narzędzia do oceny wydajności kodu 9/32 Błędy przydziału/zwolnienia pamięci (2) ==6802== Invalid read of size 1 ==6802== at 0x4C22D82: strlen (mc_replace_strmem.c:242) ==6802== by 0x4E6DB88: vfprintf (in /lib/libc-2.7.so) ==6802== by 0x4E73C69: printf (in /lib/libc-2.7.so) ==6802== by 0x4005CD: main (main2.c:12) ==6802== Address 0x5179068 is 0 bytes inside a block of size 5 ==6802== at 0x4C2130F: free (vg_replace_malloc.c:323) ==6802== by 0x4005BA: main (main2.c:10)... mystr2=test ==6802== ==6802== Invalid free() / delete / delete[] ==6802== at 0x4C2130F: free (vg_replace_malloc.c:323) ==6802== by 0x4005D6: main (main2.c:14) ==6802== Address 0x5179068 is 0 bytes inside a block of size 5 ==6802== at 0x4C2130F: free (vg_replace_malloc.c:323) ==6802== by 0x4005BA: main (main2.c:10)
Narzędzia do oceny wydajności kodu 10/32 Błędy przydziału/zwolnienia pamięci (3) ==6802== ERROR SUMMARY: 14 errors from 7 contexts (suppressed: 8 ==6802== malloc/free: in use at exit: 5 bytes in 1 blocks. ==6802== malloc/free: 2 allocs, 2 frees, 10 bytes allocated. ==6802== For counts of detected errors, rerun with: -v ==6802== searching for pointers to 1 not-freed blocks. ==6802== checked 76,816 bytes. ==6802== ==6802== ==6802== 5 bytes in 1 blocks are definitely lost in loss record ==6802== at 0x4C2260E: malloc (vg_replace_malloc.c:207) ==6802== by 0x4EA0D71: strdup (in /lib/libc-2.7.so) ==6802== by 0x400584: main (main2.c:5) ==6802== ==6802== LEAK SUMMARY: ==6802== definitely lost: 5 bytes in 1 blocks. ==6802== possibly lost: 0 bytes in 0 blocks. ==6802== still reachable: 0 bytes in 0 blocks. ==6802== suppressed: 0 bytes in 0 blocks.
Narzędzia do oceny wydajności kodu 11/32 Przesłanki do użycia debugera pamięci Kiedy używać Valgrind Przenoszenie aplikacji na inny system operacyjny Program się zawiesza Pojawiają się tajemnicze błędy Jako element testów regresyjnych Gdy ciężko znaleźć przyczynę błędu: $ valgrind --db-attach=yes./a.out
Narzędzia do oceny wydajności kodu 12/32 Kłopoty z wykorzystaniem programu Valgrind Najczęstsze problemy: Dobry przypadek testowy pokrywający kod Zwiększone wymagania programu Wielowątkowość nie zawsze wspierana Wsparcie dla niestandardowych funkcji obsługi pamięci
Narzędzia do oceny wydajności kodu 13/32 Proste podejście Wykorzystanie top top - 09:57:47 up 20:38, 4 users, load average: 0.00, 0.00, 0.00 Tasks: 122 total, 2 running, 120 sleeping, 0 stopped, 0 zombie Cpu(s): 0.0%us, 0.4%sy, 0.0%ni, 99.6%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 4063444k total, 1221240k used, 2842204k free, 87208k buffers Swap: 4883720k total, 0k used, 4883720k free, 624204k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 6913 rdyja 20 0 43904 39m 324 S 2 1.0 0:00.06 a.out 5043 root 20 0 878m 37m 17m S 1 0.9 0:38.24 Xorg...
Narzędzia do oceny wydajności kodu 14/32 Profiler wykorzystania pamięci (1) Uruchomienie $ valgrind --tool=massif./a.out n 100000 8 Wyniki $ ms_print massif.out.6952
Narzędzia do oceny wydajności kodu 15/32 Profiler wykorzystania pamięci (2) -------------------------------------------------------------------------------- Command:./a.out n 10000 3 Massif arguments: (none) ms_print arguments: massif.out.6952 -------------------------------------------------------------------------------- MB 39.22^ #..#.: : :#. ::, @::.:#: :::@ :@::. ::#:.:::@: :@::..::#:: ::::@: ::@::: :::#:: @::::@::.::@::::, :::#::.@::::@::..:::@::::. @ :::#:: : :@::::@::: ::::@::::. @ :::#:: : ::@::::@:::..::::@::::: @ :::#:: ::.::@::::@:::: :::::@:::::: : @ :::#:: :: :::@::::@::::, ::::::@::::::@ : @ :::#:: ::: :::@::::@::::@ ::::::@::::::@ :: @ :::#:: :::..:::@::::@::::@:.::::::@::::::@. :: @ :::#:: :::: ::::@::::@::::@: :::::::@::::::@: ::: @ :::#:: ::::. ::::@::::@::::@:: ::::::::@::::::@:: ::: @ :::#:: ::::: ::::@::::@::::@::..::::::::@::::::@:: @ ::: @ :::#:: :::::: : ::::@::::@::::@::: :::::::::@::::::@::. @ ::: @ :::#:: :::::: : ::::@::::@::::@:::. ::::::::::@::::::@::: @ ::: @ :::#:: ::::::: : ::::@::::@::::@::::.::::::::::@::::::@:::: 0 +----------------------------------------------------------------------->Mi 0 2.507
Narzędzia do oceny wydajności kodu 16/32 Profiler wykorzystania pamięci (3) Number of snapshots: 76 Detailed snapshots: [3, 8, 12 (peak), 29, 34, 39, 58, 68] -------------------------------------------------------------------------------- n time(i) total(b) useful-heap(b) extra-heap(b) stacks(b) -------------------------------------------------------------------------------- 0 0 0 0 0 0 1 109,978 80,008 80,000 8 0 2 150,929 3,814,648 3,807,360 7,288 0 3 181,889 6,638,200 6,625,408 12,792 0 99.81% (6,625,408B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->98.60% (6,545,408B) 0x4008AE: main (testmalloc.c:53) ->01.21% (80,000B) 0x400887: main (testmalloc.c:47) -------------------------------------------------------------------------------- n time(i) total(b) useful-heap(b) extra-heap(b) stacks(b) -------------------------------------------------------------------------------- 4 227,969 10,840,696 10,819,712 20,984 0 5 274,049 15,043,192 15,014,016 29,176 0 6 320,129 19,245,688 19,208,320 37,368 0 7 366,209 23,448,184 23,402,624 45,560 0 8 397,889 26,337,400 26,286,208 51,192 0 99.81% (26,286,208B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->99.50% (26,206,208B) 0x4008AE: main (testmalloc.c:53) ->00.30% (80,000B) in 1+ places, all below ms_print s threshold (01.00%)
Narzędzia do oceny wydajności kodu 17/32 Nadmierne zużycie pamięci Kroki przeciwdziałania nadmiernemu wykorzystaniu pamięci sprawdzić, czy nie ma wycieków pamięci oszacować (zgrubnie) zapotrzebowanie na pamięć sprawdzić użycie pamięci menedżerem procesów wykorzystać program Massif do odnalezienia obiektów zajmujących najwięcej pamięci
Narzędzia do oceny wydajności kodu 18/32 Analiza wydajności Kroki: przygotować zestaw testów upewnić się, że program działa prawidłowo dla testów użyć prostego narzędzia do mierzenia czasu wykonania odnaleźć przypadek ukazujący wąskie gardło programu użyć ten przypadek testowy w narzędziu profilującym
Narzędzia do oceny wydajności kodu 19/32 Proste metody analizy wydajności Polecenie wbudowane: $ time./mojprogram [arg1...] real 0m16.179s user 0m0.016s sys 0m0.164s Instrukcja time: $ /usr/bin/time./a.out n 10000 8 0.03user 0.14system 0:16.17elapsed 1%CPU (0avgtext+ 0avgdata 0maxresident)k 0inputs+0outputs (0major+80071minor)pagefaults 0swaps
Narzędzia do oceny wydajności kodu 20/32 Problemy przy mierzeniu czasu wykonania Pułapki: zbyt krótki czas wykonania programu operacje wejścia/wyjścia wywołania systemowe brak pamięci skalowanie zegara CPU obciążenie generowane przez inne procesy
Wybór przypadku testowego dla programu Narzędzia do oceny wydajności kodu 21/32
Narzędzia do oceny wydajności kodu 22/32 Działanie profilerów Sposoby zbierania danych próbkowanie sampling pośrednicząco, oprzyrządowaniem instrumentation
Narzędzia do oceny wydajności kodu 23/32 gprof Wykorzystanie kompilacja programu z opcją -pg uruchomienie programu powstaje plik o nazwie gmon.out tworzenie raportu komendą gprof nazwa programu gmon.out
Narzędzia do oceny wydajności kodu 24/32 gprof profil płaski (ang. flat profile) $ gprof a.out gmon.out... Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls us/call us/call name 53.64 2.92 2.92 9900000 0.30 0.53 insert_value 25.71 4.32 1.40 219300000 0.01 0.01 swap 16.13 5.20 0.88 495000000 0.00 0.00 less 2.21 5.32 0.12 100000 1.21 53.24 isort 1.47 5.40 0.08 print_array 1.29 5.47 0.07 main...
Narzędzia do oceny wydajności kodu 25/32 gprof graf wywołań (ang. call graph) Call graph (explanation follows) granularity: each sample hit covers 2 byte(s) for 0.18% of 5.47 index % time self children called name <spontaneous> [1] 98.5 0.07 5.32 main [1] 0.12 5.20 100000/100000 isort [2] ----------------------------------------------- 9900000 isort [2] 0.12 5.20 100000/100000 main [1] [2] 97.2 0.12 5.20 100000+9900000 isort [2] 2.92 2.28 9900000/9900000 insert_value [3] 9900000 isort [2] -----------------------------------------------
Narzędzia do oceny wydajności kodu 26/32 gprof graf wywołań (ang. call graph) 2.92 2.28 9900000/9900000 isort [2] [3] 95.0 2.92 2.28 9900000 insert_value [3] 1.40 0.00 219300000/219300000 swap [4] 0.88 0.00 495000000/495000000 less [5] ----------------------------------------------- 1.40 0.00 219300000/219300000 insert_value [3] [4] 25.6 1.40 0.00 219300000 swap [4] ----------------------------------------------- 0.88 0.00 495000000/495000000 insert_value [3] [5] 16.1 0.88 0.00 495000000 less [5] ----------------------------------------------- <spontaneous> [6] 1.5 0.08 0.00 print_array [6] -----------------------------------------------
Narzędzia do oceny wydajności kodu 27/32 Callgrind Użycie uruchomienie programu w środowisku Valgrind $ valgrind --tool=callgrind./program arg1 arg2 powstaje plik o nazwie: callgrind.out.<id> utworzenie raportu komendą: $ callgrind annotate callgrind.out.<id>
Narzędzia do oceny wydajności kodu 28/32 Efekty działania callgrind -------------------------------------------------------------------------------- Profile data file callgrind.out.7312 (creator: callgrind-3.3.1-debian) -------------------------------------------------------------------------------- I1 cache: D1 cache: L2 cache: Timerange: Basic block 0-25022105 Trigger: Program termination Profiled target:./a.out i 100 1000 (PID 7312, part 1) Events recorded: Ir Events shown: Ir Event sort order: Ir Thresholds: 99 Include dirs: User annotated: Auto-annotation: off
Narzędzia do oceny wydajności kodu 29/32 Efekty działania callgrind -------------------------------------------------------------------------------- Ir -------------------------------------------------------------------------------- 246,862,208 PROGRAM TOTALS -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- Ir file:function 121,053,000 /home/../isort.c:insert_value [/home/../a.out] 67,983,000 /home/../isort.c:swap [/home/../a.out] 54,450,000 /home/../isort.c:less [/home/../a.out] 1,675,000 /home/../isort.c:isort 2 [/home/../a.out]
Narzędzia do oceny wydajności kodu 30/32 Narzędzie gcov Komendy: $ gcc -g -ftest-coverage -fprofile-arcs -pg prog.c $./program $ gcov program.gcda Komunikaty: File isort.c Lines executed:61.19% of 67 isort.c:creating isort.c.gcov
Narzędzia do oceny wydajności kodu 31/32 Wyniki działania gcov $ cat program.c.gcov -: 0:Source:isort.c -: 0:Graph:isort.gcno -: 0:Data:isort.gcda -: 0:Runs:2 -: 0:Programs:1... 2193000: 16:void swap(stype *a, int i, int j) { -: 17: Stype tmp; 2193000: 18: tmp = a[i]; 2193000: 19: a[i] = a[j]; 2193000: 20: a[j] = tmp; 2193000: 21:} -: 22: 4950000: 23:int less(stype a, Stype b) { 4950000: 24: return (a < b)? 1 : 0; -: 25:}
Narzędzia do oceny wydajności kodu 32/32 W wykładzie wykorzystano materiały Thorsten Grötker, Ulrich Holtmann, Holger Keding, Markus Wloka, The Developer s Guide to Debugging, Springer, 2008 John Fusco, Linux. Niezbędnik programisty, Helion, 2009