"profiling" --- Python のプロファイラ
*************************************

Added in version 3.15.

**ソースコード:** Lib/profiling/

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


プロファイリングの概要
======================

*プロファイル* は、プログラムの各部分が何回、どれだけの時間実行された
かを示す統計情報です。 この情報は、性能上のボトルネックを特定し、最適
化の方針を決めるのに役立ちます。 Python は、この情報を収集するために、
根本的に異なる二つの方法を提供しています。 統計的サンプリングと決定論
的トレースです。

"profiling" パッケージは、Python に組み込まれたプロファイリングツール
を一つの名前空間にまとめます。 異なるプロファイリング手法を実装する、
次の二つのサブモジュールを含みます。

"profiling.sampling"
   コールスタックを定期的にサンプリングする統計的プロファイラです。 ス
   クリプトを直接実行したり、PID を指定して実行中のプロセスに接続した
   りできます。 ほぼオーバーヘッドなしで、複数の出力形式 (フレームグラ
   フ、ヒートマップ、Firefox Profiler)、GIL の分析、GC の追跡、複数の
   プロファイリングモード (実時間、CPU、GIL) を提供します。

"profiling.tracing"
   A deterministic profiler that traces every function call, return,
   and exception event. Provides exact call counts and precise timing
   information, capturing every invocation including very fast
   functions.

注釈:

  プロファイラのモジュールは、プログラムの実行プロファイルを得るための
  もので、ベンチマークを目的としていません。 ベンチマークには、十分に
  正確な時間計測ができる "timeit" モジュールを使ってください。 Python
  のコードと C のコードを比較する際は、この違いが特に重要です。 決定論
  的プロファイラは Python のコードにオーバーヘッドを加えますが、C レベ
  ルの関数には加えないため、比較結果が偏る可能性があります。


プロファイラの選択
==================

ほとんどの性能分析では、統計的プロファイラ ("profiling.sampling") を使
ってください。 オーバーヘッドが非常に小さく、開発環境と本番環境の両方
で使えます。 また、フレームグラフ、ヒートマップ、GIL 分析など、豊富な
可視化機能を提供します。

**正確な呼び出し回数** が必要で、関数呼び出しを一つも見逃せない場合は
、決定論的プロファイラ ("profiling.tracing") を使ってください。 すべて
の関数呼び出しと復帰を計測するため、サンプリング間隔の間に完了する非常
に短い関数も記録できます。 その代わり、オーバーヘッドは大きくなります
。

主な違いを次の表にまとめます。

+----------------------+--------------------------------+--------------------------------+
| 機能                 | 統計的サンプリング             | 決定論的プロファイリング       |
|                      | ("profiling.sampling")         | ("profiling.tracing")          |
|======================|================================|================================|
| **オーバーヘッド**   | ほぼなし                       | 中程度                         |
+----------------------+--------------------------------+--------------------------------+
| **精度**             | 統計的な推定                   | 正確な呼び出し回数             |
+----------------------+--------------------------------+--------------------------------+
| **出力形式**         | pstats、フレームグラフ、ヒート | pstats                         |
|                      | マップ、gecko、collapsed       |                                |
+----------------------+--------------------------------+--------------------------------+
| **プロファイリングモ | 実時間、CPU、GIL               | 実時間                         |
| ード**               |                                |                                |
+----------------------+--------------------------------+--------------------------------+
| **特殊なフレーム**   | GC、ネイティブ (C 拡張)        | N/A                            |
+----------------------+--------------------------------+--------------------------------+
| **PID を指定した接続 | 可                             | 不可                           |
| **                   |                                |                                |
+----------------------+--------------------------------+--------------------------------+


統計的サンプリングを使う場面
----------------------------

ほとんどの性能分析では、統計的プロファイラ ("profiling.sampling") を推
奨します。 "profiling.tracing" と同じように使えます。

   python -m profiling.sampling run script.py

サンプリングプロファイラの大きな特長の一つは、出力形式が多彩なことです
。 従来の pstats の表に加え、呼び出し階層を可視化する対話的なフレーム
グラフ、コードのどの行に時間がかかっているかを示すソースコードのヒート
マップ、タイムラインに沿って分析するための Firefox Profiler 形式の出力
を生成できます。

また、決定論的プロファイリングでは捉えられない Python インタープリタの
動作も調べられます。 "--mode gil" でマルチスレッドのコードの GIL 競合
を特定し、"--mode cpu" で I/O 待ちを除いた実際の CPU 時間を計測できま
す。 また、"<GC>" フレームを調べると、ガベージコレクションのオーバーヘ
ッドを把握できます。 "--native" オプションは C 拡張内で費やした時間を
示し、Python のオーバーヘッドとライブラリの性能を区別するのに役立ちま
す。

マルチスレッドのアプリケーションでは、"-a" オプションで全スレッドを同
時にサンプリングし、処理の分担を確認できます。 本番環境のデバッグでは
、"attach" コマンドで PID を指定し、再起動やコードの変更なしに実行中の
Python プロセスへ接続できます。


決定論的トレースを使う場面
--------------------------

決定論的プロファイラ ("profiling.tracing") は、すべての関数呼び出しと
復帰を計測します。 サンプリングよりもオーバーヘッドは大きくなりますが
、プログラムの実行を漏れなく記録できます。

