Profilownie kodu w Pythonie oraz Django

Ostatnio chciałem sprofilować moją aplikacje w Django. Postanowieniem przyjrzeć się tej kwestii. W Pythonie od wersji 2.2 w bibliotece standardowej jest profiler kodu HotShot(High performance logging profiler) Jest on zamiennikiem istniejącego we wcześniejszych wersjach Pythona modułu Profile. Moduł HotShot jest interface'em do modułu _hotshot z C, dzięki temu temu jest dużo szybszy niż stary moduł Profile i daje bardziej precyzyjne wyniki.

Przykład profilowanie dowolnego kodu z pomocą modułu HotShot:

Profilowanie funkcji moja_funkcja:

import hotshot

def moja_funkcja():
    j = 0
    for i in range(1,10000):
        j += i
       
    return j

if __name__ == '__main__':
    prof = hotshot.Profile("mojprofil.prof")
    prof.run("moja_funkcja()")
    prof.close()

Metoda Profile stworzy plik w którym zostaną zapisane statystki profilowania. Można także pomiędzy dowolny kod wstawić gdzie ma zacząć sie profilowanie a gdzie skończyć:

import hotshot

prof = hotshot.Profile("mojprofil.prof")
prof.start()

# ...tutaj kod który ma zostać sprofilowany...

prof.stop()
prof.close()

Drukowanie wyników:

import hotshot.stats

stats = hotshot.stats.load("mojprofil.prof")
stats.strip_dirs()
stats.sort_stats('time', 'calls')
stats.print_stats(20)
2 function calls in 0.004 CPU seconds

   Ordered by: internal time, call count

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.004    0.004    0.004    0.004 profile_test.py:3(moja_funkcja)
        1    0.000    0.000    0.004    0.004 :1()
        0    0.000             0.000          profile:0(profiler)

W zwróconym wyniku mamy następujące parametry:

ncalls
Ilość wywołań funkcji/metody
tottime
Całkowity czas wykonań danej funkcji wykluczając inne pod funkcje.
percall
Czas wykonania pojedynczej funkcji.
cumtime
Całkowity czas wykonania wszystkich funkcji o tej samej nazwie łącznie z innymi pod funkcjami które wywołuje ta funkcja.
percall
Czas wykonania pojedynczej funkcji, wraz z pod funkcjami, które wywołuje ta funkcja.
filename:lineno(function)
nazwa pliku:nr_linii(funkcja)

Tutaj można znaleźć dekorator który umożliwia, oznaczenie danej funkcji czy metody aby była sprofilowana

Wygenerowane wyniki można także zobaczyć w postaci graficznej, potrzebny jest do tego program kcachegrind dostępny pod linux'em. Nie znalazłem jakiegoś odpowiednika pod Windows'a, podobno można go uruchomić pod Windows'em z pomocą Cygwina, ale nie sprawdzałem bo używam Ubuntu, zarówno w pracy jak i w domu. Aby zobaczyć graficzne wyniki profilowania trzeba je skonwertować do formatu obsługiwanego przez kcachegrind. Potrzebny do tego jest pakiet kcachegrind-converters. Po zainstalowaniu pakietu wykonujemy polecenie hotshot2calltree nasz_plik_z_profilem > cachegrind.out.01.

Jeżeli chodzi profilowanie Django to istnieje kilka możliwości. Django posiada hander django.core.handlers.profiler-hotshot który umożliwia profilowanie widoków gdy używa się mod_pythona, druga możliwość to uruchomienie django przez serwer WSGI. Dokładny opis można znaleźć tutaj. Najbardziej ciekawy i elegancki sposób jaki znalazłem to profilowanie django za pomocą middleware'a dostępnego tutaj. Wystarczy dopisać go na początek listy middlewre'ów naszej aplikacji w settings.py. Aby z profilować dowolny widok wystarczy dopisać na koniec url'a ?prof. Np. http://mojadomena.com/mojwidok/?prof. Po wywołaniu takiego widoku na ekranie otrzymamy statystyki profilowania.


Comments turned off