Как вы можете профилировать скрипт Python?

1283

Project Euler и другие конкурсы по кодированию часто имеют максимальное время для запуска, или люди хвастаются тем, насколько быстро работает их конкретное решение. В Python иногда подходы несколько хитры - например, добавление временного кода в __main__.

Как правильно определить, сколько времени занимает запуск программы на Python?

Крис Лоулор
источник
113
Программы euler проекта не должны нуждаться в профилировании. Либо у вас есть алгоритм, который работает менее чем за минуту, или у вас совершенно неправильный алгоритм. «Тюнинг» редко уместен. Как правило, вы должны принять новый подход.
S.Lott
105
С. Лотт: Профилирование часто помогает определить, какие подпрограммы являются медленными. Подпрограммы, которые занимают много времени, являются хорошими кандидатами для улучшения алгоритмов.
stalepretzel

Ответы:

1370

Python включает в себя профилировщик cProfile . Он не только показывает общее время выполнения, но и время каждой функции в отдельности, а также сообщает, сколько раз была вызвана каждая функция, что позволяет легко определить, где вы должны выполнить оптимизацию.

Вы можете вызвать его из своего кода или из интерпретатора, например так:

import cProfile
cProfile.run('foo()')

Еще полезнее, что вы можете вызвать cProfile при запуске скрипта:

python -m cProfile myscript.py

Чтобы сделать это еще проще, я создал небольшой пакетный файл с именем 'profile.bat':

python -m cProfile %1

Так что все, что мне нужно сделать, это запустить:

profile euler048.py

И я получаю это:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

РЕДАКТИРОВАТЬ: Обновленная ссылка на хороший видео-ресурс из PyCon 2013 под названием Python Profiling
Также через YouTube .

Крис Лоулор
источник
251
Также полезно отсортировать результаты, что можно сделать с помощью ключа -s, например: -s time. Вы можете использовать совокупные / имя / время / параметры сортировки файлов.
Иржи
19
Также стоит отметить, что вы можете использовать модуль cProfile из ipython, используя волшебную функцию% prun (запуск профиля). Сначала импортируйте ваш модуль, а затем вызовите основную функцию с помощью% prun: import euler048; % prun euler048.main ()
RussellStewart
53
Для визуализации дампов cProfile (созданных python -m cProfile -o <out.profile> <script>), RunSnakeRun , вызывается как runsnake <out.profile>бесценный.
Лили Чунг,
13
@NeilG даже для Python 3, cprofileпо - прежнему рекомендуется более profile.
Трихоплакс
17
Для визуализации дампов cProfile RunSnakeRun не обновлялся с 2011 года и не поддерживает python3. Вы должны использовать Snakeviz вместо этого
Джакомо Tecya Pigani
424

Некоторое время назад я сделал, pycallgraphкоторый генерирует визуализацию из вашего кода Python. Изменить: я обновил пример для работы с 3.3, последний выпуск на момент написания.

После pip install pycallgraphустановки и установки GraphViz вы можете запустить его из командной строки:

pycallgraph graphviz -- ./mypythonscript.py

Или вы можете профилировать отдельные части вашего кода:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

Любой из них создаст pycallgraph.pngфайл, похожий на изображение ниже:

введите описание изображения здесь

гак
источник
43
Вы красите в зависимости от количества звонков? Если это так, вы должны раскрасить по времени, потому что функция с большинством вызовов не всегда та, которая занимает больше всего времени.
красный
21
@red Вы можете настроить цвета по своему вкусу и даже независимо для каждого измерения. Например, красный для звонков, синий для времени, зеленый для использования памяти.
Гак
2
получаю эту ошибкуTraceback (most recent call last): /pycallgraph.py", line 90, in generate output.done() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 94, in done source = self.generate() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 143, in generate indent_join.join(self.generate_attributes()), File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 169, in generate_attributes section, self.attrs_from_dict(attrs), ValueError: zero length field name in format
Ciasto piekarz
3
Я обновил это, чтобы упомянуть, что вам нужно установить GraphViz, чтобы все работало, как описано. На Ubuntu это просто sudo apt-get install graphviz.
mlissner
2
Это требует немного работы, чтобы установить здесь 3 шага, чтобы помочь. 1. Установите через pip, 2. Установите GraphViz через exe 3. Установите переменные пути в директорию GraphViz 4. Узнайте, как исправить все остальные ошибки. 5. Выясните, где он сохраняет файл PNG?
Марш
199

