Pytanie Jak mogę profilować kod C ++ działający pod Linuksem?


Mam aplikację C ++, działającą na Linuksie, którą właśnie rozwijam. Jak mogę określić, które obszary mojego kodu działają powoli?


1499
2017-12-17 20:29


pochodzenie


Jeśli dostarczysz więcej danych na temat swojego stosu rozwojowego, możesz uzyskać lepsze odpowiedzi. Istnieją profilery firmy Intel i Sun, ale musisz użyć ich kompilatorów. Czy to jest opcja? - Nazgob
Odpowiedzi już udzielono pod następującym linkiem: stackoverflow.com/questions/2497211/... - Kapil Gupta
Większość odpowiedzi jest code profilery. Jednak odwrócenie pierwszeństwa, aliasing pamięci podręcznej, rywalizacja o zasoby itp. Mogą być czynnikami optymalizującymi i wydajnymi. Myślę, że ludzie czytają informacje mój powolny kod. Często zadawane pytania odnoszą się do tego wątku. - artless noise
CppCon 2015: Chandler Carruth "Tuning C ++: Benchmarki, procesory i kompilatory! O mój!" - 865719
Kiedyś używałam pstack losowo, przez większość czasu wypisywano najbardziej typowy stos, w którym program jest najczęściej, co wskazuje na wąskie gardło. - Jose Manuel Gomez Alvarez


Odpowiedzi:


Jeśli Twoim celem jest użycie narzędzia profilującego, użyj jednego z sugerowanych.

Jednakże, jeśli spieszysz się i możesz ręcznie przerwać program w ramach debuggera, gdy jest on subiektywnie wolny, istnieje prosty sposób na znalezienie problemów z wydajnością.

Po prostu zatrzymaj to kilka razy i za każdym razem spójrz na stos wywoławczy. Jeśli jest jakiś kod, który marnuje pewien procent czasu, 20% lub 50% lub cokolwiek, to jest prawdopodobieństwo, że złapiesz to w akcie na każdej próbce. Więc jest to w przybliżeniu procent próbek, na których to zobaczysz. Nie wymaga się wykształconych domysłów. Jeśli masz zgadnąć, na czym polega problem, okaże się, że jest to obalone.

Możesz mieć wiele problemów z wydajnością o różnych rozmiarach. Jeśli wyczyścisz którekolwiek z nich, pozostałe będą miały większy procent i będą łatwiejsze do wykrycia przy kolejnych podaniach. To efekt powiększenia, w połączeniu z wieloma problemami, może prowadzić do naprawdę masywnych czynników przyspieszających.

Zastrzeżenie: Programiści są sceptyczni wobec tej techniki, chyba że sami jej użyli. Powiedzą, że profilery przekazują ci te informacje, ale jest to prawdą tylko wtedy, gdy próbkują całego stosu wywołań, a następnie pozwalają ci zbadać losowy zestaw próbek. (Streszczenia są tam, gdzie utracono wgląd.) Wykresy wywołań nie dają tych samych informacji, ponieważ

  1. nie streszczają się na poziomie instrukcji, oraz
  2. dają mylące podsumowania w obecności rekursji.

Powiedzą też, że działa tylko na programach zabawkowych, kiedy faktycznie działa na każdym programie i wydaje się działać lepiej na większych programach, ponieważ mają one zazwyczaj więcej problemów do znalezienia. Będą twierdzić, że czasami znajduje rzeczy, które nie są problemami, ale jest to prawdą tylko wtedy, gdy coś widzisz pewnego razu. Jeśli widzisz problem na więcej niż jednej próbce, to jest prawdziwy.

P.S. Można to również zrobić w programach wielowątkowych, jeśli istnieje sposób na zbieranie próbek stosu wątków puli wątków w danym momencie, tak jak w Javie.

P.P.S Jako ogólna ogólność, im więcej warstw abstrakcji masz w swoim oprogramowaniu, tym bardziej prawdopodobne jest, że to jest przyczyną problemów z wydajnością (i szansą na przyspieszenie).

Dodano: To może nie być oczywiste, ale technika próbkowania stosów działa równie dobrze w obecności rekurencji. Powodem jest to, że czas, który zostałby zaoszczędzony przez usunięcie instrukcji, jest przybliżony przez ułamek zawierających ją próbek, bez względu na to, ile razy może wystąpić w próbce.

