Przejdź do treści

Perf

logo Linux

Wprowadzenie

Perf (nazywany również perf_events) to podstawowe narzędzie do analizy wydajności w systemie operacyjnym Linux, ściśle powiązane z jądrem tego systemu. Umożliwia profilowanie aplikacji działających na CPU. Wspiera klasyczne procesory o architekturze x86, a także procesory Arm. Pozwala na analizę aplikacji wykorzystujących wielowątkowość. W pewnym stopniu może zostać wykorzystany do analizy aplikacji rozproszonych.

Podstawowym sposobem korzystania jest interfejs wiersza poleceń – komenda perf. Istnieją jednak dodatkowe narzędzia udostępniające interfejs graficzny dla funkcjonalności perf. Perf jest także wykorzystywany przez wiele innych narzędzi do analizy wydajności działających na systemie Linux. Więcej w sekcji Narzędzia.

Działanie perf opiera się o tzw. performance counters, a dokładniej hardware counters, czyli specjalne liczniki wydzielone we współczesnych CPU służące do zliczania różnych zdarzeń dot. pracy procesora. Dzięki nim można uzyskać wgląd w szczegóły niskopoziomowego zachowania procesora i poznać takie dane jak:

  • liczba przetworzonych instrukcji,
  • liczba nieudanych odwołań do pamięci podręcznej (cache misses),
  • liczba błędnych przewidywań rozgałęzień (branch mispredictions),
  • ... i wiele innych.

Perf z powodzeniem może zostać wykorzystany do profilowania aplikacji, które korzystają z wielu wątków (np. poprzez pthreads, standardowe wątki w C++, czy OpenMP) lub tworzą wiele procesów. Dla aplikacji rozproszonych wykorzystujących MPI nie ma dedykowanego wsparcia, ale jest możliwe profilowanie (patrz Profilowanie aplikacji rozproszonych).

Dostępność

Z perf można korzystać we wszystkich systemach opartych o jądro Linux. Aby komenda była dostępna, konieczne jest zainstalowanie przez administratora odpowiednich pakietów systemowych. Wymagane jest również ustawienie odpowiednich uprawnień dla użytkownika (patrz Konfiguracja uprawnień).

Wymagane pakiety

W popularnych dystrybucjach Linuxa perf może być zainstalowany w poniższy sposób.

Ubuntu – pakiety linux-tools

apt install linux-tools-common linux-tools-generic
Może również wystąpić konieczność zainstalowania dodatkowego pakietu linux-tools-<wersja_kernela>-generic.

Debian – pakiet linux-perf
apt install linux-perf
Fedora/RedHat/CentOS – pakiet perf
dnf install perf

Szczegóły

Narzędzie perf dostarcza zestaw komend umożliwiających zbieranie danych o wykonaniu programu oraz ich analizę pod kątem wydajności. Podstawowe komendy to:

  • perf stat – ogólne podsumowanie statystyczne podstawowych metryk dla wykonanego programu,
  • perf record – profiluje aplikację i zapisuje dane na temat jej wykonania,
  • perf report – umożliwia wyświetlanie i przeglądanie wyników profilowania.

Inne użyteczne komendy to:

  • perf annotate – przedstawia wyniki profilowania na poziomie kodu źródłowego,
  • perf diff – porównuje ze sobą wyniki profilowania,
  • perf top – pozwala na profilowanie z podglądem wyników w czasie rzeczywistym.

W sekcji Komendy zarysowano podstawowe możliwości tych poleceń. Warto mieć na uwadze, że funkcjonalność perf nie ogranicza się do nich i dostępnych jest jeszcze więcej poleceń. Pełną listę można wyświetlić za pomocą perf help.

Próbkowanie

Podstawą profilowania przez perf jest tzw. próbkowanie (sampling). Polega ono na sprawdzaniu z określoną częstotliwością jakie operacje (funkcje) wykonuje profilowana aplikacja. Każda próbka zawiera informacje o stosie wywołań funkcji w danej chwili (call stack). Jako wynik otrzymujemy więc tylko statystyczne informacje o czasie spędzonym przez aplikację w danym fragmencie kodu. Dodatkowo dokładność może być jeszcze mniejsza jeśli program, lub wykorzystywane biblioteki, zostały skompilowane z wysokimi poziomami optymalizacji (szczegóły w następnej sekcji).

Wpływ opcji kompilacji

