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.
Nota
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)¶
Esta función toma un único argumento que se puede pasar a la función
exec()y un nombre de archivo opcional. En todos los casos esta rutina ejecuta:exec(command, __main__.__dict__, __main__.__dict__)
y recopila estadísticas de perfiles de la ejecución. Si no hay ningún nombre de archivo, esta función crea automáticamente una instancia de
Statse imprime un informe de perfil simple. Si se especifica el valor de clasificación, se pasa a esta instanciaStatspara controlar cómo se ordenan los resultados.
- 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)
y recopila estadísticas de perfiles como en la función
run()anterior.
- 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.Se puede suministrar un temporizador personalizado para medir cuánto tiempo tarda el código en ejecutarse mediante el argumento timer. Esta debe ser una función que retorna un solo número que representa la hora actual. Si el número es un entero, la timeunit especifica un multiplicador que especifica la duración de cada unidad de tiempo. Por ejemplo, si el temporizador retorna tiempos medidos en miles de segundos, la unidad de tiempo sería
.001.El uso directo de la clase
Profilepermite formatear los resultados del perfil sin escribir los datos del perfil en un archivo: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 Tipos gestores de contexto):import profiling.tracing with profiling.tracing.Profile() as pr: # ... do something ... pr.print_stats()
Distinto en la versión 3.8: Se agregó soporte de administrador de contexto.
- enable()¶
Start collecting profiling data. Only in
profiling.tracing.
- disable()¶
Stop collecting profiling data. Only in
profiling.tracing.
- create_stats()¶
Deja de recopilar datos de perfiles y registre los resultados internamente como el perfil actual.
- print_stats(sort=-1)¶
Crea un objeto
Statsen función del perfil actual e imprima los resultados en 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)¶
Escribe los resultados del perfil actual en filename.
- runctx(cmd, globals, locals)¶
Perfila el cmd a través de
exec()con el entorno global y local especificado.
- runcall(func, /, *args, **kwargs)¶
Perfila
func(*args, **kwargs)
Tenga en cuenta que la creación de perfiles solo funcionará si el comando/función llamado realmente regresa. Si el intérprete se termina (por ejemplo, a través de una llamada a sys.exit() durante la ejecución del comando/función llamado) no se imprimirán resultados de generación de perfiles.
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.
En Python, dado que hay un intérprete activo durante la ejecución, no se requiere la presencia de código instrumentado para realizar un perfil determinista. Python proporciona automáticamente un hook (retrollamada opcional) para cada evento. Además, la naturaleza interpretada de Python tiende a agregar tanta sobrecarga a la ejecución, que los perfiles deterministas tienden a agregar solo una pequeña sobrecarga de procesamiento en aplicaciones típicas. El resultado es que el perfil determinista no es tan costoso, pero proporciona estadísticas extensas de tiempo de ejecución sobre la ejecución de un programa Python.
Las estadísticas de recuento de llamadas se pueden usar para identificar errores en el código (recuentos sorprendentes) e identificar posibles puntos de expansión en línea (recuentos altos de llamadas). Las estadísticas de tiempo interno se pueden utilizar para identificar «bucles activos» que deben optimizarse cuidadosamente. Las estadísticas de tiempo acumulativo deben usarse para identificar errores de alto nivel en la selección de algoritmos. Tenga en cuenta que el manejo inusual de los tiempos acumulativos en este generador de perfiles permite que las estadísticas de implementaciones recursivas de algoritmos se comparen directamente con implementaciones iterativas.
Limitaciones¶
Una limitación tiene que ver con la precisión de la información de sincronización. Hay un problema fundamental con los perfiladores deterministas que implican precisión. La restricción más obvia es que el «reloj» subyacente solo funciona a una velocidad (típicamente) de aproximadamente 0,001 segundos. Por lo tanto, ninguna medición será más precisa que el reloj subyacente. Si se toman suficientes medidas, entonces el «error» tenderá a promediar. Desafortunadamente, eliminar este primer error induce una segunda fuente de error.
El segundo problema es que «lleva un tiempo» desde que se distribuye un evento hasta que la llamada del generador de perfiles para obtener la hora en realidad obtiene el estado del reloj. Del mismo modo, hay un cierto retraso al salir del controlador de eventos del generador de perfiles desde el momento en que se obtuvo el valor del reloj (y luego se retiró), hasta que el código del usuario se está ejecutando nuevamente. Como resultado, las funciones que se llaman muchas veces, o llaman a muchas funciones, generalmente acumularán este error. El error que se acumula de esta manera es típicamente menor que la precisión del reloj (menos de un tic de reloj), pero puede acumularse y volverse muy significativo.
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.
Calibración¶
El generador de perfiles del módulo profile resta una constante de cada tiempo de manejo de eventos para compensar la sobrecarga de llamar a la función de tiempo y eliminar los resultados. Por defecto, la constante es 0. El siguiente procedimiento se puede usar para obtener una mejor constante para una plataforma dada (ver Limitaciones).
import profile
pr = profile.Profile()
for i in range(5):
print(pr.calibrate(10000))
El método ejecuta la cantidad de llamadas de Python dadas por el argumento, directamente y nuevamente bajo el generador de perfiles, midiendo el tiempo para ambos. Luego, calcula la sobrecarga oculta por evento del generador de perfiles y la retorna como un valor flotante. Por ejemplo, en un Intel Core i5 de 1.8Ghz que ejecuta macOS y usa el time.process_time () de Python como temporizador, el número mágico es aproximadamente 4.04e-6.
El objetivo de este ejercicio es obtener un resultado bastante consistente. Si su computadora es muy rápida, o su función de temporizador tiene una resolución pobre, es posible que tenga que pasar 100000, o incluso 1000000, para obtener resultados consistentes.
Cuando tiene una respuesta consistente, hay tres formas de usarla:
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)
Si tiene una opción, es mejor que elija una constante más pequeña, y luego sus resultados «con menos frecuencia» se mostrarán como negativos en las estadísticas del perfil.
Usando un temporizador personalizado¶
Si desea cambiar la forma en que se determina el tiempo actual (por ejemplo, para forzar el uso del tiempo del reloj de pared o el tiempo transcurrido del proceso), pase la función de temporización que desee a la clase constructora 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:
profile.Profileyour_time_funcdebería retornar un solo número o una lista de números cuya suma es la hora actual (como lo queos.times()retorna). Si la función retorna un número de tiempo único o la lista de números retornados tiene una longitud de 2, obtendrá una versión especialmente rápida de la rutina de envío.Be warned that you should calibrate the profiler class for the timer function that you choose (see Calibración). 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_funcdebería retornar un solo número. Si retorna enteros, también puede invocar al constructor de la clase con un segundo argumento que especifique la duración real de una unidad de tiempo. Por ejemplo, siyour_integer_time_funcretorna tiempos medidos en miles de segundos, construiría la instanciaProfilede la siguiente manera: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 agrega varias funciones nuevas en time que se puede usar para realizar mediciones precisas del proceso o el tiempo del reloj de pared (wall-clock time). Por ejemplo, vea time.perf_counter().
Ver también
profilingOverview of Python profiling tools.
profiling.tracingRecommended replacement for this module.
pstatsStatistical analysis and formatting for profile data.