Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

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

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

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

Avatar for Moscow Python Meetup

Moscow Python Meetup

July 18, 2013
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. Moscow Django MeetUp №13 Обо мне • технический руководитель Календаря

    Mail.Ru • pythonista • бывший перловик • ленивый программист
  2. Moscow Django MeetUp №13 Cбор характеристик работы программы с целью

    их дальнейшей оптимизации. Профилирование
  3. Moscow Django MeetUp №13 Что собираем? • время выполнения строк

    кода • количество вызовов функций • время выполнения функций • дерево вызовов функций • “hot spots” • загрузку CPU, использование памяти • и т.д.
  4. Moscow Django MeetUp №13 Простые делители числа 13195 — это

    5, 7, 13 и 29. Какой самый большой делитель числа 600851475143, являющийся простым числом? Project Euler: задача 3
  5. 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
  6. Moscow Django MeetUp №13 Профилирование начинается в голове. Инструменты —

    всего лишь инструменты. Искусство профилирования
  7. 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
  8. 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 Ручное профилирование
  9. 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) Ручное профилирование
  10. 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 Ручное профилирование
  11. 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 Ручное профилирование
  12. 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
  13. Moscow Django MeetUp №13 Ручное профилирование очень простое применение ограниченно

    подходит для продакшена вставка чужеродного кода в проект никакой информации о коде (кроме времени выполнения) анализ результатов может быть затруднительным
  14. Moscow Django MeetUp №13 Сбор статистики времени выполнения кода. Например,

    в graphite или statsd: Применение в реальной жизни
  15. 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() Менеджер контекста
  16. Moscow Django MeetUp №13 from django.core.mail import send_mail from 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 ) Пример использования
  17. 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 Декоратор
  18. Moscow Django MeetUp №13 from django.db import models from 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) Пример использования
  19. 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 @profile def is_prime(num): """Checks if num is prime number""" for i in range(2, num): if not num % i: return False return True
  20. 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
  21. Moscow Django MeetUp №13 Deterministic profilers вся информация о коде

    множество инструментов для анализа очень медленно непригодно для продакшена (или крайне ограниченно)
  22. Moscow Django MeetUp №13 Statistical profilers def foo() def bar()

    def baz() def foo() def bar() def baz() Timer: 1ms Timer: 10ms
  23. Moscow Django MeetUp №13 Statistical profilers можно пускать в продакшн

    (практически не влияет на быстродействие) не вся информация о коде мало инструментов для анализа
  24. Moscow Django MeetUp №13 Deterministic profilers • profile • cProfile

    • hotshot • kcachegrind • RunSnakeRun • gprof2dot • pycallgraph • line_profiler • memory_profiler • dowser • guppy • muppy • memprof • objgraph “тысячи их”...
  25. Moscow Django MeetUp №13 rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜

    python -m cProfile -s time max_prime_factor.py Answer: 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
  26. 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
  27. 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
  28. Moscow Django MeetUp №13 rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜

    python -m cProfile -s time max_prime_factor.py Answer: 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
  29. 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 @profile def foo(): ... cProfile: декоратор
  30. Moscow Django MeetUp №13 import hotshot prof = hotshot.Profile("profile_name.prof") prof.start()

    # your code goes here prof.stop() prof.close() hotshot: использование
  31. 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 @profile def foo(): ... hotshot: декоратор
  32. Moscow Django MeetUp №13 cProfile, hotshot мощные инструменты достаточно простые

    дерево вызовов функций сильно влияют на производительность анализ результатов может быть затруднительным
  33. 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 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.py Answer: 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: производительность
  34. 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: анализ результатов
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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/
  40. Moscow Django MeetUp №13 Получаем по одному *.prof файлу на

    запрос: rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜ ls /tmp/prof/ admin.000276ms.1374075009.prof admin.account.user.000278ms.1374075014.prof admin.jsi18n.000185ms.1374075018.prof favicon.ico.000017ms.1374075001.prof root.000073ms.1374075004.prof static.admin.css.base.css.000011ms.1374075010.prof static.admin.css.forms.css.000013ms.1374075017.prof static.admin.img.icon-yes.gif.000001ms.1374075015.prof static.admin.img.sorting-icons.gif.000001ms.1374075015.prof static.admin.js.core.js.000018ms.1374075014.prof static.admin.js.jquery.js.000003ms.1374075014.prof static.css.bootstrap-2.3.2.min.css.000061ms.1374074996.prof static.img.glyphicons-halflings.png.000001ms.1374075005.prof static.js.bootstrap-2.3.2.min.js.000004ms.1374074996.prof static.js.jquery-2.0.2.min.js.000001ms.1374074996.prof user.login.000187ms.1374075001.prof А дальшё всё как обычно: Профилируем Django
  41. 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
  42. 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
  43. Moscow Django MeetUp №13 rudnyh@work:~/work/python-profiling (venv: python-profiling) (git: master|✔) ➜

    runsnake /tmp/prof/user.login.000187ms.1374075001.prof Анализ: RunSnakeRun
  44. 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
  45. 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.py Python Call Graph v0.5.1 Starting trace Answer: 6857 Creating pycallgraph.png Done! pycallgraph
  46. Moscow Django MeetUp №13 import pycallgraph pycallgraph.start_trace() # your code

    goes here pycallgraph.make_dot_graph('call-graph.png') pycallgraph
  47. 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 5 Total 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 14 Total 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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 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.py Answer: 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: 3535 Total time: 10.620000 seconds python max_prime_factor.py 10,56s user 0,17s system 90% cpu 11,908 total statprof
  53. Moscow Django MeetUp №13 statprof • Устанавливаем zeromq (нужна для

    работы): ➜ brew install zmq • Устанавливаем модуль: ➜ pip install statprof django-live-profiler • Запускаем аггрегатор: ➜ aggregated --host 127.0.0.1 --port 5556
  54. 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
  55. Moscow Django MeetUp №13 statprof небольшой оверхед можно пускать в

    продакшн (если осторожно) профилирование SQL-запросов сложная установка, зависимости мало данных на выходе
  56. 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.py Answer: 6857 profile output saved to /tmp/plop.out overhead 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
  57. 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')
  58. Moscow Django MeetUp №13 plop • Запускаем Django: ➜ python

    manage.py runserver --noreload --nothreading • Запускаем просмотр результатов: ➜ python -m plop.viewer --datadir=plop
  59. Moscow Django MeetUp №13 plop минимальный оверхед (около 2%) можно

    пускать в продакшн сложная установка, зависимости очень мало данных на выходе
  60. Moscow Django MeetUp №13 New Relic предназначен для продакшена огромный

    функционал платный (есть бесплатная версия) данные отправляются на чужие серверы
  61. 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',)
  62. Moscow Django MeetUp №13 Django Debug Toolbar прост в установке

    и использовании огромный функционал расширяемый (плагины) не для продакшена (?) данные никуда не сохраняются (только просмотр в реальном времени)
  63. 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']
  64. Moscow Django MeetUp №13 Django StatsD прост в установке и

    использовании используется в продакшене мало информации (количество/время) Нужен graphite и statsd (must-have)
  65. 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) next Answer: 6857 --Return-- > /home/rudnyh/work/python-profiling/max_prime_factor.py(23)<module>()->None -> print "Answer: %d" % prime_factors(600851475143)[-1] (Pdb) quit pdb
  66. 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
  67. 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
  68. Moscow Django MeetUp №13 django-pdb • Устанавливаем модули: ➜ pip

    install django-pdb • Добавляем application в Django: INSTALLED_APPS += ('django_pdb',) • Добавляем middleware: MIDDLEWARE_CLASSES += ('django_pdb.middleware.PdbMiddleware',)
  69. 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
  70. 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