Профилирование и отладка Django

131
Профилирование и отладка Django Владимир Рудных

description

При написании программы, разработчик примерно представляет себе, как должна работать его программа. Но не всегда его ожидания соответствуют действительности — приложения тормозят, потребляют много ресурсов и вообще ведут себя не так, как задумывалось, особенно под большой нагрузкой. В своём докладе я покажу, как заглянуть "под капот" ваших приложений на Python (и Django в частности): какие способы профилирования бывают и когда их можно использовать, расскажу об отладке приложений и различных инструментах, которые помогают разработчику при разработке.

Transcript of Профилирование и отладка Django

Page 1: Профилирование и отладка Django

Профилирование и отладкаDjango

Владимир Рудных

Page 2: Профилирование и отладка Django

Moscow Django MeetUp №13

Обо мне

• технический руководитель Календаря Mail.Ru

• pythonista

• бывший перловик

• ленивый программист

Page 3: Профилирование и отладка Django

Moscow Django MeetUp №13

Cбор характеристик работы программы

с целью их дальнейшей оптимизации.

Профилирование

Page 4: Профилирование и отладка Django

Moscow Django MeetUp №13

Что собираем?

• время выполнения строк кода

• количество вызовов функций

• время выполнения функций

• дерево вызовов функций

• “hot spots”

• загрузку CPU, использование памяти

• и т.д.

Page 5: Профилирование и отладка Django

Moscow Django MeetUp №13

Project Euler

http://projecteuler.net

Тренируемся

Page 6: Профилирование и отладка Django

Moscow Django MeetUp №13

Простые делители числа 13195 — это 5, 7, 13 и 29.

Какой самый большой делитель числа 600851475143,

являющийся простым числом?

Project Euler: задача 3

Page 7: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 3 4 def is_prime(num): 5 """Checks if num is prime number""" 6 for i in range(2, num): 7 if not num % i: 8 return False 9 return True 10 11 12 def prime_factors(num): 13 """Find prime factors of num""" 14 result = [] 15 for i in range(2, num): 16 if is_prime(i) and not num % i: 17 result.append(i) 18 return result 19 20 21 if __name__ == '__main__': 22 print "Answer: %d" % prime_factors(600851475143)[-1]

Project Euler: задача 3

Page 8: Профилирование и отладка Django

Moscow Django MeetUp №13

Page 9: Профилирование и отладка Django

Moscow Django MeetUp №13

Page 10: Профилирование и отладка Django

Moscow Django MeetUp №13

Профилирование начинается в голове.

Инструменты — всего лишь инструменты.

Искусство профилирования

Page 11: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 from math import sqrt 3 4 5 def is_prime(num): 6 """Checks if num is prime number""" 7 for i in range(2, int(sqrt(num)) + 1): 8 if not num % i: 9 return False 10 return True 11 12 13 def prime_factors(num): 14 """Find prime factors of num""" 15 result = [] 16 for i in range(2, int(sqrt(num)) + 1): 17 if is_prime(i) and not num % i: 18 result.append(i) 19 return result 20 21 22 if __name__ == '__main__': 23 print "Answer: %d" % prime_factors(600851475143)[-1]

Project Euler: задача 3

Page 12: Профилирование и отладка Django

Moscow Django MeetUp №13

Подходы к профилированию

• ручное профилирование

• с помощью инструментов

Page 13: Профилирование и отладка Django

Moscow Django MeetUp №13

Ручное профилирование

Page 14: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ time python max_prime_factor.py Answer: 6857 python max_prime_factor.py 20,00s user 0,19s system 82% cpu 24,445 total

Ручное профилирование

Page 15: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 import time 3 from math import sqrt 4 5 6 def is_prime(num): 7 """Checks if num is prime number""" 8 for i in range(2, int(sqrt(num)) + 1): 9 if not num % i: 10 return False 11 return True 12 13 14 def prime_factors(num): 15 """Find prime factors of num""" 16 result = [] 17 for i in range(2, int(sqrt(num)) + 1): 18 if is_prime(i) and not num % i: 19 result.append(i) 20 return result 21 22 23 if __name__ == '__main__': 24 start = time.time() 25 print "Answer: %d" % prime_factors(600851475143)[-1] 26 print "Time: %f s" % (time.time() - start)

Ручное профилирование

Page 16: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python max_prime_factor.py Answer: 6857 Time: 23.531779 s

Ручное профилирование

Page 17: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python max_prime_factor.py Answer: 6857 Time: 21.143574 s

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python max_prime_factor.py Answer: 6857 Time: 22.638407 s

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python max_prime_factor.py Answer: 6857 Time: 20.774542 s

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python max_prime_factor.py Answer: 6857 Time: 22.272329 s

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python max_prime_factor.py Answer: 6857 Time: 23.562760 s

