"profiling.tracing" --- 确定型性能分析器
****************************************

Added in version 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()')


什么是确定型性能分析？
======================

*确定型性能分析* 会捕获程序运行期间的每个函数调用、函数返回以及异常事
件。 性能分析器将计量这些事件所用时间的精确间隔，提供有关程序行为的准
确统计信息。

与定期对调用栈进行采样来计算耗时的 统计型性能分析 不同，确定型性能分析
会记录每个事件。 这意味着你将获得准确的调用计数而不是统计近似值。 这种
方式的代价是记录每个事件会引入可能减慢程序执行速度的额外开销。

Python 的解释型性质使得确定型性能分析是可行的。 解释器已经针对函数调用
与返回发送事件，因此性能分析器可以利用这一机制设置钩子而无需修改代码。
增加的开销相对于固有的解释消耗是有限的，使得确定型性能分析适用于大多数
开发流程。

确定型性能分析有助于解答这样的问题：Deterministic profiling helps
answer questions like:

* 这个函数调用花费了多少时间？

* 我的程序的完整调用图景是怎样的？

* Which functions are called by a particular function?

* Are there unexpected function calls happening?

Call count statistics can identify bugs (surprising counts) and inline
expansion opportunities (high call counts). Internal time statistics
reveal "hot loops" that warrant optimization. Cumulative time
statistics help identify algorithmic inefficiencies. The handling of
cumulative times in this profiler allows direct comparison of
recursive and iterative implementations.


命令行接口
==========

"profiling.tracing" 模块可以作为脚本被唤起以分析另一个脚本或模块：

   python -m profiling.tracing [-o output_file] [-s sort_order] (-m module | script.py)

这将在性能分析器中运行指定的脚本或模块并将结果打印到标准输出（或将其保
存到文件）。

-o <output_file>

   将性能分析结果写入文件而不是标准输出。 输出文件可由 "pstats" 模块读
   取供后续分析。

-s <sort_order>

   Sort the output by the specified key. This accepts any of the sort
   keys recognized by "pstats.Stats.sort_stats()", such as
   "cumulative", "time", "calls", or "name". This option only applies
   when "-o" is not specified.

-m <module>

   Profile a module instead of a script. The module is located using
   the standard import mechanism.

   Added in version 3.7: 用于 "cProfile" 的 "-m" 选项。

   Added in version 3.8: 用于 "profile" 的 "-m" 选项。


编程使用示例
============

要对性能分析进行更多控制，请直接使用此模块的函数和类。


基本性能分析
------------

The simplest approach uses the "run()" function:

   import profiling.tracing
   profiling.tracing.run('my_function()')

This profiles the given code string and prints a summary to standard
output. To save results for later analysis:

   profiling.tracing.run('my_function()', 'output.prof')


使用 "Profile" 类
-----------------

"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()


模块参考
========

profiling.tracing.run(command, filename=None, sort=-1)

   执行一条命令分析性能并打印或保存结果。

   此函数会在 "__main__" 模块的命名空间中使用 "exec()" 执行 *command*
   字符串:

      exec(command, __main__.__dict__, __main__.__dict__)

   If *filename* is not provided, the function creates a
   "pstats.Stats" instance and prints a summary to standard output. If
   *filename* is provided, the raw profile data is saved to that file
   for later analysis with "pstats".

   The *sort* argument specifies the sort order for printed output,
   accepting any value recognized by "pstats.Stats.sort_stats()".

profiling.tracing.runctx(command, globals, locals, filename=None, sort=-1)

   Profile execution of a command with explicit namespaces.

   Like "run()", but executes the command with the specified *globals*
   and *locals* mappings instead of using the "__main__" module's
   namespace:

      exec(command, globals, locals)

class profiling.tracing.Profile(timer=None, timeunit=0.0, subcalls=True, builtins=True)

   负责收集执行统计信息的性能分析对象。

   The optional *timer* argument specifies a custom timing function.
   If not provided, the profiler uses a platform-appropriate default
   timer. When supplying a custom timer, it must return a single
   number representing the current time. If the timer returns
   integers, use *timeunit* to specify the duration of one time unit
   (for example, "0.001" for milliseconds).

   The *subcalls* argument controls whether the profiler tracks call
   relationships between functions. The *builtins* argument controls
   whether built-in functions are profiled.

   在 3.8 版本发生变更: 添加了上下文管理器支持。

   enable()

      开始收集性能分析数据。

   disable()

      Stop collecting profiling data.

   create_stats()

      Stop collecting data and record the results internally as the
      current profile.

   print_stats(sort=-1)

      Create a "pstats.Stats" object from the current profile and
      print the results to standard output.

      The *sort* argument specifies the sorting order. It accepts a
      single key or a tuple of keys for multi-level sorting, using the
      same values as "pstats.Stats.sort_stats()".

      Added in version 3.13: Support for a tuple of sort keys.

   dump_stats(filename)

      Write the current profile data to *filename*. The file can be
      read by "pstats.Stats" for later analysis.

   run(cmd)

      Profile the command string via "exec()".

   runctx(cmd, globals, locals)

      Profile the command string via "exec()" with the specified
      namespaces.

   runcall(func, /, *args, **kwargs)

      Profile a function call. Returns whatever *func* returns:

         result = pr.runcall(my_function, arg1, arg2, keyword=value)

备注:

  Profiling requires that the profiled code returns normally. If the
  interpreter terminates (for example, via "sys.exit()") during
  profiling, no results will be available.


使用自定义计时器
================

The "Profile" class accepts a custom timing function, allowing you to
measure different aspects of execution such as wall-clock time or CPU
time. Pass the timing function to the constructor:

   pr = profiling.tracing.Profile(my_timer_function)

The timer function must return a single number representing the
current time. If it returns integers, also specify *timeunit* to
indicate the duration of one unit:

   # Timer returns time in milliseconds
   pr = profiling.tracing.Profile(my_ms_timer, 0.001)

For best performance, the timer function should be as fast as
possible. The profiler calls it frequently, so timer overhead directly
affects profiling overhead.

The "time" module provides several functions suitable for use as
custom timers:

* "time.perf_counter()" for high-resolution wall-clock time

* "time.process_time()" for CPU time (excluding sleep)

* "time.monotonic()" for monotonic clock time


局限性
======

Deterministic profiling has inherent limitations related to timing
accuracy.

The underlying timer typically has a resolution of about one
millisecond. Measurements cannot be more accurate than this
resolution. With enough measurements, timing errors tend to average
out, but individual measurements may be imprecise.

There is also latency between when an event occurs and when the
profiler captures the timestamp. Similarly, there is latency after
reading the timestamp before user code resumes. Functions called
frequently accumulate this latency, which can make them appear slower
than they actually are. This error is typically less than one clock
tick per call but can become significant for functions called many
times.

The "profiling.tracing" module (and its "cProfile" alias) is
implemented as a C extension with low overhead, so these timing issues
are less pronounced than with the deprecated pure Python "profile"
module.

参见:

  "profiling"
     Python 性能分析工具概览和性能分析器选择指南。

  "profiling.sampling"
     Statistical sampling profiler for production use.

  "pstats"
     性能分析数据的统计分析和格式化。

  "profile"
     Deprecated pure Python profiler (includes calibration
     documentation).