Kolejny zarzut, który często słyszę, to: "Zatrzyma się gdzieś przypadkowo i nie będzie istniał prawdziwy problem". Wynika to z wcześniejszej koncepcji tego, czym jest prawdziwy problem. Kluczową właściwością problemów z wydajnością jest to, że przeciwstawiają się oczekiwaniom. Sampling mówi ci, że coś jest problemem, a twoją pierwszą reakcją jest niedowierzanie. Jest to naturalne, ale możesz być pewien, że znajdzie problem, który jest prawdziwy, i na odwrót.

DODANO: Pozwól mi wyjaśnić Bayesian, jak to działa. Załóżmy, że są jakieś instrukcje I (zadzwoń lub w inny sposób), który jest na stosie wywołań ułamek f czasu (a więc i tak dużo). Dla uproszczenia załóżmy, że nie wiemy co f jest, ale przyjmijmy, że jest to 0,1, 0,2, 0,3, ... 0,9, 1,0, a wcześniejsze prawdopodobieństwo każdej z tych możliwości wynosi 0,1, więc wszystkie te koszty są równie prawdopodobne a priori.

Załóżmy, że pobieramy tylko 2 próbki stosu i widzimy instrukcje I na obu próbkach, wyznaczona obserwacja o=2/2. To daje nam nowe oszacowania częstotliwości f z I, według tego:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&&f=x)  P(o=2/2&&f >= x)  P(f >= x)

0.1    1     1             0.1          0.1            0.25974026
0.1    0.9   0.81          0.081        0.181          0.47012987
0.1    0.8   0.64          0.064        0.245          0.636363636
0.1    0.7   0.49          0.049        0.294          0.763636364
0.1    0.6   0.36          0.036        0.33           0.857142857
0.1    0.5   0.25          0.025        0.355          0.922077922
0.1    0.4   0.16          0.016        0.371          0.963636364
0.1    0.3   0.09          0.009        0.38           0.987012987
0.1    0.2   0.04          0.004        0.384          0.997402597
0.1    0.1   0.01          0.001        0.385          1

                  P(o=2/2) 0.385                

Ostatnia kolumna mówi, że na przykład prawdopodobieństwo, że f > = 0,5 wynosi 92%, w porównaniu z poprzednim założeniem 60%.

Załóżmy, że poprzednie założenia są różne. Załóżmy, że przyjmujemy, że P (f = 0,1) wynosi 0,991 (prawie pewne), a wszystkie inne możliwości są prawie niemożliwe (0,001). Innymi słowy, nasza wcześniejsza pewność jest taka I jest tanie. Następnie otrzymujemy:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&& f=x)  P(o=2/2&&f >= x)  P(f >= x)

0.001  1    1              0.001        0.001          0.072727273
0.001  0.9  0.81           0.00081      0.00181        0.131636364
0.001  0.8  0.64           0.00064      0.00245        0.178181818
0.001  0.7  0.49           0.00049      0.00294        0.213818182
0.001  0.6  0.36           0.00036      0.0033         0.24
0.001  0.5  0.25           0.00025      0.00355        0.258181818
0.001  0.4  0.16           0.00016      0.00371        0.269818182
0.001  0.3  0.09           0.00009      0.0038         0.276363636
0.001  0.2  0.04           0.00004      0.00384        0.279272727
0.991  0.1  0.01           0.00991      0.01375        1

                  P(o=2/2) 0.01375                

Teraz mówi P (f> = 0,5) jest 26%, w porównaniu z poprzednim założeniem 0,6%. Więc Bayes pozwala nam aktualizować nasze oszacowanie prawdopodobnego kosztu I. Jeśli ilość danych jest niewielka, nie mówi nam dokładnie, jaki jest koszt, tylko że jest wystarczająco duży, by warto go było naprawić.

Jeszcze inny sposób patrzenia na to nazywa się Zasada sukcesji. Jeśli rzucisz monetą 2 razy, a pojawią się głowy za każdym razem, co to mówi o prawdopodobnym ważeniu monety? Szanowanym sposobem na odpowiedź jest stwierdzenie, że jest to rozkład Beta, ze średnią wartością (liczba trafień + 1) / (liczba prób + 2) = (2 + 1) / (2 + 2) = 75%.