Ручное профилирование

Page 18: Профилирование и отладка Django

Moscow Django MeetUp №13

timeit

http://docs.python.org/2/library/timeit.html

Ручное профилирование

Page 19: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m timeit -n 10 -s'from max_prime_factor import prime_factors' 'prime_factors(600851475143)'10 loops, best of 3: 22.3 sec per loop

timeit

Page 20: Профилирование и отладка Django

Moscow Django MeetUp №13

Ручное профилированиеочень простое применение

ограниченно подходит для продакшена

вставка чужеродного кода в проектникакой информации о коде (кроме времени выполнения)анализ результатов может быть затруднительным

Page 21: Профилирование и отладка Django

Moscow Django MeetUp №13

— Зацени, мой код быстрее твоего!

Применение

Page 22: Профилирование и отладка Django

Moscow Django MeetUp №13

Применение

Page 23: Профилирование и отладка Django

Moscow Django MeetUp №13

Сбор статистики времени выполнения кода.

Например, в graphite или statsd:

Применение в реальной жизни

Page 24: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Collect profiling statistic into graphite""" 2 import socket 3 import time 4 5 6 CARBON_SERVER = '127.0.0.1' 7 CARBON_PORT = 2003 8 9 10 class Stats(object): 11 """Context manager for send stats to graphite""" 12 13 def __init__(self, name): 14 self.name = name 15 16 def __enter__(self): 17 self.start = time.time() 18 return self 19 20 def __exit__(self, *args): 21 duration = (time.time() - self.start) * 1000 # msec 22 message = '%s %d %d\n' % (self.name, duration, time.time()) 23 24 sock = socket.socket() 25 sock.connect((CARBON_SERVER, CARBON_PORT)) 26 sock.sendall(message) 27 sock.close()

Менеджер контекста

Page 25: Профилирование и отладка Django

Moscow Django MeetUp №13

from django.core.mail import send_mailfrom profiling.context_managers import Stats

...

with Stats('django_project.profiling.send_email'): send_mail( 'Subject here', 'Here is the message.', '[email protected]', ['[email protected]'], fail_silently=False )

Пример использования

Page 26: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Collect profiling statistic into graphite""" 2 import socket 3 import time 4 5 6 CARBON_SERVER = '127.0.0.1' 7 CARBON_PORT = 2003 8 9 10 def stats(name): 11 """Decorator for send stats to graphite""" 12 def _timing(func): 13 def _wrapper(*args, **kwargs): 14 start = time.time() 15 result = func(*args, **kwargs) 16 duration = (time.time() - start) * 1000 # msec 17 message = '%s %d %d\n' % (name, duration, time.time()) 18 19 sock = socket.socket() 20 sock.connect((CARBON_SERVER, CARBON_PORT)) 21 sock.sendall(message) 22 sock.close() 23 24 return result 25 return _wrapper 26 return _timing

Декоратор

Page 27: Профилирование и отладка Django

Moscow Django MeetUp №13

from django.db import modelsfrom profiling.decorator import stats

...

class Model(model.Model):

...

@stats('django_project.profiling.application.save') def save(self, *args, **kwargs):

# do some hard work like thumbnail generation

super(Model, self).save(*args, **kwargs)

Пример использования

Page 28: Профилирование и отладка Django

Moscow Django MeetUp №13

Статистика профилирования

Page 29: Профилирование и отладка Django

Moscow Django MeetUp №13

Профилирование

с помощью инструментов

Page 30: Профилирование и отладка Django

Moscow Django MeetUp №13

Инструменты для профилирования

•Deterministic (event-based)

•Statistical

Page 31: Профилирование и отладка Django

Moscow Django MeetUp №13

def is_prime(num): """Checks if num is prime number""" for i in range(2, num): if not num % i: return False return True

Deterministic profilers

@profiledef is_prime(num): """Checks if num is prime number""" for i in range(2, num): if not num % i: return False return True

Page 32: Профилирование и отладка Django

Moscow Django MeetUp №13

def is_prime(num): """Checks if num is prime number""" with profile(): for i in range(2, num): if not num % i: return False return True

Deterministic profilers

def is_prime(num): """Checks if num is prime number""" profile.start() for i in range(2, num): if not num % i: return False profile.stop() return True

Page 33: Профилирование и отладка Django

Moscow Django MeetUp №13

Deterministic profilers

def foo()

def bar()

def baz() def ololo()

Page 34: Профилирование и отладка Django

Moscow Django MeetUp №13

Deterministic profilers

вся информация о коде

множество инструментов для анализа

очень медленно

непригодно для продакшена (или крайне ограниченно)

Page 35: Профилирование и отладка Django

Moscow Django MeetUp №13

Statistical profilers

def foo() def bar() def baz()

def foo() def bar() def baz()

Timer: 1ms

