"profile" --- Pure Python profiler
**********************************

**Source code:** Lib/profile.py

======================================================================

バージョン 3.15 で非推奨、バージョン 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.

注釈:

  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" のインスタンスが自動的に作られ、簡単なプ
   ロファイルレポートが表示されます。 *sort* が指定されている場合は、
   "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* には単位
   時間当たりの実際の持続時間を指定します。たとえば関数が 1000 分の 1
   秒単位で計測した時間を返すとすると、 *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 "Profile" class can also be used as a context manager
   (supported only in "profiling.tracing", not in the deprecated
   "profile" module; 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" オブジェクトを作成し、結果
      を標準出力に出力します。

      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* に書き出します。

   run(cmd)

      "exec()" を用いて cmd をプロファイルします。

   runctx(cmd, globals, locals)

      "exec()" を用いて指定されたグローバルおよびローカルな環境で cmd
      をプロファイルします。

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

      "func(*args, **kwargs)" をプロファイルします。

Note that profiling will only work if the called command/function
actually returns.  If the interpreter is terminated (e.g. via a
"sys.exit()" call during the called command/function execution) no
profiling results will be printed.


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 は自動的に各イベントに *フック* (オプションのコールバック) を提
供します。加えて Python のインタプリタという性質によって、実行時に大き
なオーバーヘッドを伴う傾向がありますが、それに比べると一般的なアプリケ
ーションでは決定論的プロファイリングで追加される処理のオーバーヘッドは
少ない傾向にあります。結果的に、決定論的プロファイリングは少ないコスト
で Python プログラムの実行時間に関する詳細な統計を得られる方法となって
いるのです。

呼び出し回数はコード中のバグ発見にも使用できます (とんでもない数の呼び
出しが行われている部分)。インライン拡張の対象とすべき部分を見つけるた
めにも使えます (呼び出し頻度の高い部分)。内部時間の統計は、注意深く最
適化すべき"ホットループ"の発見にも役立ちます。累積時間の統計は、アルゴ
リズム選択に関連した高レベルのエラー検知に役立ちます。なお、このプロフ
ァイラは再帰的なアルゴリズム実装の累計時間を計ることが可能で、通常のル
ープを使った実装と直接比較することもできるようになっています。


制限事項
========

一つの制限はタイミング情報の正確さに関するものです。決定論的プロファイ
ラには正確さに関する根本的問題があります。最も明白な制限は、 (一般に)
"クロック"は .001 秒の精度しかないということです。これ以上の精度で計測
することはできません。仮に充分な精度が得られたとしても、"誤差"が計測の
平均値に影響を及ぼすことがあります。この最初の誤差を取り除いたとしても
、それがまた別の誤差を引き起こす原因となります。

もう一つの問題として、イベントを検知してからプロファイラがその時刻を実
際に *取得* するまでに "いくらかの時間がかかる" ことです。同様に、イベ
ントハンドラが終了する時にも、時刻を取得して (そしてその値を保存して)
から、ユーザコードが処理を再開するまでの間に遅延が発生します。結果的に
多く呼び出される関数または多数の関数から呼び出される関数の情報にはこの
種の誤差が蓄積する傾向にあります。このようにして蓄積される誤差は、典型
的にはクロックの精度を下回ります (1クロック以下) が、一方でこの時間が
累計して非常に大きな値になることも *あり得ます* 。

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.


キャリブレーション (補正)
=========================

The profiler of the "profile" module subtracts a constant from each
event handling time to compensate for the overhead of calling the time
function, and socking away the results.  By default, the constant is
0. The following procedure can be used to obtain a better constant for
a given platform (see 制限事項).

   import profile
   pr = profile.Profile()
   for i in range(5):
       print(pr.calibrate(10000))

calibrate メソッドは引数として与えられた数だけ Python の呼び出しを行い
ます。直接呼び出す場合と、プロファイラを使って呼び出す場合の両方が実施
され、それぞれの時間が計測されます。その結果、プロファイラのイベントに
隠されたオーバーヘッドが計算され、その値は浮動小数として返されます。た
とえば、 1.8 GHz の Intel Core i5 で macOS を使用、 Python の
time.process_time() をタイマとして使った場合、値はおよそ 4.04e-6 とな
ります。

この手順で使用しているオブジェクトはほぼ一定の結果を返します。 *非常に
* 早いコンピュータを使う場合、もしくはタイマの性能が貧弱な場合は、一定
の結果を得るために引数に 100000 や 1000000 といった大きな値を指定する
必要があるかもしれません。

一定の結果が得られたら、それを使う方法には3通りあります:

   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:

"profile.Profile"
   "your_time_func()" は単一の数値、あるいは ("os.times()" と同じよう
   に) その合計が累計時間を示すリストを返すようになっていなければなり
   ません。関数が1つの数値、あるいは長さ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.Profile"
   "your_time_func()" は単一の数値を返すようになっていなければなりませ
   ん。単一の整数を返すのであれば、クラスコンストラクタの第二引数に単
   位時間当たりの実際の持続時間を渡せます。例えば
   "your_integer_time_func" が 1000 分の 1 秒単位で計測した時間を返す
   とすると、 "Profile" インスタンスを以下のように構築出来ます:

      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 で "time" に、プロセス時間や実時間の精密な計測に使える新し
い関数が追加されました。 例えば、 "time.perf_counter()" を参照してくだ
さい。

参考:

  "profiling"
     Overview of Python profiling tools.

  "profiling.tracing"
     Recommended replacement for this module.

  "pstats"
     Statistical analysis and formatting for profile data.