(Kluczem jest to, że widzimy I więcej niż raz. Jeśli widzimy go tylko raz, to nie mówi nam zbyt wiele poza tym f > 0.)

Tak więc nawet bardzo niewielka liczba próbek może nam powiedzieć wiele o kosztach instrukcji, które widzi. (I zobaczy je z częstotliwością, średnio proporcjonalnie do ich kosztu n pobiera się próbki, oraz f to jest koszt I pojawi się na nf+/-sqrt(nf(1-f)) próbki. Przykład, n=10, f=0.3, to jest 3+/-1.4 próbki.)


DODANO, aby intuicyjnie wyczuć różnicę między pomiarem a losowym próbkowaniem stosu:
Są teraz profilery, które próbkują stosu, nawet w zegar ścienny, ale co wychodzi jest pomiarami (lub gorącą ścieżką lub gorącym punktem, z których "wąskie gardło" może łatwo się ukryć). To, czego ci nie pokazują (i łatwo mogą) to same próbki. A jeśli twoim celem jest odnaleźć wąskie gardło, liczba tych, które musisz zobaczyć, średnio, 2 podzielone przez ułamek czasu, jaki zajmuje. Więc jeśli zajmie to 30% czasu, średnio 2 / .3 = 6,7 próbki pokaże to, a szansa, że ​​20 próbek pokaże to, wynosi 99,2%.

Poniżej przedstawiono różnicę między badaniem pomiarów a badaniem próbek stosów. Wąskim gardłem może być jeden wielki blob, albo wiele małych, nie ma znaczenia.

enter image description here

Pomiar jest poziomy; mówi, jaką część rutynowych procedur czasu bierze. Pobieranie próbek jest pionowe. Jeśli istnieje sposób na uniknięcie tego, co robi cały program w tym momencie, i jeśli widzisz to na drugiej próbce, znalazłeś wąskie gardło. To właśnie robi różnicę - widząc cały powód wydawania czasu, a nie tylko ile.


1194
2018-04-21 04:09



Jest to w zasadzie profiler pobierania próbek dla biednego człowieka, który jest świetny, ale ryzykujesz zbyt małą wielkością próbki, która może dać ci całkowicie fałszywe wyniki. - Crashworks
@Crash: Nie będę debatował nad częścią "biednego człowieka" :-) To prawda, że ​​statystyczna dokładność pomiaru wymaga wielu próbek, ale są dwa sprzeczne cele - pomiar i lokalizacja problemu. Skupiam się na tych ostatnich, dla których potrzebujesz precyzji lokalizacji, a nie precyzji pomiaru. Tak więc na przykład, może istnieć, w połowie stosu, pojedyncze wywołanie funkcji A (); który odpowiada za 50% czasu, ale może być w innej dużej funkcji B, wraz z wieloma innymi wywołaniami do A (), które nie są kosztowne. Dokładne podsumowania czasów funkcjonowania mogą być wskazówką, ale każda inna próbka stosu wskaże problem. - Mike Dunlavey
... świat wydaje się być przekonany, że call-graph, opatrzony adnotacjami z liczbą połączeń i / lub średnim czasem, jest wystarczająco dobry. Nie jest. A smutną częścią jest to, że dla tych, którzy próbują stosu wywołań, najbardziej przydatne informacje są tuż przed nimi, ale wyrzucają je w interesie "statystyk". - Mike Dunlavey
Nie chcę się nie zgadzać z twoją techniką. Najwyraźniej polegam dość mocno na profilerach do pobierania próbek stosu. Po prostu wskazuję, że istnieją pewne narzędzia, które robią to teraz w sposób zautomatyzowany, co jest ważne, gdy nie ma sensu uzyskiwać funkcji od 25% do 15% i trzeba zrzucić ją z 1,2% do 0,6%. - Crashworks
Dziękuję bardzo za ten pomysł. Użyłem go i udało mi się zidentyfikować i złagodzić poważne wąskie gardła o kilka lat świetlnych szybciej niż jakakolwiek inna metoda, którą próbowałem w przeszłości. Przyspieszyłem egzekucję o 60 razy. Drżę na myśl o kodzie debugowania czasu, który rozważałem. - ErikE


Możesz użyć Valgrind z następującymi opcjami

valgrind --tool=callgrind ./(Your binary)