Timer: 10ms

Page 36: Профилирование и отладка Django

Moscow Django MeetUp №13

Statistical profilers

def foo() def foo() def foo() def foo()def foo()

def foo()

Page 37: Профилирование и отладка Django

Moscow Django MeetUp №13

Statistical profilers

можно пускать в продакшн (практически не влияет на быстродействие)

не вся информация о коде

мало инструментов для анализа

Page 38: Профилирование и отладка Django

Moscow Django MeetUp №13

Deterministic profilers

• profile

• cProfile

• hotshot

• kcachegrind

• RunSnakeRun

• gprof2dot

• pycallgraph

• line_profiler

• memory_profiler

• dowser

• guppy

• muppy

• memprof

• objgraph

“тысячи их”...

Page 39: Профилирование и отладка Django

Moscow Django MeetUp №13

cProfile

http://docs.python.org/2/library/profile.html

Инструменты для профилирования

Page 40: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m cProfile -s time max_prime_factor.pyAnswer: 6857

2325444 function calls in 21.912 seconds

Ordered by: internal time

ncalls tottime percall cumtime percall filename:lineno(function) 775145 14.240 0.000 21.233 0.000 max_prime_factor.py:5(is_prime) 775146 6.779 0.000 6.779 0.000 {range} 1 0.630 0.630 21.909 21.909 max_prime_factor.py:13(prime_factors) 775146 0.260 0.000 0.260 0.000 {math.sqrt} 1 0.003 0.003 21.912 21.912 max_prime_factor.py:1(<module>) 4 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

cProfile

Page 41: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 from math import sqrt 3 4 5 def is_prime(num): 6 """Checks if num is prime number""" 7 for i in range(2, int(sqrt(num)) + 1): 8 if not num % i: 9 return False 10 return True 11 12 13 def prime_factors(num): 14 """Find prime factors of num""" 15 result = [] 16 for i in range(2, int(sqrt(num)) + 1): 17 if is_prime(i) and not num % i: 18 result.append(i) 19 return result 20 21 22 if __name__ == '__main__': 23 print "Answer: %d" % prime_factors(600851475143)[-1]

Project Euler: задача 3

Page 42: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 from math import sqrt 3 4 5 def is_prime(num): 6 """Checks if num is prime number""" 7 for i in range(2, int(sqrt(num)) + 1): 8 if not num % i: 9 return False 10 return True 11 12 13 def prime_factors(num): 14 """Find prime factors of num""" 15 result = [] 16 for i in range(2, int(sqrt(num)) + 1): 17 if not num % i and is_prime(i): 18 result.append(i) 19 return result 20 21 22 if __name__ == '__main__': 23 print "Answer: %d" % prime_factors(600851475143)[-1]

Project Euler: задача 3

Page 43: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m cProfile -s time max_prime_factor.pyAnswer: 6857

30 function calls in 0.225 seconds

Ordered by: internal time

ncalls tottime percall cumtime percall filename:lineno(function) 1 0.179 0.179 0.250 0.250 max_prime_factor.py:13(prime_factors) 8 0.070 0.009 0.070 0.009 {range} 1 0.003 0.003 0.253 0.253 max_prime_factor.py:1(<module>) 7 0.000 0.000 0.000 0.000 max_prime_factor.py:5(is_prime) 8 0.000 0.000 0.000 0.000 {math.sqrt} 4 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

cProfile

Page 44: Профилирование и отладка Django

Moscow Django MeetUp №13

Ускорил код в сто раз

Page 45: Профилирование и отладка Django

Moscow Django MeetUp №13

import cProfile

def profile(func): """Decorator for run function profile""" def wrapper(*args, **kwargs): profile_filename = func.__name__ + '.profile' profiler = cProfile.Profile() result = profiler.runcall(func, *args, **kwargs) profiler.dump_stats(profile_filename) return result

return wrapper

@profiledef foo(): ...

cProfile: декоратор

Page 46: Профилирование и отладка Django

Moscow Django MeetUp №13

hotshot

http://docs.python.org/2/library/hotshot.html

Инструменты для профилирования

Page 47: Профилирование и отладка Django

Moscow Django MeetUp №13

import hotshot

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

# your code goes here

prof.stop()prof.close()

hotshot: использование

Page 48: Профилирование и отладка Django

Moscow Django MeetUp №13

import hotshot

def profile(func): """Decorator for run function profile""" def wrapper(*args, **kwargs): profile_filename = func.__name__ + '.profile' profiler = hotshot.Profile(profile_filename) profiler.start() result = func(*args, **kwargs) profiler.stop() profiler.close() return result

return wrapper

@profiledef foo(): ...

hotshot: декоратор

Page 49: Профилирование и отладка Django

Moscow Django MeetUp №13

cProfile, hotshot

мощные инструменты

достаточно простые

