Як можна профілювати сценарій Python?


1283

Проекти Ейлера та інші конкурси кодування часто мають максимальний час для запуску або люди похвастаються тим, наскільки швидко працює їх конкретне рішення. З Python іноді підходи дещо хизуються - тобто додавання коду часу __main__.

Який хороший спосіб визначити, скільки часу займає програма Python?


113
Програми еулерських проектів не повинні потребувати профілювання. Або у вас є алгоритм, який працює менше хвилини, або ви абсолютно неправильний алгоритм. "Налаштування" рідко підходить. Як правило, ви повинні використовувати новий підхід.
S.Lott

105
С.Лотт: Профілювання часто корисний спосіб визначити, які підпрограми є повільними. Підпрограми, які потребують тривалого часу, є чудовими кандидатами для алгоритмічного вдосконалення.
stalepretzel

Відповіді:


1369

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}

EDIT: оновлене посилання на хороший відеоресурс з 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

423

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

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
Тут потрібно трохи попрацювати, щоб встановити ось три кроки, щоб допомогти. 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, а також як аргумент. Я очікував би тут побачити посилання на метод запуску іншого потоку.
PypeBros

Це не в документації, але в модулі. Див. Hg.python.org/cpython/file/6bf07db23445/Lib/cProfile.py#l140 . Це дозволяє профайлювати конкретний виклик функції, і в нашому випадку ми хочемо профілювати функцію "Нитка" target, що і 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
Джо, ти знаєш, як профайлер грає з асинціо в Python 3.4?
Нік Чаммас

148

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

як і документи python: 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 (який надає крапкову програму):

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

12
gprof2dot теж може робити ці графіки. Я думаю, що вихід трохи приємніший ( приклад ).
макси

2
graphviz також потрібен, якщо ви використовуєте OSX
Vaibhav Mishra

134

@ Коментар Maxy щодо цієї відповіді досить допоміг мені, що я вважаю, що вона заслуговує власної відповіді: у мене вже були створені файли .pstats, створені cProfile, і я не хотів повторно запускати речі з 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


1
Хороший підхід, працює дуже добре, оскільки ви можете переглядати SVG в Chrome тощо та масштабувати його вгору / вниз. Третій рядок має помилку pwdдруку : ln -s /gprof2dot/gprof2dot.py $ HOME / bin (або використовувати ln -s $ PWD / gprof2dot / gprof2dot.py ~ / bin у більшості оболонок - серйозний акцент приймається за формат спочатку версія).
RichVel

2
Ах, хороший пункт. Я lnмайже щоразу помиляюся з наказом аргументів.
kodlibetor

7
хитрість полягає в тому, щоб пам’ятати, що ln і cp мають однаковий порядок аргументів - подумайте про це як «копіювання
файлу1 у файл2

Це має сенс, я вважаю, що використання "TARGET" у маніпуляції кидає мене.
quodlibetor

Будь ласка, як ви отримали закруглені кути? Я відчуваю, що це покращує читабельність. Я просто отримую некрасиві гострі кути, які не круті при наявності безлічі країв коробки.
Hibou57

77

Під час дослідження цієї теми я наткнувся на зручний інструмент під назвою SnakeViz . SnakeViz - це веб-інструмент візуалізації профілів. Встановити та використовувати дуже просто. Звичайний спосіб, яким я користуюсь, - це генерувати статистичний файл, %prunа потім робити аналіз у SnakeViz.

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

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

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


1
Відповідь CodeCabbie включає в себе (короткі) інструкції з установки та показує, як (легко) використовувати SnakeViz.
Орен Мільман

Тут я прочитав хороший посібник ІМХО про те, як використовувати профілювання для Python на ноутбуці з юпітером: premadatascience.com/speed-up-jupyter-notebooks-20716cbe2025
Олексій Мартьянов

72

Найпростіший і швидкий спосіб знайти куди йде весь час.

1. pip install snakeviz

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

3. snakeviz temp.dat

Малює кругову діаграму в браузері. Найбільша частина - це проблемна функція. Дуже просто.


1
Це було дуже корисно. Дякую.
jippyjoe4

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

Результат:

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


9
Користувачі Mac встановлюють brew install qcachegrindі підмножують кожен kcachegrind з них qcachegrind в описі для успішного профілювання.
Кевін Кацке

Мені довелося це зробити, щоб він працював:export QT_X11_NO_MITSHM=1
Йонатан Сімсон

41

Також варто відзначити переглядач дампівського дампа GUI cProfile RunSnakeRun . Це дозволяє сортувати та вибирати, тим самим збільшуючи масштаб відповідних частин програми. Розміри прямокутників на малюнку пропорційні витраченому часу. Якщо ви наведіть курсор миші на прямокутник, він виділяє цей виклик у таблиці та скрізь на карті. Коли ви двічі клацніть на прямокутнику, він збільшує цю частину. Він покаже вам, хто називає цю частину і як називає цю частину.

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