Wygeneruje plik o nazwie callgrind.out.x. Możesz wtedy użyć kcachegrind narzędzie do odczytu tego pliku. Otrzymasz graficzną analizę rzeczy z wynikami, na przykład, ile linii kosztuje ile.


472
2017-12-17 20:34



Valgrind jest świetny, ale należy pamiętać, że jego program będzie działać wolno - neves
Sprawdź również Gprof2Dot za niesamowity alternatywny sposób wizualizacji wyników. ./gprof2dot.py -f callgrind callgrind.out.x | dot -Tsvg -o output.svg - Sebastian
@neves Tak Valgrind nie jest bardzo pomocny jeśli chodzi o szybkość profilowania aplikacji "gstreamer" i "opencv" w czasie rzeczywistym. - enthusiasticgeek
stackoverflow.com/questions/375913/... jest częściowym solutonem dla wydania prędkości. - Tõnu Samuel
@Sebastian: gprof2dot jest teraz tutaj: github.com/jrfonseca/gprof2dot - John Zwinck


Zakładam, że używasz GCC. Standardowym rozwiązaniem byłoby profilowanie za pomocą gprof.

Pamiętaj, aby dodać -pg do kompilacji przed profilowaniem:

cc -o myprog myprog.c utils.c -g -pg

Jeszcze tego nie próbowałem, ale słyszałem dobre rzeczy google-perftools. Zdecydowanie warto spróbować.

Powiązane pytanie tutaj.

Kilka innych powiedzonek, jeśli gprof nie wykonuje twojej pracy: Valgrind, Intel VTune, Słońce DTrace.


296
2017-08-17 11:48



Zgadzam się, że gprof jest aktualnym standardem. Po prostu notatka, Valgrind służy do profilowania wycieków pamięci i innych aspektów związanych z pamięcią programów, a nie do optymalizacji prędkości. - Bill the Lizard
Bill, w pakiecie vaglrind można znaleźć callgrind i masyw. Oba są całkiem przydatne do profilowania aplikacji - dario minonne
@ Bill-the-Lizard: Kilka komentarzy gprof : stackoverflow.com/questions/1777556/alternatives-to-gprof/... - Mike Dunlavey
Zobacz także moje zastrzeżenia do gprof poniżej, stackoverflow.com/a/6540100/823636 - Rob_before_edits
gprof -pg to tylko przybliżenie profilowania callstack. Wstawia wywołania mcount do śledzenia, które funkcje wywołują inne funkcje. Używa standardowego próbkowania na podstawie czasu, uh, czasu. Następnie przypisuje czasy próbkowane w funkcji foo () z powrotem do wywołujących funkcję foo (), w zakresie liczby wywołań. Więc nie rozróżnia połączeń o różnych kosztach. - Krazy Glew


Nowsze jądra (np. Najnowsze wersje jądra systemu Ubuntu) są dostarczane z nowymi narzędziami "perf" (apt-get install linux-tools) ZNANY JAKO perf_events.

Są one dostarczane z klasycznymi profilerami do pobierania próbek (strona podręcznika), a także niesamowite wykres czasu!

Ważne jest to, że te narzędzia mogą być profilowanie systemowe a nie tylko profilowanie procesów - mogą pokazywać interakcję między wątkami, procesami i jądrem oraz umożliwiać zrozumienie zależności między harmonogramami a operacjami we / wy między procesami.

Alt text


216
2018-05-22 21:44



Świetne narzędzie! Czy mimo to mam typowy widok "motyla", który zaczyna się od stylu "main-> func1-> fun2"? Nie mogę tego zrozumieć ... perf report wydaje mi się, że nadaję im nazwy funkcyjne z dzwoniącymi rodzicami ... (więc jest to rodzaj odwróconego widoku motyla) - kizzx2
Czy, może perf pokazać timechart wątku aktywności; z dodanymi informacjami o liczbie procesorów? Chcę zobaczyć, kiedy i który wątek był uruchomiony na każdym procesorze. - osgx
@ kizzx2 - możesz użyć gprof2dot i perf script. Bardzo ładne narzędzie! - dashesy
Nawet nowsze jądra jak 4.13 mają eBPF do profilowania. Widzieć brendangregg.com/blog/2015-05-15/ebpf-one-small-step.html i brendangregg.com/ebpf.html - Andrew Stern
Kolejne miłe wprowadzenie do perf istnieje w archive.li/9r927#selection-767.126-767.271   (Dlaczego bogowie SO zdecydowali się usunąć tę stronę z bazy wiedzy SO jest poza mną ....) - ragerdl