дерево вызовов функций

сильно влияют на производительностьанализ результатов может быть затруднительным

Page 50: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ time python max_prime_factor.pyAnswer: 6857python max_prime_factor.py 0,18s user 0,01s system 95% cpu 0,199 total

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ time python -m cProfile max_prime_factor.pyAnswer: 6857

22 function calls in 0.252 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function) 1 0.005 0.005 0.252 0.252 max_prime_factor.py:1(<module>) 1 0.247 0.247 0.247 0.247 max_prime_factor.py:13(prime_factors) 7 0.000 0.000 0.000 0.000 max_prime_factor.py:5(is_prime) 8 0.000 0.000 0.000 0.000 {math.sqrt} 4 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

python -m cProfile max_prime_factor.py 0,23s user 0,09s system 58% cpu 0,541 total

cProfile: производительность

Page 51: Профилирование и отладка Django

Moscow Django MeetUp №13

Сохраняем результаты профилирования в файл для дальнейшего анализа:

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ python -m cProfile -o max_prime_factor.prof max_prime_factor.py Answer: 6857

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ ls max_prime_factor.prof max_prime_factor.py

cProfile: анализ результатов

Page 52: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ ipython

In [1]: import pstats

In [2]: p = pstats.Stats('max_prime_factor.prof')

In [3]: p.sort_stats('calls')Out[3]: <pstats.Stats instance at 0x10689bf80>

In [4]: p.print_stats(5)

22 function calls in 0.166 seconds

Ordered by: call count List reduced from 6 to 5 due to restriction <5>

ncalls tottime percall cumtime percall filename:lineno(function) 8 0.000 0.000 0.000 0.000 {math.sqrt} 7 0.000 0.000 0.000 0.000 max_prime_factor.py:5(is_prime) 4 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects} 1 0.003 0.003 0.166 0.166 max_prime_factor.py:1(<module>) 1 0.163 0.163 0.163 0.163 max_prime_factor.py:13(prime_factors)

Out[4]: <pstats.Stats instance at 0x10689bf80>

Анализ: pstats

Page 53: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install pyprof2calltree

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pyprof2calltree -i max_prime_factor.prof -o max_prime_factor.kgrind

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pyprof2calltree -i max_prime_factor.prof -k

Анализ: kcachegrind

Page 54: Профилирование и отладка Django

Moscow Django MeetUp №13

Анализ: kcachegrind

Page 55: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ brew install wxwidgets

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install SquareMap RunSnakeRun

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ runsnake max_prime_factor.prof

Анализ: RunSnakeRun

Page 56: Профилирование и отладка Django

Moscow Django MeetUp №13

Анализ: RunSnakeRun

Page 57: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ brew install graphviz

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install gprof2dot

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ gprof2dot -f pstats max_prime_factor.prof | dot -Tpng -o max_prime_factor.png

Анализ: gprof2dot

Page 58: Профилирование и отладка Django

Moscow Django MeetUp №13

Анализ: gprof2dot

Page 59: Профилирование и отладка Django

Moscow Django MeetUp №13

Но где же Django?

Page 60: Профилирование и отладка Django

Moscow Django MeetUp №13

Профилируем Django• Устанавливаем модуль:

➜ pip install django-extensions

• Добавляем application в Django:INSTALLED_APPS += ('django_extensions',)

• Запускаем тестовый сервер:➜ python manage.py runprofileserver \ --use-cprofile \ --prof-path=/tmp/prof/

Page 61: Профилирование и отладка Django

Moscow Django MeetUp №13

Получаем по одному *.prof файлу на запрос:rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ ls /tmp/prof/admin.000276ms.1374075009.profadmin.account.user.000278ms.1374075014.profadmin.jsi18n.000185ms.1374075018.proffavicon.ico.000017ms.1374075001.profroot.000073ms.1374075004.profstatic.admin.css.base.css.000011ms.1374075010.profstatic.admin.css.forms.css.000013ms.1374075017.profstatic.admin.img.icon-yes.gif.000001ms.1374075015.profstatic.admin.img.sorting-icons.gif.000001ms.1374075015.profstatic.admin.js.core.js.000018ms.1374075014.profstatic.admin.js.jquery.js.000003ms.1374075014.profstatic.css.bootstrap-2.3.2.min.css.000061ms.1374074996.profstatic.img.glyphicons-halflings.png.000001ms.1374075005.profstatic.js.bootstrap-2.3.2.min.js.000004ms.1374074996.profstatic.js.jquery-2.0.2.min.js.000001ms.1374074996.profuser.login.000187ms.1374075001.prof

А дальшё всё как обычно:

Профилируем Django

Page 62: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ ipython

In [1]: import pstats

In [2]: p = pstats.Stats('/tmp/prof/user.login.000187ms.1374075001.prof')