Стоит отметить, что использование профилировщика работает (по умолчанию) только в основном потоке, и вы не получите никакой информации из других потоков, если будете их использовать. Это может быть немного затруднительно, поскольку это совершенно не упоминается в документации профилировщика .

Если вы также хотите профилировать потоки, вы должны посмотреть на threading.setprofile()функцию в документах.

Вы также можете создать свой собственный threading.Threadподкласс для этого:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

и использовать этот ProfiledThreadкласс вместо стандартного. Это может дать вам больше гибкости, но я не уверен, что оно того стоит, особенно если вы используете сторонний код, который не будет использовать ваш класс.

Джо Шоу
источник
1
Я не вижу ссылки на runcall в документации. Посмотрев на cProfile.py, я не уверен, почему вы используете функцию threading.Thread.run или self в качестве аргумента. Я бы ожидал увидеть ссылку на метод запуска другого потока здесь.
PypeBros
Это не в документации, но в модуле. См. Hg.python.org/cpython/file/6bf07db23445/Lib/cProfile.py#l140 . Это позволяет вам профилировать вызов конкретной функции, и в нашем случае мы хотим профилировать targetфункцию Thread , то есть то, что threading.Thread.run()выполняет вызов. Но, как я сказал в ответе, вероятно, не стоит делать подкласс Thread, поскольку любой сторонний код не будет его использовать, а вместо этого использовать threading.setprofile().
Джо Шоу
9
Обертывание кода с помощью profiler.enable () и profiler.disable (), похоже, тоже работает очень хорошо. Это в основном то, что делает runcall, и он не навязывает никакого количества аргументов или подобных вещей.
PypeBros
1
Я объединил свой собственный stackoverflow.com/questions/10748118/... с ddaa.net/blog/python/lsprof-calltree и kindof работы; -)
Дима Tisnek
1
Джо, ты знаешь, как профилировщик играет с Asyncio в Python 3.4?
Ник Чаммас
149

Python Wiki - отличная страница для профилирования ресурсов: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

как и документы по питону: http://docs.python.org/library/profile.html

Крис Лоулор показывает, что cProfile - отличный инструмент, который можно легко использовать для печати на экране:

python -m cProfile -s time mine.py <args>

или в файл:

python -m cProfile -o output.file mine.py <args>

PS> Если вы используете Ubuntu, обязательно установите python-профиль

apt-get install python-profiler 

Если вы выводите в файл, вы можете получить хорошую визуализацию, используя следующие инструменты

PyCallGraph: инструмент для создания изображений графа вызовов
.

 pip install pycallgraph

запустить:

 pycallgraph mine.py args

Посмотреть:

 gimp pycallgraph.png

Вы можете использовать все, что вам нравится, чтобы просмотреть файл PNG, я использовал GIMP
К сожалению, я часто получаю

точка: график слишком велик для растровых изображений каир-рендерера. Масштабирование по 0,257079, чтобы соответствовать

что делает мои изображения необычайно маленькими. Поэтому я обычно создаю SVG-файлы:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS> Обязательно установите graphviz (который предоставляет программа dot):

pip install graphviz

Альтернативный график с использованием gprof2dot через @maxy / @quodlibetor:

pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
brent.payne
источник
12
gprof2dot тоже может делать эти графики. Я думаю, что вывод немного лучше ( пример ).
maxy
2
graphviz также требуется, если вы используете OSX
Vaibhav Mishra
134