Użyłbym Valgrind i Callgrind jako bazy dla mojego zestawu narzędzi do profilowania. Ważne jest, aby wiedzieć, że Valgrind jest w zasadzie maszyną wirtualną:

(wikipedia) Valgrind jest w istocie wirtualnym   maszyna za pomocą just-in-time (JIT)   techniki kompilacji, w tym   dynamiczna rekompilacja. Nic z   oryginalny program zostanie kiedykolwiek uruchomiony   bezpośrednio na procesorze hosta.   Zamiast tego Valgrind najpierw tłumaczy   program w tymczasową, prostszą formę   o nazwie Reprezentacja pośrednia   (IR), który jest neutralny dla procesora,   Formularz oparty na SSA. Po konwersji   narzędzie (patrz poniżej) jest do zrobienia   Jakiekolwiek transformacje by chciały   na IR, zanim tłumaczy Valgrind   IR z powrotem do kodu maszynowego i pozwala   procesor hosta go uruchomi.

Callgrind to profiler oparty na tym. Główną korzyścią jest to, że nie trzeba uruchamiać aplikacji przez wiele godzin, aby uzyskać wiarygodny wynik. Nawet jedna sekunda biegu jest wystarczająca, aby uzyskać solidne, wiarygodne wyniki, ponieważ Callgrind jest bez sondowania profiler.

Kolejnym narzędziem zbudowanym na Valgrind jest Massif. Używam go do profilowania użycia sterty pamięci. Działa świetnie. To, co robi, to to, że daje migawki użycia pamięci - szczegółowe informacje CO zawiera WHAT procent pamięci i WHO umieścił go tam. Takie informacje są dostępne w różnych momentach uruchamiania aplikacji.


65
2018-06-30 19:30





To jest odpowiedź na Odpowiedź Ggrofa Nazgoba.

Korzystam z Gprof przez ostatnie kilka dni i znalazłem już trzy istotne ograniczenia, z których jeden nie został jeszcze udokumentowany nigdzie indziej (jeszcze):

  1. Nie działa poprawnie w wielowątkowym kodzie, chyba że używasz obejście

  2. Wykres wywołania jest zagmatwany przez wskaźniki funkcji. Przykład: Mam funkcję o nazwie multithread (), która pozwala mi na wielowątkowość określonej funkcji przez określoną tablicę (obie przekazywane jako argumenty). Gprof jednak postrzega wszystkie wywołania funkcji multithread () jako odpowiednik w celu obliczenia czasu spędzanego u dzieci. Ponieważ niektóre funkcje przechodzę do multithread () trwa znacznie dłużej niż inne moje wykresy połączeń są w większości bezużyteczne. (Dla tych, którzy zastanawiają się, czy wątek jest tutaj problemem: nie, funkcja multithread () może opcjonalnie i w tym przypadku uruchomić wszystko sekwencyjnie tylko w wątku wywołującym).

  3. To mówi tutaj że "... liczby dotyczące liczby wywołań pochodzą z liczenia, a nie z próbkowania, są całkowicie dokładne ...". Jednak mój wykres wywoławczy daje mi 5345859132 + 784984078 jako statystyki połączeń do mojej najbardziej zwanej funkcji, gdzie pierwsza liczba ma być bezpośrednią rozmową, a druga rekursywna (która jest sama w sobie). Ponieważ to sugerowało, że mam błąd, włożyłem długie (64-bitowe) liczniki do kodu i wykonałem ten sam cykl ponownie. Moje liczby: 5345859132 bezpośrednie i 78094395406 samokierowne połączenia. Jest tam wiele cyfr, więc wskażę, że rekurencyjne połączenia, które mierzę, wynoszą 78 miliardów, w porównaniu z 784 m od Gprof: współczynnik równy 100. Oba przebiegi były jednozmienne i niezoptymalizowany kod, jeden skompilowany -g i drugi -pg.

To był GNU Gprof (GNU Binutils for Debian) 2.18.0.20080103 działa pod 64-bitowym Debian Lenny, jeśli to pomaga każdemu.


49
2018-06-08 08:01