In [3]: p.sort_stats('calls')Out[3]: <pstats.Stats instance at 0x107efa5f0>

In [4]: p.print_stats(5)

36854 function calls (35710 primitive calls) in 0.187 seconds

Ordered by: call count List reduced from 774 to 5 due to restriction <5>

ncalls tottime percall cumtime percall filename:lineno(function) 4714 0.002 0.000 0.002 0.000 {method 'append' of 'list' objects} 3562 0.003 0.000 0.003 0.000 {isinstance} 2456 0.003 0.000 0.003 0.000 {method 'startswith' of 'unicode' objects}1058/1048 0.002 0.000 0.002 0.000 {getattr} 979/962 0.000 0.000 0.025 0.000 {len}

Out[4]: <pstats.Stats instance at 0x107efa5f0>

Анализ: pstats

Page 63: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pyprof2calltree -i /tmp/prof/user.login.000187ms.1374075001.prof -k

Анализ: kcachegrind

Page 64: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ runsnake /tmp/prof/user.login.000187ms.1374075001.prof

Анализ: RunSnakeRun

Page 65: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ gprof2dot -f pstats /tmp/prof/user.login.000187ms.1374075001.prof | dot -Tpng -o login.png

Анализ: gprof2dot

Page 66: Профилирование и отладка Django

Moscow Django MeetUp №13

Ещё инструменты

Page 67: Профилирование и отладка Django

Moscow Django MeetUp №13

pycallgraph

http://pycallgraph.slowchop.com/

Инструменты для профилирования

Page 68: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install pycallgraph

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pycallgraph max_prime_factor.pyPython Call Graph v0.5.1Starting traceAnswer: 6857Creating pycallgraph.pngDone!

pycallgraph

Page 69: Профилирование и отладка Django

Moscow Django MeetUp №13

import pycallgraph

pycallgraph.start_trace()

# your code goes here

pycallgraph.make_dot_graph('call-graph.png')

pycallgraph

Page 70: Профилирование и отладка Django

Moscow Django MeetUp №13

line_profiler

https://bitbucket.org/robertkern/line_profiler

Инструменты для профилирования

Page 71: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ kernprof.py -v -l max_prime_factor.py

Function: is_prime at line 5Total time: 0.001412 s

Line # Hits Time Per Hit % Time Line Contents============================================================== 6 def is_prime(num): 7 """Checks if num is prime number""" 8 366 767 2.1 54.3 for i in range(2, int(sqrt(num)) + 1): 9 362 614 1.7 43.5 if not num % i: 10 3 23 7.7 1.6 return False 11 4 8 2.0 0.6 return True

Function: prime_factors at line 14Total time: 2.67703 s

Line # Hits Time Per Hit % Time Line Contents============================================================== 15 def prime_factors(num): 16 """Find prime factors of num""" 17 1 4 4.0 0.0 result = [] 18 775146 1320370 1.7 49.3 for i in range(2, int(sqrt(num)) + 1): 19 775145 1356632 1.8 50.7 if not num % i and is_prime(i): 20 4 16 4.0 0.0 result.append(i) 21 1 10 10.0 0.0 return result

line_profiler

Page 72: Профилирование и отладка Django

Moscow Django MeetUp №13

memory_profiler

https://github.com/fabianp/memory_profiler

Инструменты для профилирования

Page 73: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m memory_profiler max_prime_factor.py

Line # Mem usage Increment Line Contents================================================ 6 def is_prime(num): 7 32.469 MB 0.000 MB """Checks if num is prime number""" 8 57.414 MB 24.945 MB for i in range(2, int(sqrt(num)) + 1): 9 57.414 MB 0.000 MB if not num % i: 10 32.566 MB -24.848 MB return False 11 33.047 MB 0.480 MB return True

Line # Mem usage Increment Line Contents================================================ 15 def prime_factors(num): 16 8.379 MB 0.000 MB """Find prime factors of num""" 17 8.379 MB 0.000 MB result = [] 18 75.332 MB 66.953 MB for i in range(2, int(sqrt(num)) + 1): 19 33.047 MB -42.285 MB if not num % i and is_prime(i): 20 75.332 MB 42.285 MB result.append(i) 21 75.332 MB 0.000 MB return result

memory_profiler

Page 74: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 from math import sqrt 3 4 5 def is_prime(num): 6 """Checks if num is prime number""" 7 for i in xrange(2, int(sqrt(num)) + 1): 8 if not num % i: 9 return False 10 return True 11 12 13 def prime_factors(num): 14 """Find prime factors of num""" 15 result = [] 16 for i in xrange(2, int(sqrt(num)) + 1): 17 if not num % i and is_prime(i): 18 result.append(i) 19 return result 20 21 22 if __name__ == '__main__': 23 print "Answer: %d" % prime_factors(600851475143)[-1]

