2013-08-12 18 views
5

Próbuję zoptymalizować wydajność programu C++ i zmniejszyć jego czas działania. Jednak mam problem z ustaleniem, gdzie jest wąskie gardło.Jak analizować czas działania programu

Komenda czasu pokazuje, że sam program trwa około 5 minut, a około 5 minut czasu procesora użytkownika trwa 4,5 minuty.

Profiler procesora (zarówno profiler gcc, jak i google perftool) pokazuje, że wywołania funkcji zajmują łącznie 60 sekund w czasie procesora. Próbowałem również użyć profilera do próbkowania czasu rzeczywistego zamiast czasu procesora, i to daje mi podobne wyniki.

Profiler I/O (użyłem ioapps) pokazuje również, że I/O zajmuje tylko około 30 sekund czasu działania programu.

Zasadniczo mam nierozliczone 3,5 minuty (największa część czasu działania programu), i uważam, że jest to wąskie gardło.

Czego mi brakowało i jak mogę się dowiedzieć, dokąd zmierza ten czas?

+0

Czy kod jest wielowątkowy? Czy uruchamia inny proces (na przykład 'fork', z lub bez następującego' exec')? –

+0

Czy wypróbowałeś wbudowany system Linux? 'perf record ' następnie 'perf raport'. – DanielKO

+1

Z tym, co nam dałeś, domyślam się, że nie czytasz prawidłowo wyników profilera. Opublikuj wynik gprof/perf/strace (przynajmniej 15 ostatnich linii). – DanielKO

Odpowiedz

6

Jak zasugerował Tiib Tiib, wystarczy przerwać program w debugerze. Sposób, w jaki to robię, polega na uruchomieniu programu, przełączeniu do okna wyjściowego, wpisaniu Ctrl-C, przerwaniu programu, przełączeniu z powrotem do okna GDB, wpisaniu "wątku 1" tak, aby był w kontekście programu głównego, i wpisz "bt", aby zobaczyć ślad stosu.

Teraz spojrzeć na ślad stosu i zrozumieć go, ponieważ podczas gdy dyspozycja na licznik programu jest odpowiedzialny za danego cyklu są wydawane, tak jest każde połączenie na stosie.

Jeśli zrobisz to kilka razy, zobaczysz, która linia odpowiada za wąskie gardło. Jak tylko zobaczysz to na dwóch (2) próbkach, przybiłeś go. Następnie napraw to i zrób to wszystko ponownie, znajdując kolejne wąskie gardło i tak dalej. Możesz łatwo zauważyć, że w ten sposób uzyskujesz ogromne przyspieszenie.

< płomień>

Niektórzy mówią, to jest dokładnie to, co zrobić profilowania, tylko robią to lepiej. To jest to, co słyszysz w salach wykładowych i na blogach, ale tutaj jest umowa: Istnieją sposoby, aby przyspieszyć swój kod, który nie ujawnia się jako "wolne funkcje" lub "gorące ścieżki", na przykład - reorganizacja struktury danych. Każda funkcja wygląda bardziej lub mniej niewinnie, nawet jeśli ma wysoki procent czasu.

Ujawniają się, jeśli użytkownik rzeczywiście patrzy na próbki stosów. Więc problem z dobrymi profilerami nie jest w kolekcji próbek, jest w prezentacji wyników. Statystyki i pomiary nie mogą ci powiedzieć, co ci mówi niewielka ilość próbek, sprawdzonych dokładnie.

Co z problemem małej lub dużej liczby próbek? Nie są lepsze? OK, załóżmy, że masz nieskończoną pętlę, lub jeśli nie jest nieskończona, to po prostu działa znacznie dłużej niż wiesz, że powinno? Czy 1000 próbek stosów okaże się lepsze niż pojedyncza próbka? (Nie) Jeśli spojrzysz na to pod debuggerem, wiesz, że jesteś w pętli, ponieważ zajmuje to w zasadzie 100% czasu. Jest gdzieś na stosie - po prostu skanuj stos, aż go znajdziesz. Nawet jeśli pętla zajmuje tylko 50% lub 20% czasu, jest to prawdopodobieństwo, że każda próbka je zobaczy. Jeśli widzisz coś, czego możesz się pozbyć na zaledwie dwóch próbkach, warto to zrobić. Co zatem kupią 1000 próbek?

Może ktoś myśli: "A więc, jeśli pominiemy jeden lub dwa problemy? Może to wystarczy." Czy to prawda? Załóżmy, że kod ma trzy problemy: P przyjmuje 50% czasu, Q bierze 25%, a R przyjmuje 12,5%. Dobre rzeczy nazywają się A. To pokazuje przyspieszenie, które otrzymasz, jeśli naprawisz jedną z nich, dwie lub wszystkie trzy.

PRPQPQPAPQPAPRPQ original time with avoidable code P, Q, and R all mixed together 
RQQAQARQ   fix P   - 2 x speedup 
PRPPPAPPAPRP  fix Q   - 1.3 x " 
PPQPQPAPQPAPPQ fix R   - 1.14 x " 
RAAR    fix P and Q  - 4 x  " 
QQAQAQ   fix P and R  - 2.7 x " 
PPPPAPPAPP  fix Q and R  - 1.6 x " 
AA    fix P, Q, and R - 8 x speedup 

Czy to wyjaśnia, dlaczego ci, którzy "uciekają" naprawdę bolą? Najlepiej można zrobić, jeśli pominąć, że jest dwa razy tak wolno.

Są łatwe do znalezienia, jeśli pobierzesz próbki. P jest na połowie próbek. Jeśli poprawisz P i zrobisz to ponownie, Q jest na połowie próbek. Po ustaleniu Q, R jest na połowie próbek. Napraw R i masz przyspieszenie 8x. Nie musisz się tam zatrzymywać. Możesz iść dalej, dopóki naprawdę nie znajdziesz niczego do naprawienia.

Im więcej problemów, tym większe potencjalne przyspieszenie, , ale nie można pominąć żadnego. Problem z profilerami (nawet tymi dobrymi) polega na tym, że odmawiając możliwości zobaczenia i zbadania poszczególnych próbek, ukrywają problemy, które trzeba znaleźć. More on all that. For the statistically inclined, here's how it works.

Istnieją dobre profilery. Najlepsze są samplery stosów na ścianie, które zgłaszają procent w poszczególnych liniach, pozwalając na włączanie i wyłączanie samplowania za pomocą skrótu klawiszowego. Zoom (wiki) jest takim profilerem.

Ale nawet popełniają błąd zakładając, że potrzebujesz wielu próbek. Nie, a cena, jaką za nie zapłacisz, nie jest widoczna, więc nie możesz zobaczyć , dlaczego czas jest zużyty, więc nie możesz łatwo stwierdzić, czy jest to konieczne, i nie możesz się pozbyć czegoś, chyba że wiesz, że go nie potrzebujesz. W rezultacie brakuje ci wąskich gardeł, a oni kończą na hamowaniu twojego przyśpieszenia.

</płomień>