@ Комментарий Макси к этому ответу выручил меня настолько, что я думаю, что он заслуживает своего собственного ответа: у меня уже были файлы, сгенерированные cProfile .pstats, и я не хотел перезапускать вещи с pycallgraph, поэтому я использовал gprof2dot , и получил довольно SVGs:

$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

и БЛАМ!

Он использует точку (то же самое, что и pycallgraph), поэтому вывод выглядит аналогично. У меня создается впечатление, что gprof2dot теряет меньше информации:

Пример вывода gprof2dot

quodlibetor
источник
1
Хороший подход, работает очень хорошо, так как вы можете просматривать SVG в Chrome и т. Д. И увеличивать / уменьшать его. Третья строка содержит опечатку, она должна выглядеть следующим образом: ln -s pwd/gprof2dot/gprof2dot.py $ HOME / bin (или использовать ln -s $ PWD / gprof2dot / gprof2dot.py ~ / bin в большинстве оболочек - серьезный акцент используется в качестве форматирования в первой версия).
RichVel
2
Ах, хорошая мысль. Я получаю lnнеправильный порядок аргументов почти каждый раз.
quodlibetor
7
Хитрость заключается в том, что нужно помнить, что ln и cp имеют одинаковый порядок аргументов - думайте об этом как о «копировании file1 в file2 или dir2, но создании ссылки»
RichVel
Это имеет смысл, я думаю, что использование «TARGET» в man-странице бросает меня.
quodlibetor
Пожалуйста, как вы получили закругленные углы? Я чувствую, что это улучшает читаемость. Я просто получаю уродливые острые углы, что не круто при наличии множества краев вокруг коробок.
Hibou57 10.09.14
78

Я столкнулся с удобным инструментом под названием SnakeViz при исследовании этой темы. SnakeViz - это веб-инструмент для визуализации профилирования. Это очень легко установить и использовать. Обычный способ, которым я использую его, - это сгенерировать файл статистики с помощью, %prunа затем выполнить анализ в SnakeViz.

Основным методом, который используется, является диаграмма Sunburst, как показано ниже, в которой иерархия вызовов функций организована в виде слоев дуг и информации о времени, закодированных по их угловым значениям ширины.

Лучше всего, вы можете взаимодействовать с графиком. Например, чтобы увеличить масштаб, можно щелкнуть мышью по дуге, и дуга и ее потомки будут увеличены до новых солнечных лучей, чтобы отобразить больше деталей.

введите описание изображения здесь

zaxliu
источник
2
Ответ CodeCabbie включает в себя (краткие) инструкции по установке и показывает, как (легко) использовать SnakeViz.
Орен Мильман
Вот я прочитал ИМХО хорошее руководство, как использовать профилирование для Python на ноутбуке jupyter
Алексей
74

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

1. pip install snakeviz

2. python -m cProfile -o temp.dat <PROGRAM>.py

3. snakeviz temp.dat

Рисует круговую диаграмму в браузере. Самая большая часть - это проблемная функция. Очень просто.

CodeCabbie
источник
1
Это было очень полезно. Спасибо.
jippyjoe4
Смотрите также ответ zaxliu, в котором содержится ссылка на инструмент и пример вывода.
Мелебиус
55

Я думаю, что cProfileэто хорошо для профилирования, а также kcachegrindдля визуализации результатов. pyprof2calltreeМежду ручками преобразования файлов.

python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree

Чтобы установить необходимые инструменты (по крайней мере, в Ubuntu):

apt-get install kcachegrind
pip install pyprof2calltree

Результат:

Скриншот результата

Federico
источник
9
Пользователи Mac установить brew install qcachegrindи substitude каждый kcachegrind с qcachegrind в описании для успешного профилирования.
Кевин Кацке
Я должен был сделать это, чтобы заставить это работать:export QT_X11_NO_MITSHM=1
Йонатан Симсон
41