Dla zwiększenia czytelności raportów perf, dla profilowanego oprogramowania zalecana jest kompilacja z włączonymi symbolami debugowania (opcja -g lub --ggdb w kompilatorze GCC oraz Clang). W takim wypadku perf będzie w stanie bardziej skutecznie powiązać zebrane próbki (dot. rejonów pliku binarnego) z nazwami funkcji w kodzie programu oraz prześledzić stos wywołań funkcji. W przypadku kompilacji bez -g warto wziąć pod uwagę użycie opcji -fno-omit-frame-pointer, która też może poprawić czytelność zebranych danych. Oprócz tego symbole debugowania są wymagane do pełnego wykorzystania możliwości perf annotate (gdyż dostarczają informacji która instrukcja dotyczy której linii kodu źródłowego). Kompilacja z -g nie powinna mieć wpływu na wydajność, jednak zwiększa wielkość pliku binarnego.

Z perspektywy optymalizacji interesuje nas poprawa wydajności docelowego programu, czyli programu skompilowanego z wybranymi przez nas flagami optymalizującymi (zazwyczaj -O2 lub -O3). Jednakże czasem profile otrzymane dla takich kodów mogą nie być zbyt czytelne. Wtedy przydatne może okazać się zmniejszenie poziomu optymalizacji do -O0 lub -O1. Jest to spowodowane tym, że w wyższych poziomach optymalizacji kompilator częściej dokonuje wstawiania instrukcji realizujących krótkie funkcje bezpośrednio w miejsca gdzie są one wywoływane (tzw. inlining). Negatywnym skutkiem z punktu widzenia profilowania jest to, że w takim wypadku trudniej powiązać wskazania profilera z konkretnymi fragmentami kodu (pewne funkcje tracą swoją odrębność na poziomie pliku binarnego).

Weryfikowanie zmian w kodzie

Zawsze po wprowadzeniu poprawek w kodzie należy zweryfikować ich wpływ na wydajność programu skompilowanego z docelowymi flagami.

Należy pamiętać, że optymalizacje kompilatora nie wpływają na wydajność programu równomiernie. Może się okazać, że fragment programu, który na niskich poziomach optymalizacji jest wolny w stosunku do pozostałych fragmentów, po zwiększeniu optymalizacji staje się dużo bardziej efektywny. Takie sytuacje sprawiają, że obraz zachowania programu skompilowanego z niższym poziomem optymalizacji niż docelowy może nie przystawać do docelowej wydajności. W przypadku obniżenia poziomu optymalizacji należy więc z pewną ostrożnością wyciągać wnioski z profilu wykonania programu.

Konfiguracja uprawnień

Ze względów bezpieczeństwa perf wymaga podwyższonych uprawnień użytkownika. Dla użytkowników innych niż administrator (root) konieczne jest:

  • posiadanie dodatkowych uprawnień CAP_PERFMON (lub CAP_SYS_PTRACE albo CAP_SYS_ADMIN) przez linuxowy mechanizm capabilities (patrz również man capabilities),
    • w tym wypadku użytkownik powinien należeć do grupy użytkowników, która posiada to uprawnienie;
  • lub konfiguracja opcji kernela perf_event_paranoid na wartość mniejszą niż 2,
    • 1 w przypadku profilowania pojedynczego procesu,
    • 0 lub -1 w przypadku profilowania wielu procesów lub profilowania na poziomie całego systemu operacyjnego.
Sprawdzenie wartości opcji perf_event_paranoid
cat /proc/sys/kernel/perf_event_paranoid
Poziomy uprawnień

Domyślnie, w jądrze linux dostępne są 4 poziomy perf_event_paranoid – im wyższa wartość, tym bardziej są ograniczone możliwości zbierania informacji.

  -1: Allow use of (almost) all events by all users
      Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
>= 0: Disallow raw and ftrace function tracepoint access
>= 1: Disallow CPU event access
>= 2: Disallow kernel profiling
W niektórych dystrybucjach Linuxa można spotkać się z jeszcze bardziej restrykcyjnymi (tj. wyższymi) poziomami perf_event_paranoid. Przykładowo w dystrybucji Ubuntu oraz pochodnych wartość >=4 skutkuje całkowitym wyłączeniem możliwości pomiarowych perf. Podobne działanie występuje w dystrybucji Debian, jednak już od wartości 3.

Przykład ustawienia perf_event_paranoid na wartość 1

Ustawienie do czasu ponownego uruchomienia systemu

sudo sh -c 'echo 1 > /proc/sys/kernel/perf_event_paranoid'
Ustawienie wartości na stałe
sudo sh -c 'echo kernel.perf_event_paranoid=1 >> /etc/sysctl.d/99-perf.conf'

