"Szanowny Panie, Pana program działa, ale niestety wolno. Czy da się go przyspieszyć?" Który programista nie spotkał się z takim stwierdzeniem niech pierwszy rzuci kamień. W prezentacji poruszamy tematykę analizy wydajności programów za pomocą narzędzia DTrace.
2. Agenda
● Niska wydajność, co robić?
● Rozwiązanie: DTrace
● Kilka przykładów z życia wziętych
● Agregacja danych i FlameGraph
● Off-CPU time: co program robi gdy nic nie robi
● Kilka słów o Linuksie
● Pytania i (być może) odpowiedzi
3. Problemy z wydajnością
● Program zajmuje 100% czasu procesora
○ Co jest najbardziej czasochłonną operacją?
○ Która ścieżka kodu wykonywana jest
najczęściej?
● Program nie zajmuje 100% czasu procesora
○ Czemu jest wywłaszczany?
○ Na co czeka (dane?)?
○ Czy są jakieś współdzielone blokady?
4. Narzędzie idealne
● Możliwość śledzenia przebiegu programu (kernel i
userspace)
● Podgląd:
○ stosu wywołań funkcji
○ parametrów funkcji
○ wartości zwracanej
● Statystyka, liczenie ilości zdarzeń, histogramów, min/max
● Śledzenie zmian kontekstu, blokad
● Brak ograniczeń ilości śledzonych miejsc/zdarzeń
● Reagowanie na samodzielnie zdefiniowane zdarzenia
● Brak wpływu na wydajność testowanej aplikacji
● Prosta obsługa, wygodne narzędzia, GUI
5. Rozwiązanie: DTrace
● Pierwsze takie narzędzie, powstało dla systemu
Solaris. Obecnie używane w:
○ FreeBSD
○ Solaris
○ macOS
○ NetBSD
○ Linux (Oracle Linux)
● Narzędzie bazujące na “hook’ach” dynamicznie
instalowanych i usuwanych
● Pozwala dynamicznie śledzić wykonanie wątków
6. DTrace - trzy filary
Podsystem (subsystem)
Obszar, który udostępnia
próbki. Podsystemem może być
np. fbt (kernel, w jego skład
wchodzą “probe’y” jądra),
aplikacja (wtedy próbki dotyczą
funkcji userspace) jak i
biblioteki systemowe.
Próbka (probe)
Zdarzenie, które ma być
przechwycone przez DTrace. Na
przykład:
● wejście do funkcji (entry)
● wyjście z funkcji (return)
● próbka zdefiniowana
przez programistę
Akcja (action)
Zdefiniowana przez użytkownika w
skrypcie czynność, która zostanie
wykonana przy uruchomieniu próbki w
danym podsystemie. Na przykład:
● zliczenie ilości wejść
● wyświetlenie stosu wywołań
● podejrzenie parametrów funkcji
7. Rozwiązanie: DTrace
● Wkompilowanie w kernel (FreeBSD)
options KDTRACE_HOOKS
● Inicjalizacja
#kldload dtraceall
● Wyświetlenie listy probe’ów
#dtrace -l
#dtrace -ln 'pid$target:::entry' -p 633
Przykład
8. Skrypty DTrace
Obsługa probe’a
<provider>:<module>:<p-function>:<p-name>
/ <condition> /
{
… user code
}
Zmienne predefiniowane
pid Process ID
tid Thread ID
timestamp Nanosecond timestamp since boot
execname Process name
arg0, ... Function arguments and return value
errno Last syscall failure error code
probefunc Probe function name (3rd field)
probename Probe name (4th field)
12. Agregacje
Format
@name[ keys ] = aggfunc( args );
name Nazwa agregacji
keys Klucz agregacji
aggfunc Funkcja agregacyjna
Funkcje agregacyjne
count Ilość wystąpień
sum(arg) Sumowanie wartości
avg(arg) Średnia wartość
min(arg) Minimalna wartość
max(arg) Maksymalna wartość
lquantize(arg) Histogram liniowy
quantize(arg) Histogram "power-of-two"
18. Historia pewnego sterownika
● Chory: sterownik karty sieciowej 40G na
48-rdzeniowym SoC ARMv8
● Objawy: Linux potrafi 36Gb/s a FreeBSD
tylko 20Gb/s
● Diagnoza: <przykład z iperf3>
Przykład