Project Euler: задача 3

Page 75: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m memory_profiler max_prime_factor.py

Line # Mem usage Increment Line Contents================================================ 6 def is_prime(num): 7 8.391 MB 0.000 MB """Checks if num is prime number""" 8 22.605 MB 14.215 MB for i in xrange(2, int(sqrt(num)) + 1): 9 22.605 MB 0.000 MB if not num % i: 10 8.484 MB -14.121 MB return False 11 8.965 MB 0.480 MB return True

Line # Mem usage Increment Line Contents================================================ 15 def prime_factors(num): 16 8.379 MB 0.000 MB """Find prime factors of num""" 17 8.379 MB 0.000 MB result = [] 18 34.141 MB 25.762 MB for i in xrange(2, int(sqrt(num)) + 1): 19 8.965 MB -25.176 MB if not num % i and is_prime(i): 20 34.141 MB 25.176 MB result.append(i) 21 34.141 MB 0.000 MB return result

memory_profiler

Page 76: Профилирование и отладка Django

Moscow Django MeetUp №13

И ещё инструменты

Page 77: Профилирование и отладка Django

Moscow Django MeetUp №13

Профилирование памяти

Dowser

http://www.aminus.net/wiki/Dowser

Инструменты для профилирования

Page 78: Профилирование и отладка Django

Moscow Django MeetUp №13

Профилирование памяти

guppy

http://guppy-pe.sourceforge.net/

Инструменты для профилирования

Page 79: Профилирование и отладка Django

Moscow Django MeetUp №13

Обнаружение утечек памяти

muppy

http://pythonhosted.org/Pympler/muppy.html

Инструменты для профилирования

Page 80: Профилирование и отладка Django

Moscow Django MeetUp №13

Профилирование памяти

memprof

http://jmdana.github.io/memprof/

Инструменты для профилирования

Page 81: Профилирование и отладка Django

Moscow Django MeetUp №13

Исследование объектов

objgraph

http://mg.pov.lt/objgraph/

Инструменты для профилирования

Page 82: Профилирование и отладка Django

Moscow Django MeetUp №13

Statistical profilers

• StatProf

• Plop

• New Relic

Page 83: Профилирование и отладка Django

Moscow Django MeetUp №13

statprof

https://github.com/bos/statprof.py

Инструменты для профилирования

Page 84: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install statprof

import statprof

statprof.start()try: function()finally: statprof.stop() statprof.display()

import statprof

with statprof.profile(): function()

statprof

Page 85: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ time python max_prime_factor.pyAnswer: 6857python max_prime_factor.py 10,42s user 0,04s system 97% cpu 10,750 total

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ time python max_prime_factor.pyAnswer: 6857

% cumulative self time seconds seconds name 83.03 8.82 8.82 max_prime_factor.py:9:is_prime 13.52 1.44 1.44 max_prime_factor.py:8:is_prime 2.01 10.62 0.21 max_prime_factor.py:18:prime_factors 0.88 0.09 0.09 max_prime_factor.py:6:is_prime 0.48 0.05 0.05 max_prime_factor.py:10:is_prime 0.06 0.01 0.01 max_prime_factor.py:11:is_prime 0.03 10.62 0.00 max_prime_factor.py:26:<module>---Sample count: 3535Total time: 10.620000 secondspython max_prime_factor.py 10,56s user 0,17s system 90% cpu 11,908 total

statprof

Page 86: Профилирование и отладка Django

Moscow Django MeetUp №13

statprof

• Устанавливаем zeromq (нужна для работы):➜ brew install zmq

• Устанавливаем модуль:➜ pip install statprof django-live-profiler

• Запускаем аггрегатор:➜ aggregated --host 127.0.0.1 --port 5556

Page 87: Профилирование и отладка Django

Moscow Django MeetUp №13

statprof• Добавляем application в Django:

INSTALLED_APPS += ('profiler',)

• Добавляем middleware:MIDDLEWARE_CLASSES += (

'profiler.middleware.ProfilerMiddleware',

'profiler.middleware.StatProfMiddleware')

• Добавляем urls:url(r'^profiler/', include('profiler.urls'))

• Запускаем Django:➜ python manage.py runserver --noreload --nothreading

Page 88: Профилирование и отладка Django

Moscow Django MeetUp №13

statprof

Page 89: Профилирование и отладка Django

Moscow Django MeetUp №13

statprof

Page 90: Профилирование и отладка Django

Moscow Django MeetUp №13

statprof

небольшой оверхед

можно пускать в продакшн (если осторожно)

профилирование SQL-запросов

сложная установка, зависимости

мало данных на выходе

Page 91: Профилирование и отладка Django

Moscow Django MeetUp №13

plop

https://github.com/bdarnell/plop

Инструменты для профилирования