Szczegółowe informacje o zasadach kontroli dostępu do perf można znaleźć w dokumentacji jądra Linuxa – patrz perf events and tool security.

Profilowanie aplikacji rozproszonych

Możliwe jest korzystanie z perf do profilowania aplikacji rozproszonych z użyciem biblioteki MPI. Mechanizm ten nie jest wbudowany w narzędzie dlatego w tym celu trzeba ręcznie użyć dostępnych technik.

Standardową metodą uruchamiania perf w środowisku MPI jest opakowanie testowanej aplikacji w komendę perf record oraz ustawienie dla każdego z procesów unikalnej nazwy pliku z raportem (na przykład zawierającej identyfikator procesu MPI).

Przykład profilowania aplikacji korzystającej z Open MPI

Dla aplikacji MPI uruchamianej poprzez mpirun -n 4 ./example, profilowanie uruchamiamy poprzez wrapper:

mpirun -n 4 ./wrapper.sh
gdzie wrapper.sh uruchamia właściwą aplikację ./example z profilowaniem
#!/bin/bash
perf record -o perf.data.${OMPI_COMM_WORLD_RANK} ./example
Warto zwrócić uwagę, że wrapper odwołuje się do zmiennej OMPI_COMM_WORLD_RANK, która jest ustawiana przez środowisko Open MPI (dla każdego procesu na inną wartość), nie ma więc do niej dostępu na poziomie komendy mpirun.

Należy pamiętać, że w przypadku uruchomienia w ten sposób perf na wielu węzłach obliczeniowych, na wszystkich musi być ustawiona odpowiednia wartość perf_event_paranoid.

Inne przykłady użycia perf z MPI można znaleźć w materiałach:

Jak widać, technika ta sprowadza się do niezależnego zebrania profili dla wszystkich procesów MPI. Każdy z tych profili możemy następnie analizować z osobna. Nie jest to więc najwygodniejsza metoda, ale może pozwolić zlokalizować problemy z wydajnością poszczególnych procesów.

Komendy

Poniżej opisane są szczegóły niektórych komend. Lista wszystkich komend dostępna przez perf help. Informacje o danej komendzie, np. perf record, można wyświetlić poprzez perf help record lub man perf-record.

perf stat

Wyświetla podsumowanie statystyczne zdarzeń zliczanych w czasie wykonania wskazanej aplikacji lub procesu. Domyślnie zlicza tylko podstawowe zdarzenia takie jak liczba wykonanych instrukcji czy instrukcji warunkowych. Oprócz tego, można także wyświetlić podsumowanie dotyczące innych zdarzeń. Lista dostępnych typów zdarzeń może się różnić w zależności od architektury procesora, a ich pełną listę można wyświetlić za pomocą komendy perf list.

Przydatne opcje:

  • perf stat ./example – wykonanie i analiza wskazanego programu
  • perf stat -p <PID> – analiza działającego procesu
  • perf stat -e <event> ./example – umożliwia wskazanie zdarzeń do zliczania

perf stat

przykładowy output komendy perf stat

perf record

Wykonuje profilowanie aplikacji poprzez próbkowanie oraz zapisuje wyniki do pliku o domyślnej nazwie perf.data. Domyślnie, próbkowanie jest wykonywane z częstotliwością tysiąca próbek na sekundę (1000Hz). Możliwe jest także ustawienie innej częstotliwości próbkowanie lub wskazanie zdarzenia, na którego liczniku ma być oparte próbkowanie (na przykład jedna próbka na każde 1000 wykonanych instrukcji.

Standardowe wywołanie tej komendy skutkuje profilowaniem wskazanego programu wraz ze wszystkimi utworzonymi przez niego wątkami i procesami (mimo to zebrane dane trafiają do jednego pliku). Oprócz tego możliwe jest profilowanie działającego już procesu, a także wszystkich procesów działających w ramach systemu.

Przydatne opcje:

  • perf record ./example – wykonanie i zebranie profilu działania wskazanego programu
  • perf record -p <PID> – profilowanie działającego procesu
  • perf record -a – profilowanie wszystkich procesów w systemie (wymaga odpowiednio niskiej wartości perf_event_paranoid, patrz Konfiguracja uprawnień)
  • perf record -g ./example – profilowanie z rejestrowaniem grafu wywołań funkcji; poza informacją o udziale poszczególnych funkcji w wykonaniu programu, rejestrowana jest też informacja o miejscach kodu, w których funkcje są wywoływane
  • perf record -o <nazwa_pliku>) – wskazanie innego niż domyślny pliku wyjściowego
  • perf record -F <częstotliwość> – profilowanie z zadaną częstotliwością próbkowania (domyślnie 1000 Hz)
  • perf record -e <zdarzenie> – profilowanie w oparciu o zdarzenie inne niż cykle zegara procesora; listę dostępnych zdarzeń można sprawdzić poleceniem perf list
  • perf record -e <zdarzenie> -c <liczba_wystąpień> – pozwala na profilowanie z próbkowaniem wykonywanym co określoną liczbę wystąpień zadanego zdarzenia (w przeciwieństwie do domyślnego trybu opartego o częstotliwość próbkowania)
  • perf record -s – profilowanie z osobnymi licznikami dla wątków, ułatwiające przeglądanie wyników w przypadku aplikacji wielowątkowej

