Содержание страницы
profiling.tracing – Детерминированный профилировщик¶profiling.tracing – Deterministic profiler
Добавлено в версии 3.15.
Исходный код: Lib/profiling/tracing/
Модуль profiling.tracing обеспечивает детерминированное профилирование программ на Python.
Он отслеживает каждый вызов функции, возврат из функции и событие исключения,
записывая точное время для каждого. Такой подход даёт точные счётчики вызовов и
полную видимость выполнения программы, что делает его идеальным для разработки и
тестирования.
Примечание
Этот модуль также доступен как cProfile для обратной совместимости.
Имя cProfile будет продолжать работать во всех будущих версиях Python.
Используйте тот стиль импорта, который подходит вашему коду:
# Рекомендуемый (новый стиль)
import profiling.tracing
profiling.tracing.run('my_function()')
# Также работает (обратная совместимость)
import cProfile
cProfile.run('my_function()')
Что такое детерминированное профилирование?¶What is deterministic profiling?
Детерминированное профилирование фиксирует каждый вызов функции, возврат из функции и событие исключения во время выполнения программы. Профилировщик измеряет точные временные интервалы между этими событиями, предоставляя точную статистику о том, как программа ведёт себя.
В отличие от статистического профилирования, которое периодически опрашивает стек вызовов для оценки затрат времени, детерминированное профилирование записывает каждое событие. Это означает, что вы получаете точные счётчики вызова, а не статистические приближения. Оборотная сторона в том, что инструментирование каждого события вносит накладные расходы, которые могут замедлить выполнение программы.
Интерпретируемая природа Python делает детерминированное профилирование практичным. Интерпретатор уже диспетчеризует события для вызовов и возвратов функций, поэтому профилировщик может подключиться к этому механизму без необходимости изменения кода. Накладные расходы обычно невелики по сравнению с внутренними затратами на интерпретацию, что делает детерминированное профилирование подходящим для большинства рабочих процессов разработки.
Детерминированное профилирование помогает ответить на такие вопросы, как:
Сколько раз была вызвана эта функция?
Каков полный граф вызовов моей программы?
Какие функции вызываются конкретной функцией?
Происходят ли неожиданные вызовы функций?
Статистика счётчиков вызовов может выявить ошибки (неожиданные значения) и возможности для встраивания (высокие счётчики вызовов). Статистика внутреннего времени показывает «горячие циклы», требующие оптимизации. Статистика кумулятивного времени помогает выявить алгоритмическую неэффективность. Обработка кумулятивного времени в этом профилировщике позволяет напрямую сравнивать рекурсивные и итеративные реализации.
Интерфейс командной строки¶Command-line interface
Модуль profiling.tracing можно вызвать как сценарий для профилирования
другого сценария или модуля:
python -m profiling.tracing [-o output_file] [-s sort_order] (-m module | script.py)
Это запускает указанный сценарий или модуль под профилировщиком и выводит результаты в стандартный вывод (или сохраняет их в файл).
- -o <output_file>¶
Записывает результаты профилирования в файл, а не в стандартный вывод. Выходной файл может быть прочитан модулем
pstatsдля последующего анализа.
- -s <sort_order>¶
Сортирует вывод по указанному ключу. Принимает любой из ключей сортировки, распознаваемых
pstats.Stats.sort_stats(), таких какcumulative,time,callsилиname. Этот параметр применяется только если-oне указан.
Примеры программного использования¶Programmatic usage examples
Для более тонкого управления профилированием используйте функции и классы модуля напрямую.
Основное профилирование¶Basic profiling
Самый простой подход – использовать функцию run():
import profiling.tracing
profiling.tracing.run('my_function()')
Это профилирует переданную строку кода и выводит сводку в стандартный вывод. Чтобы сохранить результаты для последующего анализа:
profiling.tracing.run('my_function()', 'output.prof')
Использование Profile класса¶Using the Profile class
Класс Profile обеспечивает детальный контроль:
import profiling.tracing
import pstats
from io import StringIO
pr = profiling.tracing.Profile()
pr.enable()
# ... код для профилирования ...
pr.disable()
# Вывести результаты
s = StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats(pstats.SortKey.CUMULATIVE)
ps.print_stats()
print(s.getvalue())
Класс Profile также работает как менеджер контекста:
import profiling.tracing
with profiling.tracing.Profile() as pr:
# ... код для профилирования ...
pr.print_stats()
Справочник модуля ¶Module reference
- profiling.tracing.run(command, filename=None, sort=-1)¶
Профилирует выполнение команды и выводит или сохраняет результаты.
Эта функция выполняет строку command с помощью
exec()в пространстве имён модуля__main__:exec(command, __main__.__dict__, __main__.__dict__)
Если filename не указан, функция создаёт экземпляр
pstats.Statsи выводит сводку в стандартный вывод. Если filename указан, необработанные данные профиля сохраняются в этот файл для последующего анализа с помощьюpstats.Аргумент sort задаёт порядок сортировки для выводимых данных, принимая любое значение, распознаваемое
pstats.Stats.sort_stats().
- profiling.tracing.runctx(command, globals, locals, filename=None, sort=-1)¶
Профилирует выполнение команды с явными пространствами имён.
Как
run(), но выполняет команду с указанными отображениями globals и locals вместо использования пространства имён модуля__main__:exec(command, globals, locals)
- class profiling.tracing.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)¶
Объект профилировщика, собирающий статистику выполнения.
Необязательный аргумент timer задаёт пользовательскую функцию замера времени. Если он не указан, профилировщик использует таймер по умолчанию, подходящий для платформы. При передаче пользовательского таймера он должен возвращать одно число, представляющее текущее время. Если таймер возвращает целые числа, используйте timeunit, чтобы указать длительность одной единицы времени (например,
0.001для миллисекунд).Аргумент subcalls управляет тем, отслеживает ли профилировщик отношения вызовов между функциями. Аргумент builtins управляет тем, профилируются ли встроенные функции.
Изменено в версии 3.8: Добавлена поддержка контекстного менеджера.
- enable()¶
Начинает сбор данных профилирования.
- disable()¶
Прекращает сбор данных профилирования.
- create_stats()¶
Прекращает сбор данных и сохраняет результаты внутри как текущий профиль.
- print_stats(sort=-1)¶
Создаёт объект
pstats.Statsиз текущего профиля и выводит результаты в стандартный вывод.Аргумент sort задаёт порядок сортировки. Он принимает один ключ или кортеж ключей для многоуровневой сортировки, используя те же значения, что и
pstats.Stats.sort_stats().Добавлено в версии 3.13: Поддержка кортежа ключей сортировки.
- dump_stats(filename)¶
Записывает текущие данные профиля в filename. Файл может быть прочитан с помощью
pstats.Statsдля последующего анализа.
- runctx(cmd, globals, locals)¶
Профилирует строку команды с помощью
exec()с указанными пространствами имён.
- runcall(func, /, *args, **kwargs)¶
Профилирует вызов функции. Возвращает то, что возвращает func:
result = pr.runcall(my_function, arg1, arg2, keyword=value)
Примечание
Для профилирования необходимо, чтобы профилируемый код завершился нормально. Если интерпретатор завершится (например, через sys.exit()) во время профилирования, результаты получены не будут.
Использование пользовательского таймера¶Using a custom timer
Класс Profile принимает пользовательскую функцию таймера, позволяя измерять различные аспекты выполнения, такие как реальное время (wall-clock time) или процессорное время. Передайте функцию таймера в конструктор:
pr = profiling.tracing.Profile(my_timer_function)
Функция таймера должна возвращать одно число, представляющее текущее время. Если она возвращает целые числа, также укажите timeunit, чтобы указать продолжительность одной единицы:
# Таймер возвращает время в миллисекундах
pr = profiling.tracing.Profile(my_ms_timer, 0.001)
Для наилучшей производительности функция таймера должна быть как можно быстрее. Профилировщик вызывает её часто, поэтому накладные расходы таймера напрямую влияют на накладные расходы профилирования.
Модуль time предоставляет несколько функций, подходящих для использования в качестве пользовательских таймеров:
time.perf_counter()для астрономического времени (высокое разрешение)time.process_time()для процессорного времени (без учёта сна)time.monotonic()для монотонного времени
Ограничения¶Limitations
Детерминированное профилирование имеет внутренние ограничения, связанные с точностью измерения времени.
Базовый таймер обычно имеет разрешение около одной миллисекунды. Измерения не могут быть точнее этого разрешения. При достаточном количестве измерений ошибки синхронизации обычно усредняются, но отдельные измерения могут быть неточными.
Существует также задержка между моментом возникновения события и моментом захвата временной метки профилировщиком. Аналогично, после чтения временной метки есть задержка, прежде чем пользовательский код возобновит выполнение. Часто вызываемые функции накапливают эту задержку, из-за чего они могут казаться медленнее, чем на самом деле. Эта ошибка обычно составляет менее одного тика часов на вызов, но может стать значительной для функций, вызываемых многократно.
Модуль profiling.tracing (и его псевдоним cProfile) реализован как расширение на C с низкими накладными расходами, поэтому эти проблемы синхронизации менее заметны по сравнению с устаревшим чисто Python-модулем profile.
См. также
profilingОбзор инструментов профилирования Python и рекомендации по выбору профилировщика.
profiling.samplingСтатистический профилировщик с выборкой для использования в production.
pstatsАнализ статистики и форматирование данных профилирования.
profileУстаревший чисто Python-профилировщик (включает документацию по калибровке).