Page 92: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install plop tornado

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m plop.collector max_prime_factor.pyAnswer: 6857profile output saved to /tmp/plop.outoverhead was 4.78124272996e-05 per sample (0.00478124272996%)

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m plop.viewer --datadir=/tmp/

plop

Page 93: Профилирование и отладка Django

Moscow Django MeetUp №13

plop

Page 94: Профилирование и отладка Django

Moscow Django MeetUp №13

plop

Page 95: Профилирование и отладка Django

Moscow Django MeetUp №13

plop

• Устанавливаем модули:➜ pip install plop django-plop tornado

• Добавляем application в Django:INSTALLED_APPS += ('django_plop',)

• Добавляем middleware:MIDDLEWARE_CLASSES += (

'django_plop.middleware.PlopMiddleware',)

• Указываем путь для сохранения результатов:PLOP_DIR = os.path.join(ROOT_DIR, 'plop')

Page 96: Профилирование и отладка Django

Moscow Django MeetUp №13

plop

• Запускаем Django:➜ python manage.py runserver --noreload --nothreading

• Запускаем просмотр результатов:➜ python -m plop.viewer --datadir=plop

Page 97: Профилирование и отладка Django

Moscow Django MeetUp №13

plop

минимальный оверхед (около 2%)

можно пускать в продакшн

сложная установка, зависимости

очень мало данных на выходе

Page 98: Профилирование и отладка Django

Moscow Django MeetUp №13

New Relic

http://newrelic.com/

Инструменты для профилирования

Page 99: Профилирование и отладка Django

Moscow Django MeetUp №13

New Relic

Page 100: Профилирование и отладка Django

Moscow Django MeetUp №13

New Relic

Page 101: Профилирование и отладка Django

Moscow Django MeetUp №13

New Relic

Page 102: Профилирование и отладка Django

Moscow Django MeetUp №13

New Relic

предназначен для продакшена

огромный функционал

платный (есть бесплатная версия)

данные отправляются на чужие серверы

Page 103: Профилирование и отладка Django

Moscow Django MeetUp №13

Django Debug Toolbarhttps://github.com/django-debug-toolbar/django-debug-toolbar

Инструменты для профилирования

Page 104: Профилирование и отладка Django

Moscow Django MeetUp №13

Django Debug Toolbar

• Устанавливаем модули:➜ pip install django-debug-toolbar

• Добавляем application в Django:INSTALLED_APPS += ('debug_toolbar',)

• Добавляем middleware:MIDDLEWARE_CLASSES += (

'debug_toolbar.middleware.DebugToolbarMiddleware',)

• Указываем IP для которых показываем тулбар:INTERNAL_IPS = ('127.0.0.1',)

Page 105: Профилирование и отладка Django

Moscow Django MeetUp №13

Django Debug Toolbar

Page 106: Профилирование и отладка Django

Moscow Django MeetUp №13

Django Debug Toolbar

Page 107: Профилирование и отладка Django

Moscow Django MeetUp №13

Django Debug Toolbar

Page 108: Профилирование и отладка Django

Moscow Django MeetUp №13

Django Debug Toolbar

прост в установке и использовании

огромный функционал

расширяемый (плагины)

не для продакшена (?)

данные никуда не сохраняются (только просмотр в реальном времени)

Page 109: Профилирование и отладка Django

Moscow Django MeetUp №13

Django StatsD

https://github.com/andymckay/django-statsd

Инструменты для профилирования

Page 110: Профилирование и отладка Django

Moscow Django MeetUp №13

Django StatsD• Устанавливаем модули:

➜ pip install django-statsd-mozilla

• Добавляем application в Django:INSTALLED_APPS += ('django_statsd',)

• Добавляем middleware:MIDDLEWARE_CLASSES += (

'django_statsd.middleware.GraphiteRequestTimingMiddleware',

'django_statsd.middleware.GraphiteMiddleware',)

• Указываем, что хотим получать тайминги БД:STATSD_PATCHES = ['django_statsd.patches.db']

Page 111: Профилирование и отладка Django

Moscow Django MeetUp №13

Django StatsD

Page 112: Профилирование и отладка Django

Moscow Django MeetUp №13

Django StatsD

прост в установке и использовании

используется в продакшене

мало информации (количество/время)

Нужен graphite и statsd (must-have)

Page 113: Профилирование и отладка Django

Moscow Django MeetUp №13

Обнаружение, локализация

и устранение ошибок.

Отладка

Page 114: Профилирование и отладка Django

Moscow Django MeetUp №13

The Python Debugger

http://docs.python.org/2/library/pdb.html

Инструменты для отладки