Також хочу зазначити, що ОП сказала "профілювання", але, здається, він означав "терміни". Майте на увазі, що програми будуть працювати повільніше при їх профілюванні.

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


34

Приємним модулем профілювання є line_profiler (називається за допомогою скрипту kernprof.py). Його можна завантажити тут .

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


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

pprofile

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

Лінійна деталізація, детермінований детермінований та статистичний чисто-пітонний профілер

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

vprof

Існує також vprof , пакет Python, описаний як:

[...], що забезпечує насичені та інтерактивні візуалізації для різних характеристик програми Python, таких як час роботи та використання пам'яті.

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


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}? мій профіль друкує {метод 'стискання' об'єктів 'zlib.Compress'} займає більшу частину часу, але я не використовую жодного zlib, тому я думаю, що деяка функція numpy виклику може використовувати його. Як дізнатися, який саме файл і рядок займає багато часу?
machen

12

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


3
Відмінна порада! Швидкий погляд на cprofile.pyвихідний код показує, що саме це runcall()робить. Більш конкретно, після створення екземпляра профілю prof = cprofile.Profile(), негайно зателефонуйте prof.disable(), а потім просто додайте prof.enable()та називайте prof.disable()навколо розділу коду, який ви хочете профілювати.
martineau

Це дуже корисно, але, схоже, код, який насправді між включенням і відключенням не є профільованим - лише ті функції, які він викликає. Чи маю я це право? Мені доведеться загорнути цей код у виклик функції, щоб він міг рахувати будь-яке число в print_stats ().
Боб Штейн

10

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


1
Дякую за цей дорогоцінний камінь. FYI: Це може використовуватися як окремий модуль з будь-яким кодом, база коду Virtaal не потрібна. Просто збережіть файл у profiling.py та імпортуйте профіль_func (). Використовуйте @profile_func () як декоратор для будь-яких функцій, які вам потрібні для профілю та віоли. :)
Амжіт

9

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

import cProfile
cProfile.runctx('foo()', None, locals())

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():
    ...

7

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

Встановити:

$ pip install pyinstrument

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

$ python -m pyinstrument ./prog.py

Працює з python2 та 3.

[EDIT] Документацію API, призначену для профілювання лише частини коду, можна знайти тут .


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/release або використовувати збірку, яку я зробив для Windows в репо фортованому
Містер Гіргітт,

сумісність з версією 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)}) (Гаразд після спроби пару разів вставити блок коду в коментар, який я відмовився. Це неймовірно складно для орієнтованого на програмування сайту Q&A. )
Містер Гіргітт

4

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

Він має деякі унікальні особливості, такі як

  • Приєднайте профілер до запущеної програми (CPython)
  • На замовлення профілювання з інтеграцією Yappi
  • Профіль на іншій машині
  • Підтримка декількох процесів (багатопроцесорна робота, джанго ...)
  • Живий вибірки / перегляд процесора (з вибором діапазону часу)
  • Детерміноване профілювання за допомогою інтеграції cProfile / профілю
  • Проаналізуйте існуючі результати PStats
  • Відкрийте файли DOT
  • Програматичний доступ до API
  • Групуйте зразки за методом чи лінією
  • Інтеграція PyDev
  • Інтеграція PyCharm

Примітка: вона комерційна, але безкоштовна для відкритого коду.


4

gprof2dot_magic

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

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

GitHub repo: 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')

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


3

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

Inspect 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. важкий (від проекту Guppy) використання об'єктів у купі.

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


2

При такому статистичному профіле, як Austin , ніяких інструментів не потрібно, це означає, що ви можете отримати дані профілю з програми Python просто за допомогою

austin python3 my_script.py

Невикористаний вихід не дуже корисний, але ви можете передати це на flamegraph.pl, щоб отримати представлення на графіку полум'я цих даних, який дає вам змогу визначити, де витрачається час (вимірюється в мікросекундах реального часу).

austin python3 my_script.py | flamegraph.pl > my_script_profile.svg

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


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


0

Отримання швидкої статистики профілю для фрагментів коду на ноутбуці IPython. Можна вставляти line_profiler та memory_profiler прямо у свої ноутбуки.

Отримайте!

!pip install line_profiler
!pip install memory_profiler

Завантажте!

%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 -s cumulative 'Code to profile' 

Дає:

  • кількість викликів функцій (ncalls)
  • має записи на виклик функції (окремо)
  • час, взятий за дзвінок (percall)
  • час, що минув до виклику цієї функції (час закінчення)
  • назва функції / модуля, що називається тощо ...

Сукупний профіль


% пам

%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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.