"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.