決定論的トレースを選ぶ主な理由は、正確な呼び出し回数が必要な場合です。
統計的プロファイリングはサンプリングから頻度を推定するため、サンプル間
で終了する短い関数の回数を少なく見積もることがあります。 最適化によっ
て関数呼び出しが実際に減ったかを確認したい場合や、呼び出しグラフ全体を
追跡して呼び出し元と呼び出し先の関係を理解したい場合は、決定論的トレー
スが適しています。

決定論的トレースは、マイクロ秒単位で実行される関数の記録にも優れていま
す。 そのような関数は統計的なサンプルに十分な頻度で現れない可能性があ
りますが、決定論的トレースは実行時間に関係なくすべての呼び出しを記録し
ます。


クイックスタート
================

この節では、プロファイリングを始めるために必要な最小限の手順を示します
。 詳しい説明は、各プロファイラの専用ページを参照してください。


統計的プロファイリング
----------------------

スクリプトをプロファイルするには、"profiling.sampling" モジュールの
"run" コマンドを使います。

   python -m profiling.sampling run script.py
   python -m profiling.sampling run -m mypackage.module

これにより、プロファイラの下でスクリプトを実行し、どこで時間を使ったか
の概要を表示します。 対話的なフレームグラフを生成するには、次のように
します。

   python -m profiling.sampling run --flamegraph script.py

すでに実行中のプロセスをプロファイルするには、"attach" コマンドにプロ
セス ID を指定します。

   python -m profiling.sampling attach 1234

設定を変更するには、サンプリング間隔 (マイクロ秒) と計測時間 (秒) を指
定します。

   python -m profiling.sampling run -i 50 -d 30 script.py


決定論的プロファイリング
------------------------

コマンドラインからスクリプトをプロファイルするには、次のようにします。

   python -m profiling.tracing script.py

プログラムからコードの一部をプロファイルするには、次のようにします。

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

指定したコードをプロファイラの下で実行し、正確な関数呼び出し回数と時間
の概要を表示します。


プロファイル出力の読み方
========================

どちらのプロファイラも関数単位の統計を収集しますが、表示形式が異なりま
す。 サンプリングプロファイラには複数の可視化形式 (フレームグラフ、ヒ
ートマップ、Firefox Profiler、pstats の表) があり、決定論的プロファイ
ラは pstats 互換の出力を生成します。 形式によらず、基本的な概念は同じ
です。

プロファイリングの主な概念は次のとおりです。

**直接時間** (*self time* または *tottime* とも呼びます)
   呼び出し先の関数で費やした時間を除き、関数自身のコードを実行した時
   間です。 直接時間が長ければ、その関数に時間のかかる処理が含まれてい
   ることを示します。

**累積時間** (*total time* または *cumtime* とも呼びます)
   その関数と、そこから呼び出したすべての関数で費やした時間です。 呼び
   出し先の部分木全体を含めた、関数呼び出しの総コストを表します。

**呼び出し回数** (*ncalls* または *samples* とも呼びます)
   関数を呼び出した回数 (決定論的プロファイリング)、またはサンプリング
   した回数 (統計的プロファイリング) です。 決定論的プロファイリングで
   は正確な回数です。 統計的プロファイリングでは、その関数がスタックの
   サンプルに現れた回数を表します。

**プリミティブな呼び出し**
   再帰によって生じたものではない呼び出しです。 関数が再帰する場合、総
   呼び出し回数には再帰呼び出しも含みますが、プリミティブな呼び出しに
   は最初の呼び出しだけを数えます。 "総呼び出し回数/プリミティブな呼び
   出し回数" の形で表示します (例えば "3/1" は、総呼び出し回数が 3 回
   、プリミティブな呼び出しが 1 回であることを表します)。

**呼び出し元と呼び出し先の関係**
   ある関数をどの関数が呼び出したか (呼び出し元)、その関数がどの関数を
   呼び出したか (呼び出し先) を示します。 フレームグラフでは入れ子の長
   方形で可視化し、pstats では "print_callers()" と "print_callees()"
   メソッドで表示できます。


従来のコードとの互換性
======================

後方互換性のため、"cProfile" モジュールは "profiling.tracing" の別名と
して引き続き利用できます。 "import cProfile" を使う既存のコードは、今
後のすべての Python バージョンで変更せずに動作します。

バージョン 3.15 で非推奨: 純粋な Python による "profile" モジュールは
非推奨で、Python 3.17 で削除されます。 代わりに "profiling.tracing" (
またはその別名 "cProfile") を使ってください。 移行については "profile"
を参照してください。

参考:

  "profiling.sampling"
     フレームグラフ、ヒートマップ、GIL 分析を備えた統計的サンプリング
     プロファイラです。 ほとんどのユーザに推奨します。

  "profiling.tracing"
     正確な呼び出し回数を取得するための決定論的トレースプロファイラで
     す。

  "pstats"
     プロファイルデータの統計分析と整形。

  "timeit"
     短いコードの実行時間を測定するモジュールです。

-[ サブモジュール ]-

* "profiling.tracing" --- 決定論的プロファイラ

* "profiling.sampling" --- 統計的プロファイラ