Также стоит упомянуть программу просмотра дампа cProfile с графическим интерфейсом RunSnakeRun . Это позволяет вам сортировать и выбирать, тем самым увеличивая соответствующие части программы. Размеры прямоугольников на картинке пропорциональны затраченному времени. Если вы наведите курсор мыши на прямоугольник, он выделит этот вызов в таблице и повсюду на карте. Когда вы дважды щелкаете по прямоугольнику, он увеличивает эту часть. Он покажет вам, кто вызывает эту часть и что эта часть вызывает.

Описательная информация очень полезна. Он показывает вам код для этого бита, который может быть полезен, когда вы имеете дело со встроенными вызовами библиотеки. Он говорит вам, какой файл и в какой строке найти код.

Также хочу отметить, что ОП сказал «профилирование», но, похоже, он имел в виду «выбор времени». Имейте в виду, что программы будут работать медленнее при профилировании.

введите описание изображения здесь

Пит
источник
34

Недавно я создал тунца для визуализации Python во время выполнения и импорта профилей; это может быть полезно здесь.

введите описание изображения здесь

Установить с

pip install tuna

Создать профиль времени выполнения

python3 -m cProfile -o program.prof yourfile.py

или профиль импорта (требуется Python 3.7+)

python3 -X importprofile yourfile.py 2> import.log

Тогда просто запустите тунца на файл

tuna program.prof
Нико Шлёмер
источник
33

Хорошим модулем профилирования является line_profiler (вызывается с использованием скрипта kernprof.py). Это можно скачать здесь .

Насколько я понимаю, cProfile предоставляет только информацию об общем времени, потраченном на каждую функцию. Таким образом, отдельные строки кода не рассчитаны. Это проблема научных вычислений, поскольку часто одна строка может занимать много времени. Кроме того, насколько я помню, cProfile не улавливал время, которое я проводил, скажем, в numpy.dot.

Ян Лэнгмор
источник
33

pprofile

line_profiler(уже представлен здесь) также вдохновил pprofile, который описывается как:

Линейная гранулярность, потоково-детерминированный и статистический профилировщик чистого Python

Он обеспечивает линейную гранулярность, так как line_profilerявляется чистым Python, может использоваться как отдельная команда или модуль и может даже генерировать файлы в формате callgrind, которые могут быть легко проанализированы с помощью[k|q]cachegrind .

vprof

Существует также vprof , пакет Python, описанный как:

[...] обеспечение богатых и интерактивных визуализаций для различных характеристик программы Python, таких как время работы и использование памяти.

Тепловая карта

BENČ
источник
14

Есть много отличных ответов, но они либо используют командную строку, либо какую-то внешнюю программу для профилирования и / или сортировки результатов.

Я действительно упустил какой-то способ, которым я мог бы использовать в своей IDE (eclipse-PyDev), не касаясь командной строки и не устанавливая что-либо. Так и здесь.

Профилирование без командной строки

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

Смотрите документы или другие ответы для получения дополнительной информации.

Давид Машек
источник
например, профиль печатает {map} или {xxx}. откуда мне знать, из какого файла вызывается метод {xxx}? Мой профиль печатает {метод 'compress' из 'zlib.Compress' objects} занимает большую часть времени, но я не использую zlib, поэтому я предполагаю, что некоторые функции вызова numpy могут использовать его. Как узнать, какой именно файл и строка занимает много времени?
machen
12

После ответа Джо Шоу о том, что многопоточный код не работает runcallдолжным образом , я понял, что метод в cProfile просто выполняет self.enable()и self.disable()вызывает вызов профилируемой функции, так что вы можете просто сделать это самостоятельно и получить любой код, который вы хотите использовать с минимальное вмешательство в существующий код.

