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

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

Каков хороший способ определить, как долго запускается программа python для запуска?

+1136
24 февр. '09 в 16:01
источник поделиться
23 ответа

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.

+1219
24 февр. '09 в 16:01
источник

Некоторое время назад я сделал 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 подобный изображению ниже:

enter image description here

+389
06 авг. '12 в 5:37
источник

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

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

Вы также можете создать свой собственный подкласс 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 вместо стандартного. Это может дать вам большую гибкость, но я не уверен, что это того стоит, особенно если вы используете сторонний код, который не будет использовать ваш класс.

+189
17 дек. '09 в 16:30
источник

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

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

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

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

или файл:

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

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

sudo apt-get install python-profiler 

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

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

 sudo 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 (который предоставляет программу-точка):

sudo pip install graphviz

Альтернативное отображение с использованием gprof2dot через @maxy/@quodlibetor:

sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
+136
08 окт. '11 в 0:04
источник

Комментарий @Maxy на этот ответ помог мне достаточно, что я думаю, что он заслуживает собственного ответа: у меня уже были файлы сгенерированы 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

и BLAM!

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

gprof2dot example output

+127
11 дек. '12 в 23:16
источник

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

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

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

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

+58
25 мая '16 в 8:06
источник

Я думаю, что 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

Результат:

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

+44
11 мая '16 в 8:32
источник

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

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

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

enter image description here

+40
22 февр. '15 в 16:18
источник

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

1. pip install snakeviz

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

3. snakeviz temp.dat

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

+32
08 мар. '18 в 13:03
источник

Хорошим профилирующим модулем является line_profiler (называемый с помощью script kernprof.py). Его можно загрузить здесь.

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

+31
20 окт. '11 в 16:05
источник

pprofile

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

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

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

vprof

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

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

heatmap

+29
02 мар. '15 в 11:36
источник

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

enter image description here

Установить с

pip3 install tuna

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

python -mcProfile -o program.prof yourfile.py

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

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

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

tuna program.prof
+17
04 авг. '18 в 7:27
источник

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

Я действительно пропустил какой-то способ, который мог бы использовать в моей среде 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)

Подробнее см. docs или другие ответы.

+13
21 авг. '15 в 11:59
источник

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

+12
09 нояб. '11 в 12:59
источник

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

+10
24 февр. '09 в 20:31
источник

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

import cProfile
cProfile.runctx('foo()', None, locals())
+9
30 мар. '15 в 11:11
источник

Мой способ - использовать yappi (https://code.google.com/p/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 можно многократно называть профилем и сравнивать, например. разные сценарии использования программы.

+6
19 февр. '14 в 15:38
источник

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

Он имеет некоторые уникальные функции, такие как

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

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

+3
28 апр. '15 в 22:50
источник

Чтобы добавить к qaru.site/questions/11372/...,

Я написал этот модуль, который позволяет вам легко использовать 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
21 мар. '15 в 13:50
источник

Всегда хотите знать, какого черта, что делает python script? Введите Проверьте оболочку. Inspect Shell позволяет печатать/изменять глобальные значения и запускать функции без прерывания работы script. Теперь с автозаполнение и история команд (только для Linux).

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

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

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

+3
13 окт. '12 в 15:21
источник

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

time python python_prog.py

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

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

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

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

+2
19 апр. '17 в 19:42
источник

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

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

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

Вы можете запустить его следующим образом:

import statprof

with statprof.profile():
    my_questionable_function()

См. также qaru.site/questions/11395/...

+1
11 февр. '16 в 22:50
источник

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

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

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

0
02 февр. '17 в 10:18
источник

Посмотрите другие вопросы по меткам или Задайте вопрос