Upload
vladimir-rudnyh
View
779
Download
2
Embed Size (px)
DESCRIPTION
При написании программы, разработчик примерно представляет себе, как должна работать его программа. Но не всегда его ожидания соответствуют действительности — приложения тормозят, потребляют много ресурсов и вообще ведут себя не так, как задумывалось, особенно под большой нагрузкой. В своём докладе я покажу, как заглянуть "под капот" ваших приложений на Python (и Django в частности): какие способы профилирования бывают и когда их можно использовать, расскажу об отладке приложений и различных инструментах, которые помогают разработчику при разработке.
Citation preview
Профилирование и отладкаDjango
Владимир Рудных
Moscow Django MeetUp №13
Обо мне
• технический руководитель Календаря Mail.Ru
• pythonista
• бывший перловик
• ленивый программист
Moscow Django MeetUp №13
Cбор характеристик работы программы
с целью их дальнейшей оптимизации.
Профилирование
Moscow Django MeetUp №13
Что собираем?
• время выполнения строк кода
• количество вызовов функций
• время выполнения функций
• дерево вызовов функций
• “hot spots”
• загрузку CPU, использование памяти
• и т.д.
Moscow Django MeetUp №13
Project Euler
http://projecteuler.net
Тренируемся
Moscow Django MeetUp №13
Простые делители числа 13195 — это 5, 7, 13 и 29.
Какой самый большой делитель числа 600851475143,
являющийся простым числом?
Project Euler: задача 3
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
Moscow Django MeetUp №13
Moscow Django MeetUp №13
Moscow Django MeetUp №13
Профилирование начинается в голове.
Инструменты — всего лишь инструменты.
Искусство профилирования
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
Moscow Django MeetUp №13
Подходы к профилированию
• ручное профилирование
• с помощью инструментов
Moscow Django MeetUp №13
Ручное профилирование
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
Ручное профилирование
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)
Ручное профилирование
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
Ручное профилирование
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
Ручное профилирование
Moscow Django MeetUp №13
timeit
http://docs.python.org/2/library/timeit.html
Ручное профилирование
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
Moscow Django MeetUp №13
Ручное профилированиеочень простое применение
ограниченно подходит для продакшена
вставка чужеродного кода в проектникакой информации о коде (кроме времени выполнения)анализ результатов может быть затруднительным
Moscow Django MeetUp №13
— Зацени, мой код быстрее твоего!
Применение
Moscow Django MeetUp №13
Применение
Moscow Django MeetUp №13
Сбор статистики времени выполнения кода.
Например, в graphite или statsd:
Применение в реальной жизни
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()
Менеджер контекста
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 )
Пример использования
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
Декоратор
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)
Пример использования
Moscow Django MeetUp №13
Статистика профилирования
Moscow Django MeetUp №13
Профилирование
с помощью инструментов
Moscow Django MeetUp №13
Инструменты для профилирования
•Deterministic (event-based)
•Statistical
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
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
Moscow Django MeetUp №13
Deterministic profilers
def foo()
def bar()
def baz() def ololo()
Moscow Django MeetUp №13
Deterministic profilers
вся информация о коде
множество инструментов для анализа
очень медленно
непригодно для продакшена (или крайне ограниченно)
Moscow Django MeetUp №13
Statistical profilers
def foo() def bar() def baz()
def foo() def bar() def baz()
Timer: 1ms
Timer: 10ms
Moscow Django MeetUp №13
Statistical profilers
def foo() def foo() def foo() def foo()def foo()
def foo()
Moscow Django MeetUp №13
Statistical profilers
можно пускать в продакшн (практически не влияет на быстродействие)
не вся информация о коде
мало инструментов для анализа
Moscow Django MeetUp №13
Deterministic profilers
• profile
• cProfile
• hotshot
• kcachegrind
• RunSnakeRun
• gprof2dot
• pycallgraph
• line_profiler
• memory_profiler
• dowser
• guppy
• muppy
• memprof
• objgraph
“тысячи их”...
Moscow Django MeetUp №13
cProfile
http://docs.python.org/2/library/profile.html
Инструменты для профилирования
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
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
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
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
Moscow Django MeetUp №13
Ускорил код в сто раз
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: декоратор
Moscow Django MeetUp №13
hotshot
http://docs.python.org/2/library/hotshot.html
Инструменты для профилирования
Moscow Django MeetUp №13
import hotshot
prof = hotshot.Profile("profile_name.prof")prof.start()
# your code goes here
prof.stop()prof.close()
hotshot: использование
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: декоратор
Moscow Django MeetUp №13
cProfile, hotshot
мощные инструменты
достаточно простые
дерево вызовов функций
сильно влияют на производительностьанализ результатов может быть затруднительным
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: производительность
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: анализ результатов
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
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
Moscow Django MeetUp №13
Анализ: kcachegrind
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
Moscow Django MeetUp №13
Анализ: RunSnakeRun
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
Moscow Django MeetUp №13
Анализ: gprof2dot
Moscow Django MeetUp №13
Но где же 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/
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
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
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
Moscow Django MeetUp №13
rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔)➜ runsnake /tmp/prof/user.login.000187ms.1374075001.prof
Анализ: RunSnakeRun
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
Moscow Django MeetUp №13
Ещё инструменты
Moscow Django MeetUp №13
pycallgraph
http://pycallgraph.slowchop.com/
Инструменты для профилирования
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
Moscow Django MeetUp №13
import pycallgraph
pycallgraph.start_trace()
# your code goes here
pycallgraph.make_dot_graph('call-graph.png')
pycallgraph
Moscow Django MeetUp №13
line_profiler
https://bitbucket.org/robertkern/line_profiler
Инструменты для профилирования
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
Moscow Django MeetUp №13
memory_profiler
https://github.com/fabianp/memory_profiler
Инструменты для профилирования
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
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
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
Moscow Django MeetUp №13
И ещё инструменты
Moscow Django MeetUp №13
Профилирование памяти
Dowser
http://www.aminus.net/wiki/Dowser
Инструменты для профилирования
Moscow Django MeetUp №13
Профилирование памяти
guppy
http://guppy-pe.sourceforge.net/
Инструменты для профилирования
Moscow Django MeetUp №13
Обнаружение утечек памяти
muppy
http://pythonhosted.org/Pympler/muppy.html
Инструменты для профилирования
Moscow Django MeetUp №13
Профилирование памяти
memprof
http://jmdana.github.io/memprof/
Инструменты для профилирования
Moscow Django MeetUp №13
Исследование объектов
objgraph
http://mg.pov.lt/objgraph/
Инструменты для профилирования
Moscow Django MeetUp №13
Statistical profilers
• StatProf
• Plop
• New Relic
Moscow Django MeetUp №13
statprof
https://github.com/bos/statprof.py
Инструменты для профилирования
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
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
Moscow Django MeetUp №13
statprof
• Устанавливаем zeromq (нужна для работы):➜ brew install zmq
• Устанавливаем модуль:➜ pip install statprof django-live-profiler
• Запускаем аггрегатор:➜ aggregated --host 127.0.0.1 --port 5556
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
Moscow Django MeetUp №13
statprof
Moscow Django MeetUp №13
statprof
Moscow Django MeetUp №13
statprof
небольшой оверхед
можно пускать в продакшн (если осторожно)
профилирование SQL-запросов
сложная установка, зависимости
мало данных на выходе
Moscow Django MeetUp №13
plop
https://github.com/bdarnell/plop
Инструменты для профилирования
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
Moscow Django MeetUp №13
plop
Moscow Django MeetUp №13
plop
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')
Moscow Django MeetUp №13
plop
• Запускаем Django:➜ python manage.py runserver --noreload --nothreading
• Запускаем просмотр результатов:➜ python -m plop.viewer --datadir=plop
Moscow Django MeetUp №13
plop
минимальный оверхед (около 2%)
можно пускать в продакшн
сложная установка, зависимости
очень мало данных на выходе
Moscow Django MeetUp №13
New Relic
http://newrelic.com/
Инструменты для профилирования
Moscow Django MeetUp №13
New Relic
Moscow Django MeetUp №13
New Relic
Moscow Django MeetUp №13
New Relic
Moscow Django MeetUp №13
New Relic
предназначен для продакшена
огромный функционал
платный (есть бесплатная версия)
данные отправляются на чужие серверы
Moscow Django MeetUp №13
Django Debug Toolbarhttps://github.com/django-debug-toolbar/django-debug-toolbar
Инструменты для профилирования
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',)
Moscow Django MeetUp №13
Django Debug Toolbar
Moscow Django MeetUp №13
Django Debug Toolbar
Moscow Django MeetUp №13
Django Debug Toolbar
Moscow Django MeetUp №13
Django Debug Toolbar
прост в установке и использовании
огромный функционал
расширяемый (плагины)
не для продакшена (?)
данные никуда не сохраняются (только просмотр в реальном времени)
Moscow Django MeetUp №13
Django StatsD
https://github.com/andymckay/django-statsd
Инструменты для профилирования
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']
Moscow Django MeetUp №13
Django StatsD
Moscow Django MeetUp №13
Django StatsD
прост в установке и использовании
используется в продакшене
мало информации (количество/время)
Нужен graphite и statsd (must-have)
Moscow Django MeetUp №13
Обнаружение, локализация
и устранение ошибок.
Отладка
Moscow Django MeetUp №13
The Python Debugger
http://docs.python.org/2/library/pdb.html
Инструменты для отладки
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
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
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
Moscow Django MeetUp №13
pdb
практически неограниченный функционал
не очень удобно
Moscow Django MeetUp №13
django-pdb
https://github.com/tomchristie/django-pdb
Инструменты для отладки
Moscow Django MeetUp №13
django-pdb
• Устанавливаем модули:➜ pip install django-pdb
• Добавляем application в Django:INSTALLED_APPS += ('django_pdb',)
• Добавляем middleware:MIDDLEWARE_CLASSES += ('django_pdb.middleware.PdbMiddleware',)
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
Moscow Django MeetUp №13
IPython pdb
https://github.com/gotcha/ipdb
Инструменты для отладки
Moscow Django MeetUp №13
ipdb
подсветка кода
автодополнение
лучше traceback и introspection
консоль (спорно)
Moscow Django MeetUp №13
ipdbplugin
https://github.com/flavioamieiro/nose-ipdb
Инструменты для отладки
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
Moscow Django MeetUp №13
PyCharm
http://www.jetbrains.com/pycharm/
Инструменты для отладки
Moscow Django MeetUp №13
PyCharm
Moscow Django MeetUp №13
PyCharm
отладка прямо в редакторе
установка breakpoint кликом мышки
GUI (спорно)
Moscow Django MeetUp №13
Пожалуй, хватит
Moscow Django MeetUp №13
Вопросы?
Moscow Django MeetUp №13
Контакты
•Владимир Рудных
• github.com/dreadatour
• dreadatour.habrahabr.ru