Page 115: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python -m pdb max_prime_factor.py> /home/rudnyh/work/python-profiling/max_prime_factor.py(1)<module>()-> """Project Euler problem 3 solve"""(Pdb) next> /home/rudnyh/work/python-profiling/max_prime_factor.py(2)<module>()-> from math import sqrt(Pdb) next> /home/rudnyh/work/python-profiling/max_prime_factor.py(5)<module>()-> def is_prime(num):(Pdb) next> /home/rudnyh/work/python-profiling/max_prime_factor.py(13)<module>()-> def prime_factors(num):(Pdb) next> /home/rudnyh/work/python-profiling/max_prime_factor.py(22)<module>()-> if __name__ == '__main__':(Pdb) next> /home/rudnyh/work/python-profiling/max_prime_factor.py(23)<module>()-> print "Answer: %d" % prime_factors(600851475143)[-1](Pdb) nextAnswer: 6857--Return--> /home/rudnyh/work/python-profiling/max_prime_factor.py(23)<module>()->None-> print "Answer: %d" % prime_factors(600851475143)[-1](Pdb) quit

pdb

Page 116: Профилирование и отладка Django

Moscow Django MeetUp №13

1 """Project Euler problem 3 solve""" 2 from math import sqrt 3 4 5 def is_prime(num): 6 """Checks if num is prime number""" 7 import pdb; pdb.set_trace() 8 for i in xrange(2, int(sqrt(num)) + 1): 9 if not num % i: 10 return False 11 return True 12 13 14 def prime_factors(num): 15 """Find prime factors of num""" 16 result = [] 17 for i in xrange(2, int(sqrt(num)) + 1): 18 if not num % i and is_prime(i): 19 result.append(i) 20 return result 21 22 23 if __name__ == '__main__': 24 print "Answer: %d" % prime_factors(600851475143)[-1]

pdb

Page 117: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python max_prime_factor.py> /home/rudnyh/work/python-profiling/max_prime_factor.py(8)is_prime()-> for i in xrange(2, int(sqrt(num)) + 1):(Pdb) list 3 4 5 def is_prime(num): 6 """Checks if num is prime number""" 7 import pdb; pdb.set_trace() 8 -> for i in xrange(2, int(sqrt(num)) + 1): 9 if not num % i: 10 return False 11 return True 12 13 (Pdb) next> /home/rudnyh/work/python-profiling/max_prime_factor.py(9)is_prime()-> if not num % i:(Pdb) continue> /home/rudnyh/work/python-profiling/max_prime_factor.py(8)is_prime()-> for i in xrange(2, int(sqrt(num)) + 1):(Pdb)

pdb

Page 118: Профилирование и отладка Django

Moscow Django MeetUp №13

pdb

практически неограниченный функционал

не очень удобно

Page 119: Профилирование и отладка Django

Moscow Django MeetUp №13

django-pdb

https://github.com/tomchristie/django-pdb

Инструменты для отладки

Page 120: Профилирование и отладка Django

Moscow Django MeetUp №13

django-pdb

• Устанавливаем модули:➜ pip install django-pdb

• Добавляем application в Django:INSTALLED_APPS += ('django_pdb',)

• Добавляем middleware:MIDDLEWARE_CLASSES += ('django_pdb.middleware.PdbMiddleware',)

Page 121: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python manage.py runserver

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python manage.py runserver --pdb

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python manage.py runserver --ipdb

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ python manage.py runserver --pm

django-pdb

Page 122: Профилирование и отладка Django

Moscow Django MeetUp №13

IPython pdb

https://github.com/gotcha/ipdb

Инструменты для отладки

Page 123: Профилирование и отладка Django

Moscow Django MeetUp №13

ipdb

подсветка кода

автодополнение

лучше traceback и introspection

консоль (спорно)

Page 124: Профилирование и отладка Django

Moscow Django MeetUp №13

ipdbplugin

https://github.com/flavioamieiro/nose-ipdb

Инструменты для отладки

Page 125: Профилирование и отладка Django

Moscow Django MeetUp №13

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ pip install ipdbplugin

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ nosetests --ipdb

rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ nosetests --ipdb-failures

ipdbplugin

Page 126: Профилирование и отладка Django

Moscow Django MeetUp №13

PyCharm

http://www.jetbrains.com/pycharm/

Инструменты для отладки

Page 127: Профилирование и отладка Django

Moscow Django MeetUp №13

PyCharm

Page 128: Профилирование и отладка Django

Moscow Django MeetUp №13

PyCharm

отладка прямо в редакторе

установка breakpoint кликом мышки

GUI (спорно)

Page 129: Профилирование и отладка Django

Moscow Django MeetUp №13

Пожалуй, хватит

Page 130: Профилирование и отладка Django

Moscow Django MeetUp №13

Вопросы?

Page 131: Профилирование и отладка Django

Moscow Django MeetUp №13

Контакты

•Владимир Рудных

[email protected]

• github.com/dreadatour

• dreadatour.habrahabr.ru