najwyraźniej może to zrobić próbkowanie stackoverflow.com/a/11143125/32453 - rogerdpack
Tak, wykonuje próbkowanie, ale nie w przypadku liczby połączeń. Co ciekawe, po tym linku ostatecznie doprowadziłem mnie do zaktualizowanej wersji strony podręcznika, do której linkowałem w moim poście, nowego adresu URL: sourceware.org/binutils/docs/gprof/...  Powtarza to cytat w części (iii) mojej odpowiedzi, ale także mówi: "W aplikacjach wielowątkowych lub aplikacjach z pojedynczym gwintem, które łączą się z bibliotekami wielowątkowymi, zliczenia są deterministyczne tylko wtedy, gdy funkcja zliczania jest wątkowo bezpieczna. Uwaga: pamiętaj, że funkcja liczenia mcount w glibc nie jest bezpieczna dla wątków). " - Rob_before_edits
Nie jest dla mnie jasne, czy to wyjaśnia mój wynik w (iii). Mój kod został połączony z -lpthread -lm i zadeklarował zmienną statyczną "pthread_t * thr" i "pthread_mutex_t nextLock = PTHREAD_MUTEX_INITIALIZER", nawet gdy był uruchomiony z pojedynczym wątkiem. Zazwyczaj zakładam, że "powiązanie z wielowątkowymi bibliotekami" oznacza faktycznie korzystanie z tych bibliotek, i to w większym stopniu niż to, ale mogę się mylić! - Rob_before_edits


Odpowiedź na uruchomienie valgrind --tool=callgrind nie jest kompletny bez niektórych opcji. Zwykle nie chcemy profilować 10 minut wolnego czasu uruchamiania w Valgrind i chcieć profilować nasz program, gdy wykonuje on jakieś zadanie.

Więc to jest to, co polecam. Najpierw uruchom program:

valgrind --tool=callgrind --dump-instr=yes -v --instr-atstart=no ./binary > tmp

Teraz kiedy to działa i chcemy rozpocząć profilowanie, powinniśmy uruchomić w innym oknie:

callgrind_control -i on

To włącza profilowanie. Aby wyłączyć tę funkcję i zatrzymać całe zadanie, możemy użyć:

callgrind_control -k

Teraz mamy kilka plików o nazwie callgrind.out. * W bieżącym katalogu. Aby zobaczyć wyniki profilowania, użyj:

kcachegrind callgrind.out.*

Polecam w następnym oknie, aby kliknęło nagłówek kolumny "Self", w przeciwnym razie pokazuje, że "main ()" jest najbardziej czasochłonnym zadaniem. "Self" pokazuje, ile czasu zajęła sama dana funkcja, a nie razem z osobami zależnymi.


47
2018-02-23 21:28



Teraz z jakiegoś powodu pliki callgrind.out. * Zawsze były puste. Wywołanie callgrind_control -d było użyteczne, aby wymusić zrzut danych na dysk. - Tõnu Samuel
nie rozumiem tych instrukcji. Czy to mówisz? podczas działania programu, możemy wykonać callgrind_control w innym oknie do włączania / wyłączania profilowania? wydaje mi się, że lepiej byłoby zaprojektować minimalny program, który zawiera tylko to, co chcesz profilować, a następnie profilować cały program. - dbliss
Żargon. Moje zwykłe konteksty to coś w rodzaju całego MySQL lub PHP lub czegoś podobnego. Często nawet nie wiem, co chcę od siebie oddzielić. - Tõnu Samuel
Lub w moim przypadku mój program faktycznie ładuje grono danych do pamięci podręcznej LRU i nie chcę tego profilu. Wymuszam ładowanie podzbioru pamięci podręcznej podczas uruchamiania i profilowanie kodu przy użyciu tylko tych danych (pozwalając procesorowi OS + zarządzać wykorzystaniem pamięci w pamięci podręcznej). Działa, ale ładowanie tej pamięci podręcznej jest powolne, a procesor intensywny w kodzie, który próbuję profilować w innym kontekście, więc wywołanie wywołuje bardzo zanieczyszczone wyniki. - Code Abominator
jest również CALLGRIND_TOGGLE_COLLECT w celu automatycznego włączania / wyłączania kolekcji; widzieć stackoverflow.com/a/13700817/288875 - Andre Holzner