# `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.sampling` for production debugging with zero overhead

- `profiling.tracing` for 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 `Stats` e imprime un informe de perfil simple. Si se especifica el valor de clasificación, se pasa a esta instancia `Stats` para 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 `Profile` permite 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 `Profile` class can also be used as a context manager (supported only in `profiling.tracing`, not in the deprecated `profile` module; 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 `Stats` en 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.

  run(cmd)

    Perfila el cmd a través de `exec()`.

  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.Profile`

  `your_time_func` debería retornar un solo número o una lista de números cuya suma es la hora actual (como lo que `os.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.Profile`

  `your_time_func` deberí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, si `your_integer_time_func` retorna tiempos medidos en miles de segundos, construiría la instancia `Profile` de la siguiente manera:

      pr = profiling.tracing.Profile(your_integer_time_func, 0.001)

  As the `profiling.tracing.Profile` class 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 `_lsprof` module.

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

`profiling`

  Overview of Python profiling tools.

`profiling.tracing`

  Recommended replacement for this module.

`pstats`

  Statistical analysis and formatting for profile data.