PypeBros
источник
3
Отличный совет! Быстрый взгляд на cprofile.pyисходный код показывает, что это именно то , что runcall()делает. Точнее говоря, после создания экземпляра Profile с помощью prof = cprofile.Profile(), немедленно позвоните prof.disable(), а затем просто добавьте prof.enable()и prof.disable()обзвоните раздел кода, который вы хотите профилировать.
Мартино
Это очень полезно, но кажется, что код, который фактически находится между enable и disable, не профилируется - только те функции, которые он вызывает. Есть ли у меня это право? Мне нужно было обернуть этот код в вызов функции, чтобы он учитывался по любому из чисел в print_stats ().
Боб Стейн
10

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

Вальтер
источник
1
Спасибо за этот драгоценный камень. К вашему сведению: это можно использовать как отдельный модуль с любым кодом, база кода Virtaal не требуется. Просто сохраните файл в profiling.py и импортируйте profile_func (). Используйте @profile_func () в качестве декоратора для любой функции, которая вам нужна для профилирования и альта. :)
Амжит
9

cProfile отлично подходит для быстрого профилирования, но большую часть времени он заканчивался для меня ошибками. Функция runctx решает эту проблему, правильно инициализируя окружение и переменные, надеясь, что это может быть полезно для кого-то:

import cProfile
cProfile.runctx('foo()', None, locals())
Datageek
источник
7

Если вы хотите создать накопительный профилировщик, то есть запустить функцию несколько раз подряд и посмотреть сумму результатов.

Вы можете использовать этот cumulative_profilerдекоратор:

это специфично для python> = 3.6, но вы можете удалить nonlocalего для более старых версий.

import cProfile, pstats

