Документация Python неофициальный перевод
Содержание страницы

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 не указан.

-m <module>

Профилирует модуль вместо сценария. Модуль находится с помощью стандартного механизма импорта.

Добавлено в версии 3.7: Параметр -m для cProfile.

Добавлено в версии 3.8: Параметр -m для profile.

Примеры программного использования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 для последующего анализа.

run(cmd)

Профилирует строку команды с помощью exec().

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-профилировщик (включает документацию по калибровке).