perf report

Pozwala na odczyt plików raportu generowanych przez perf record. Umożliwia interaktywne poruszanie się po zawartości raportu z poziomu terminala. Ekran pomocy z listą dostępnych akcji klawiszowych i wskazówkami można wyświetlić klawiszem H. W zależności od wersji perf i opcji wywołania, możliwości poruszania się po raporcie mogą być rozbudowane w różnym stopniu.

perf report

przykład podglądu raportu z drzewem wywołań

Przydatne opcje:

  • perf report – wyświetla raport dla pliku perf.data (znajdującym się w aktualnym katalogu roboczym); raport domyślnie uwzględnia wszystkie śledzone wątki i procesy
  • perf report -i <nazwa_pliku> – raport dla wskazanego pliku z wynikami profilowania
  • perf report --tid <tid> – pokazuje raport profilowania dla wątku o identyfikatorze <tid> (wymaga użycia opcji -s w perf record)
  • perf report -g – prezentuje informacje dotyczące grafu wywołań funkcji i umożliwia nawigację po nim (wymaga użycia analogicznej opcji -g w perf record)

Niektóre z opcji perf report, takie jak -g, w nowszych wersjach jądra Linuxa mogą być dodawane przez perf automatycznie jeśli analizowany raport zawiera wymagane informacje.

perf top

Pozwala na profilowanie i monitorowanie długodziałających programów. Domyślnie (wywołany bez dodatkowych parametrów) wykonuje profilowanie wszystkich procesów w systemie. Za pomocą dodatkowych opcji możliwe jest również uruchomienie monitorowania tylko dla konkretnego procesu lub procesów działających na wybranych rdzeniach procesora. Nawigacja po wynikach jest analogiczna do poruszania się po raporcie w perf report.

perf top

przykład działania perf top dla wszystkich procesów w systemie operacyjnym

Przydatne opcje:

  • perf top – śledzenie wszystkich procesów w systemie lub w przestrzeni użytkownika (w zależności od ustawionego poziomu perf_event_paranoid, patrz Konfiguracja uprawnień)
  • perf top -p <PID> – śledzenie wybranego procesu o podanym PID
  • perf top -g – włącza śledzenie drzewa wywołań

perf annotate

Umożliwia powiązanie wyników profilowania z konkretnymi fragmentami kodu źródłowego. Wymaga, aby analizowany program został skompilowany z włączonymi symbolami debugowania (patrz Wpływ opcji kompilacji). W przeciwnym wypadku adnotacje będę umieszczane tylko w kontekście kodu asemblerowego.

perf annotate

przykład działania perf annotate – widok kodu i instrukcji assemblerowych

Narzędzia

Istnieją zewnętrzne narzędzia ułatwiające pracę z perf. Umożliwiają one przede wszystkim wizualizację oraz łatwiejszą nawigację po zebranych raportach.

  • hotspot – Aplikacja pomyślana jako GUI dla perf. Umożliwia zlecanie profilowania oraz przeglądanie zebranych raportów w trybie graficznym.
  • FlameGraph – Pozwala na wygenerowanie wizualizacji stosu wywołań funkcji w postaci tzw. Flame Graph.

Warto wiedzieć, że perf bardzo często jest wykorzystywany przez inne narzędzia służące do analizy wydajności. Przykładowo niektóre środowiska programistyczne (IDE) używają perf do realizacji wbudowanego profilera (np. CLion). Perf odpowiada także za profilowanie aktywności CPU w narzędziach NVIDIA Nsight. Również Intel VTune Profiler w niektórych sytuacjach korzysta z możliwości perf.

Linki


Ostatnia aktualizacja: 6 grudnia 2023