class _ProfileFunc:
    def __init__(self, func, sort_stats_by):
        self.func =  func
        self.profile_runs = []
        self.sort_stats_by = sort_stats_by

    def __call__(self, *args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()  # this is the profiling section
        retval = self.func(*args, **kwargs)
        pr.disable()

        self.profile_runs.append(pr)
        ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
        return retval, ps

def cumulative_profiler(amount_of_times, sort_stats_by='time'):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            nonlocal function, amount_of_times, sort_stats_by  # for python 2.x remove this row

            profiled_func = _ProfileFunc(function, sort_stats_by)
            for i in range(amount_of_times):
                retval, ps = profiled_func(*args, **kwargs)
            ps.print_stats()
            return retval  # returns the results of the function
        return wrapper

    if callable(amount_of_times):  # incase you don't want to specify the amount of times
        func = amount_of_times  # amount_of_times is the function in here
        amount_of_times = 5  # the default amount
        return real_decorator(func)
    return real_decorator

пример

профилирование функции baz

import time

@cumulative_profiler
def baz():
    time.sleep(1)
    time.sleep(2)
    return 1

baz()

baz побежал 5 раз и напечатал это:

         20 function calls in 15.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   15.003    1.500   15.003    1.500 {built-in method time.sleep}
        5    0.000    0.000   15.003    3.001 <ipython-input-9-c89afe010372>:3(baz)
        5    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

указав количество раз

@cumulative_profiler(3)
def baz():
    ...
moshevi
источник
7

Только для терминала (и самое простое) решение, в случае если все эти модные интерфейсы пользователя не могут быть установлены или запущены: полностью
игнорировать cProfileи заменить его на то pyinstrument, что будет собирать и отображать дерево вызовов сразу после выполнения.

Установка:

$ pip install pyinstrument

Профиль и результат отображения:

$ python -m pyinstrument ./prog.py

Работает с python2 и 3.

[РЕДАКТИРОВАТЬ] Документация API, для профилирования только часть кода, можно найти здесь .

Francois
источник
6

Мой способ - использовать yappi ( https://github.com/sumerc/yappi ). Это особенно полезно в сочетании с RPC-сервером, на котором (даже только для отладки) вы регистрируете метод для запуска, остановки и печати данных профилирования, например, таким образом:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

Затем, когда ваша программа заработает, вы можете в любой момент запустить профилировщик, вызвав startProfilerметод RPC, и вывести информацию о профилировании в файл журнала, вызвав printProfiler(или изменив метод rpc, чтобы вернуть его вызывающей стороне), и получить такой вывод:

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
<string>.__new__:8                                                                                                                        220       0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
<string>.__new__:8                                                                                                                        4         0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

Это может быть не очень полезно для коротких сценариев, но помогает оптимизировать процессы серверного типа, особенно с учетом того, что printProfilerметод может вызываться несколько раз с течением времени для профилирования и сравнения, например, различных сценариев использования программы.

В новых версиях yappi будет работать следующий код:

@staticmethod
def printProfile():
    yappi.get_func_stats().print_all()
Мистер гиргитт
источник
Разве это не должно быть названо Великолепным Яппи?
Therealstubot
К сожалению, приведенный выше код работает только с версией 0.62, которая недоступна в pypy. Модуль должен быть скомпилирован из источников 0.62, доступных здесь: github.com/nirs/yappi/releases или использовать сборку, которую я сделал для окон в репо, для этой цели разветвленный github.com/Girgitt/yappi/releases
г-н Гиргитт,
совместимость с версией 1.0 может быть легко обеспечена - по крайней мере для вывода на печать - путем изменения функции printProfiler: def printProfiler(): if not yappi_available: return stats = yappi.get_func_stats() stats.print_all(columns={0:("name",90), 1:("ncall", 5), 2:("tsub", 8), 3:("ttot", 8), 4:("tavg",8)}) (ОК после попытки пару раз вставить блок кода в оставленный мной комментарий. Это невероятно сложно для ориентированного на программирование сайта вопросов и ответов. )
Г-н Гиргитт
4

Новый инструмент для обработки профилей в Python - это PyVmMonitor: http://www.pyvmmonitor.com/

У этого есть некоторые уникальные особенности, такие как

  • Присоедините профилировщик к запущенной (CPython) программе
  • Профилирование по требованию с интеграцией Yappi
  • Профиль на другой машине
  • Поддержка нескольких процессов (multiprocessing, django ...)
  • Живая выборка / просмотр CPU (с выбором временного диапазона)
  • Детерминированное профилирование через интеграцию cProfile / профиля
  • Анализировать существующие результаты PStats
  • Открытые DOT файлы
  • Программный доступ к API
  • Группировать образцы по методу или линии
  • Интеграция PyDev
  • Интеграция PyCharm

Примечание: он коммерческий, но бесплатный для открытого источника.

Фабио Задрозный
источник
4

gprof2dot_magic

Магическая функция для gprof2dotпрофилирования любого оператора Python в виде графа DOT в JupyterLab или Jupyter Notebook.

введите описание изображения здесь

Репозиторий GitHub: https://github.com/mattijn/gprof2dot_magic

установка

Убедитесь, что у вас есть пакет Python gprof2dot_magic.

pip install gprof2dot_magic

Его зависимости gprof2dotиgraphviz будут установлены

Применение

Чтобы включить магическую функцию, сначала загрузите gprof2dot_magicмодуль

%load_ext gprof2dot_magic

а затем профилировать любой оператор строки как график DOT как таковой:

%gprof2dot print('hello world')

введите описание изображения здесь

Mattijn
источник
3

Вы когда-нибудь хотели узнать, что, черт возьми, делает этот скрипт на Python? Войдите в Осмотр Оболочки. Inspect Shell позволяет печатать / изменять глобальные переменные и запускать функции, не прерывая работающий скрипт. Теперь с автозаполнением и историей команд (только в Linux).

Осмотрите Shell не отладчик в стиле pdb.

https://github.com/amoffat/Inspect-Shell

Вы можете использовать это (и ваши наручные часы).

Полковник паника
источник
3

Добавить на https://stackoverflow.com/a/582337/1070617 ,

Я написал этот модуль, который позволяет вам использовать cProfile и легко просматривать его вывод. Больше здесь: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

Также см .: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html о том, как разобраться в собранной статистике.

Майкл
источник
3

Это будет зависеть от того, что вы хотите увидеть из профилирования. Простые метрики времени могут быть предоставлены (bash).

time python python_prog.py

Даже '/ usr / bin / time' может выводить подробные метрики, используя флаг --verbose.

Чтобы проверить показатели времени, предоставляемые каждой функцией, и лучше понять, сколько времени тратится на функции, вы можете использовать встроенный cProfile в python.

Если говорить о более детальных показателях, таких как производительность, время - не единственная метрика. Вы можете беспокоиться о памяти, потоках и т. Д. Параметры
профилирования:
1. line_profiler - еще один профилировщик, используемый для построчного поиска метрик времени.
2. memory_profiler - это инструмент для профилирования использования памяти.
3. куча (из проекта гуппи) Профиль того, как используются объекты в куче.

Вот некоторые из наиболее часто используемых мной. Но если вы хотите узнать больше, попробуйте прочитать эту книгу. Это очень хорошая книга о том, как начать с производительности. Вы можете перейти к более сложным темам об использовании Python, скомпилированных на языке Cython и JIT (Just-in-time).

VishalMishra
источник
2

С таким статистическим профилировщиком, как Остин , не требуется никаких инструментов, а это означает, что вы можете получать данные профилирования из приложения Python просто с

austin python3 my_script.py

Необработанный вывод не очень полезен, но вы можете направить его в Flamegraph.pl, чтобы получить представление данных пламени на графике пламени, которое дает вам представление о том, где время (измеренное в микросекундах реального времени) тратится.

austin python3 my_script.py | flamegraph.pl > my_script_profile.svg
Phoenix87
источник
2

Для получения быстрой статистики профиля на ноутбуке IPython. Можно встраивать line_profiler и memory_profiler прямо в свои ноутбуки.

Еще один полезный пакет - это Pympler . Это мощный пакет профилирования, который способен отслеживать классы, объекты, функции, утечки памяти и т. Д. Примеры ниже, документы прилагаются.

Возьми!

!pip install line_profiler
!pip install memory_profiler
!pip install pympler

Загрузите это!

%load_ext line_profiler
%load_ext memory_profiler

Используй это!


%время

%time print('Outputs CPU time,Wall Clock time') 
#CPU times: user 2 µs, sys: 0 ns, total: 2 µs Wall time: 5.96 µs

дает:

  • Время процессора: время выполнения на уровне процессора
  • sys times: время выполнения на системном уровне
  • Итого: процессорное время + системное время
  • Время стены: Время настенных часов

% timeit

%timeit -r 7 -n 1000 print('Outputs execution time of the snippet') 
#1000 loops, best of 7: 7.46 ns per loop
  • Дает лучшее время из заданного количества прогонов (r) в цикле (n) раз.
  • Выводит подробности о системном кешировании:
    • Когда фрагменты кода выполняются несколько раз, система кэширует несколько операций и не выполняет их снова, что может снизить точность отчетов профиля.

% prun

%prun -s cumulative 'Code to profile' 

дает:

  • количество вызовов функций (ncalls)
  • имеет записи для каждого вызова функции (разные)
  • время, затрачиваемое на звонок (percall)
  • время, прошедшее до вызова этой функции (cumtime)
  • название func / module называется etc ...

Накопительный профиль


% memit

%memit 'Code to profile'
#peak memory: 199.45 MiB, increment: 0.00 MiB

дает:

  • Использование памяти

% lprun

#Example function
def fun():
  for i in range(10):
    print(i)

#Usage: %lprun <name_of_the_function> function
%lprun -f fun fun()

дает:

  • Линейная статистика

LineProfile


sys.getsizeof

sys.getsizeof('code to profile')
# 64 bytes

Возвращает размер объекта в байтах.


asizeof () от pympler

from pympler import asizeof
obj = [1,2,("hey","ha"),3]
print(asizeof.asizeof(obj,stats=4))

pympler.asizeof может использоваться, чтобы исследовать, сколько памяти потребляют определенные объекты Python. В отличие от sys.getsizeof, asizeof размеров рекурсивно

pympler.asizeof


трекер от пимплера

from pympler import tracker
tr = tracker.SummaryTracker()
def fun():
  li = [1,2,3]
  di = {"ha":"haha","duh":"Umm"}
fun()
tr.print_diff()

Отслеживает время жизни функции.

выход трекера

Пакет Pympler состоит из огромного количества высокоуровневых функций для профилирования кода. Все это не может быть рассмотрено здесь. См. Прилагаемую документацию для реализации подробного профиля.

Pympler doc

Адитья Патнаик
источник
1

Также есть статистический профайлер statprof. Это профилировщик выборки, поэтому он добавляет минимальные накладные расходы к вашему коду и дает синхронизацию по строкам (а не только по функциям). Он больше подходит для мягких приложений реального времени, таких как игры, но может иметь меньшую точность, чем cProfile.

Версия в PyPI старовата, поэтому его можно установить с pipпомощью указания мерзавцев хранилища :

pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01

Вы можете запустить его так:

import statprof

with statprof.profile():
    my_questionable_function()

Смотрите также https://stackoverflow.com/a/10333592/320036

z0r
источник
1

Я только что разработал свой собственный профилировщик, вдохновленный pypref_time:

https://github.com/modaresimr/auto_profiler

При добавлении декоратора он покажет дерево трудоемких функций

@Profiler(depth=4, on_disable=show)

Install by: pip install auto_profiler

пример

import time # line number 1
import random

from auto_profiler import Profiler, Tree

def f1():
    mysleep(.6+random.random())

def mysleep(t):
    time.sleep(t)

def fact(i):
    f1()
    if(i==1):
        return 1
    return i*fact(i-1)


def show(p):
    print('Time   [Hits * PerHit] Function name [Called from] [Function Location]\n'+\
          '-----------------------------------------------------------------------')
    print(Tree(p.root, threshold=0.5))

@Profiler(depth=4, on_disable=show)
def main():
    for i in range(5):
        f1()

    fact(3)


if __name__ == '__main__':
    main()

Пример вывода


Time   [Hits * PerHit] Function name [Called from] [function location]
-----------------------------------------------------------------------
8.974s [1 * 8.974]  main  [auto-profiler/profiler.py:267]  [/test/t2.py:30]
├── 5.954s [5 * 1.191]  f1  [/test/t2.py:34]  [/test/t2.py:14]
   └── 5.954s [5 * 1.191]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
       └── 5.954s [5 * 1.191]  <time.sleep>
|
|
|   # The rest is for the example recursive function call fact
└── 3.020s [1 * 3.020]  fact  [/test/t2.py:36]  [/test/t2.py:20]
    ├── 0.849s [1 * 0.849]  f1  [/test/t2.py:21]  [/test/t2.py:14]
       └── 0.849s [1 * 0.849]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
           └── 0.849s [1 * 0.849]  <time.sleep>
    └── 2.171s [1 * 2.171]  fact  [/test/t2.py:24]  [/test/t2.py:20]
        ├── 1.552s [1 * 1.552]  f1  [/test/t2.py:21]  [/test/t2.py:14]
           └── 1.552s [1 * 1.552]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
        └── 0.619s [1 * 0.619]  fact  [/test/t2.py:24]  [/test/t2.py:20]
            └── 0.619s [1 * 0.619]  f1  [/test/t2.py:21]  [/test/t2.py:14]
Али
источник
0

Когда я не являюсь пользователем root на сервере, я использую lsprofcalltree.py и запускаю свою программу следующим образом:

python lsprofcalltree.py -o callgrind.1 test.py

Затем я могу открыть отчет с помощью любого совместимого с callgrind программного обеспечения, такого как qcachegrind

Винсент Фенет
источник