profile — Pure Python profiler¶
Source code: Lib/profile.py
Deprecated since version 3.15, will be removed in version 3.17.
The profile module is deprecated and will be removed in Python 3.17.
Use profiling.tracing instead.
The profile module provides a pure Python implementation of a
deterministic profiler. While useful for understanding profiler internals or
extending profiler behavior through subclassing, its pure Python implementation
introduces significant overhead compared to the C-based profiling.tracing
module.
For most profiling tasks, use:
profiling.samplingfor production debugging with zero overheadprofiling.tracingfor development and testing
Migration¶
Migrating from profile to profiling.tracing is straightforward.
The APIs are compatible:
# Old (deprecated)
import profile
profile.run('my_function()')
# New (recommended)
import profiling.tracing
profiling.tracing.run('my_function()')
For most code, replacing import profile with import profiling.tracing
(and using profiling.tracing instead of profile throughout) provides
a straightforward migration path.
Примітка
The cProfile module remains available as a backward-compatible alias
to profiling.tracing. Existing code using import cProfile will
continue to work without modification.
profile and profiling.tracing module reference¶
Both the profile and profiling.tracing modules provide the
following functions:
- profile.run(command, filename=None, sort=-1)¶
Ця функція приймає один аргумент, який можна передати функції
exec(), і необов’язкове ім’я файлу. У всіх випадках ця процедура виконує:exec(command, __main__.__dict__, __main__.__dict__)
і збирає статистику профілювання від виконання. Якщо ім’я файлу відсутнє, ця функція автоматично створює екземпляр
Statsі друкує простий звіт профілювання. Якщо вказано значення сортування, воно передається цьому екземпляруStatsдля керування сортуванням результатів.
- profile.runctx(command, globals, locals, filename=None, sort=-1)¶
This function is similar to
run(), with added arguments to supply the globals and locals mappings for the command string. This routine executes:exec(command, globals, locals)
і збирає статистику профілювання, як у функції
run()вище.
- class profile.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)¶
This class is normally only used if more precise control over profiling is needed than what the
profiling.tracing.run()function provides.Можна надати власний таймер для вимірювання тривалості виконання коду за допомогою аргументу timer. Це має бути функція, яка повертає одне число, що відповідає поточному часу. Якщо число є цілим числом, timeunit визначає множник, який визначає тривалість кожної одиниці часу. Наприклад, якщо таймер повертає час, виміряний у тисячах секунд, одиницею часу буде
.001.Безпосереднє використання класу
Profileдозволяє форматувати результати профілю без запису даних профілю у файл:import profiling.tracing import pstats import io from pstats import SortKey pr = profiling.tracing.Profile() pr.enable() # ... do something ... pr.disable() s = io.StringIO() sortby = SortKey.CUMULATIVE ps = pstats.Stats(pr, stream=s).sort_stats(sortby) ps.print_stats() print(s.getvalue())
The
Profileclass can also be used as a context manager (supported only inprofiling.tracing, not in the deprecatedprofilemodule; see Типи менеджера контексту):import profiling.tracing with profiling.tracing.Profile() as pr: # ... do something ... pr.print_stats()
Змінено в версії 3.8: Додано підтримку менеджера контексту.
- enable()¶
Start collecting profiling data. Only in
profiling.tracing.
- disable()¶
Stop collecting profiling data. Only in
profiling.tracing.
- create_stats()¶
Припиніть збір даних профілювання та запишіть результати внутрішньо як поточний профіль.
- print_stats(sort=-1)¶
Створіть об’єкт
Statsна основі поточного профілю та надрукуйте результати в stdout.The sort parameter specifies the sorting order of the displayed statistics. It accepts a single key or a tuple of keys to enable multi-level sorting, as in
pstats.Stats.sort_stats().Added in version 3.13:
print_stats()now accepts a tuple of keys.
- dump_stats(filename)¶
Запишіть результати поточного профілю в filename.
- runctx(cmd, globals, locals)¶
Профілюйте cmd через
exec()із зазначеним глобальним і локальним середовищем.
- runcall(func, /, *args, **kwargs)¶
Профіль
func(*args, **kwargs)
Зауважте, що профілювання працюватиме, лише якщо викликана команда/функція дійсно повернеться. Якщо інтерпретатор завершується (наприклад, через виклик sys.exit() під час виконання викликаної команди/функції), результати профілювання не друкуються.
Differences from profiling.tracing¶
The profile module differs from profiling.tracing in several
ways:
Higher overhead. The pure Python implementation is significantly slower than the C implementation, making it unsuitable for profiling long-running programs or performance-sensitive code.
Calibration support. The profile module supports calibration to
compensate for profiling overhead. This is not needed in profiling.tracing
because the C implementation has negligible overhead.
Custom timers. Both modules support custom timers, but profile
accepts timer functions that return tuples (like os.times()), while
profiling.tracing requires a function returning a single number.
Subclassing. The pure Python implementation is easier to subclass and extend for custom profiling behavior.
What is deterministic profiling?¶
Deterministic profiling is meant to reflect the fact that all function
call, function return, and exception events are monitored, and precise
timings are made for the intervals between these events (during which time the
user’s code is executing). In contrast, statistical profiling (which is
provided by the profiling.sampling module) periodically samples the
effective instruction pointer, and deduces where time is being spent. The
latter technique traditionally involves less overhead (as the code does not
need to be instrumented), but provides only relative indications of where time
is being spent.
У Python, оскільки під час виконання активний інтерпретатор, наявність інструментального коду не потрібна для виконання детермінованого профілювання. Python автоматично надає hook (додатковий зворотний виклик) для кожної події. Крім того, інтерпретована природа Python має тенденцію додавати стільки накладних витрат на виконання, що детерміноване профілювання має тенденцію лише додавати невеликі накладні витрати на обробку в типових програмах. Результатом є те, що детерміноване профілювання не таке вже й дороге, але забезпечує розширену статистику часу виконання про виконання програми Python.
Статистику кількості викликів можна використовувати для виявлення помилок у коді (несподівана кількість) і для визначення можливих точок вбудованого розширення (висока кількість викликів). Внутрішню статистику часу можна використовувати для виявлення «гарячих циклів», які слід ретельно оптимізувати. Кумулятивну статистику часу слід використовувати для виявлення помилок високого рівня у виборі алгоритмів. Зауважте, що незвичайна обробка сукупного часу в цьому профайлері дозволяє прямо порівнювати статистику для рекурсивних реалізацій алгоритмів з ітеративними реалізаціями.
Обмеження¶
Одне обмеження пов’язане з точністю інформації про час. Існує фундаментальна проблема з детермінованим профайлером, пов’язана з точністю. Найбільш очевидним обмеженням є те, що основний «годинник» цокає лише зі швидкістю (зазвичай) приблизно 0,001 секунди. Тому жодні вимірювання не будуть точнішими, ніж базовий годинник. Якщо проведено достатньо вимірювань, «похибка» матиме тенденцію до усереднення. На жаль, видалення цієї першої помилки спричиняє друге джерело помилки.
Друга проблема полягає в тому, що «потрібен деякий час» від моменту надсилання події до моменту, коли виклик профайлера для отримання часу фактично отримує стан годинника. Подібним чином існує певна затримка під час виходу з обробника подій профайлера з моменту, коли було отримано значення годинника (і потім вилучено), до моменту, коли код користувача знову виконується. У результаті функції, які викликаються багато разів або викликають багато функцій, зазвичай накопичуватимуть цю помилку. Похибка, яка накопичується таким чином, зазвичай менша, ніж точність годинника (менше одного такту), але вона може накопичуватися і стати дуже значною.
The problem is more important with the deprecated profile module than
with the lower-overhead profiling.tracing. For this reason,
profile provides a means of calibrating itself for a given platform so
that this error can be probabilistically (on the average) removed. After the
profiler is calibrated, it will be more accurate (in a least square sense), but
it will sometimes produce negative numbers (when call counts are exceptionally
low, and the gods of probability work against you :-). ) Do not be alarmed
by negative numbers in the profile. They should only appear if you have
calibrated your profiler, and the results are actually better than without
calibration.
Калібрування¶
Профайлер модуля profile віднімає константу від часу обробки кожної події, щоб компенсувати накладні витрати на виклик функції часу та накопичення результатів. За замовчуванням константа дорівнює 0. Наступну процедуру можна використати, щоб отримати кращу константу для даної платформи (див. Обмеження).
import profile
pr = profile.Profile()
for i in range(5):
print(pr.calibrate(10000))
Метод виконує кількість викликів Python, заданих аргументом, безпосередньо та знову під профайлером, вимірюючи час для обох. Потім він обчислює приховані накладні витрати на кожну подію профілювача та повертає їх як число з плаваючою точкою. Наприклад, на процесорі Intel Core i5 з тактовою частотою 1,8 ГГц, який працює під керуванням macOS і використовує Python time.process_time() як таймер, магічне число становить приблизно 4,04e-6.
Мета цієї вправи — отримати досить послідовний результат. Якщо ваш комп’ютер дуже швидкий або ваша функція таймера має низьку роздільну здатність, вам, можливо, доведеться передати 100 000 або навіть 1000 000, щоб отримати стабільні результати.
Якщо у вас є послідовна відповідь, ви можете використовувати її трьома способами:
import profile
# 1. Apply computed bias to all Profile instances created hereafter.
profile.Profile.bias = your_computed_bias
# 2. Apply computed bias to a specific Profile instance.
pr = profile.Profile()
pr.bias = your_computed_bias
# 3. Specify computed bias in instance constructor.
pr = profile.Profile(bias=your_computed_bias)
Якщо у вас є вибір, краще вибрати меншу константу, і тоді ваші результати будуть «рідше» відображатися в статистиці профілю як негативні.
Використання спеціального таймера¶
Якщо ви хочете змінити спосіб визначення поточного часу (наприклад, щоб примусово використовувати час настінного годинника або час, що минув), передайте потрібну функцію синхронізації в конструктор класу Profile:
pr = profile.Profile(your_time_func)
The resulting profiler will then call your_time_func. Depending on whether
you are using profile.Profile or profiling.tracing.Profile,
your_time_func’s return value will be interpreted differently:
профіль.Профільyour_time_funcмає повертати одне число або список чисел, сума яких є поточним часом (як те, що повертаєos.times()). Якщо функція повертає єдине число часу або список повернутих чисел має довжину 2, тоді ви отримаєте особливо швидку версію процедури відправки.Be warned that you should calibrate the profiler class for the timer function that you choose (see Калібрування). For most machines, a timer that returns a lone integer value will provide the best results in terms of low overhead during profiling. (
os.times()is pretty bad, as it returns a tuple of floating-point values). If you want to substitute a better timer in the cleanest fashion, derive a class and hardwire a replacement dispatch method that best handles your timer call, along with the appropriate calibration constant.profiling.tracing.Profileyour_time_funcмає повертати одне число. Якщо він повертає цілі числа, ви також можете викликати конструктор класу з другим аргументом, який визначає реальну тривалість однієї одиниці часу. Наприклад, якщоyour_integer_time_funcповертає час, виміряний у тисячах секунд, ви повинні створити екземплярProfileнаступним чином:pr = profiling.tracing.Profile(your_integer_time_func, 0.001)
As the
profiling.tracing.Profileclass cannot be calibrated, custom timer functions should be used with care and should be as fast as possible. For the best results with a custom timer, it might be necessary to hard-code it in the C source of the internal_lsprofmodule.
Python 3.3 додає кілька нових функцій у time, які можна використовувати для точного вимірювання часу процесу або настінного годинника. Наприклад, перегляньте time.perf_counter().
Дивись також
profilingOverview of Python profiling tools.
profiling.tracingRecommended replacement for this module.
pstatsStatistical analysis and formatting for profile data.