Python スクリプトをランダムな時間実行し、一時停止し、スタック トレースバックを取得して、一時停止を解除する必要があります。これを行う方法をグーグルで調べましたが、明らかな解決策はありません。
8 に答える
pip install statprof
(またはeasy_install statprof
)、次に使用します。
import statprof
statprof.start()
try:
my_questionable_function()
finally:
statprof.stop()
statprof.display()
このブログ投稿からモジュールの背景が少しあります:
しかし、なぜこれが問題になるのでしょうか?Python には既に 2 つの組み込みプロファイラーがあります: lsprof と、長く非推奨となっている hotshot です。lsprof の問題は、関数呼び出しのみを追跡することです。関数内にいくつかのホット ループがある場合、どれが実際に重要であるかを判断するには、lsprof はほとんど役に立ちません。
数日前、私はまさに lsprof が失敗する状況に陥っていることに気付きました。それは、ホット関数があることを教えてくれましたが、その関数は私にはなじみがなく、問題がどこにあるのかすぐにはわからないほど長かったのです。 .
Twitter と Google+ で少し物乞いをした後、誰かが statprof を教えてくれました。しかし、問題がありました: 統計的サンプリングを行っていましたが (イェイ!)、サンプリング時に関数の最初の行のみを追跡していました (wtf!?)。それで私はそれを修正し、ドキュメンテーションを一新しました。今ではそれは使いやすく、誤解を招くものではありません。その出力の例を次に示します。そのホット関数で問題のある行をより正確に見つけます。
% cumulative self time seconds seconds name 68.75 0.14 0.14 scmutil.py:546:revrange 6.25 0.01 0.01 cmdutil.py:1006:walkchangerevs 6.25 0.01 0.01 revlog.py:241:__init__ [...blah blah blah...] 0.00 0.01 0.00 util.py:237:__get__ --- Sample count: 16 Total time: 0.200000 seconds
statprof を Python パッケージ インデックスにアップロードしたので、「easy_install statprof」をインストールするのはほとんど簡単です。
コードは github にアップされているので、バグ レポートや改善に貢献していただけると幸いです。楽しみ!
これを行うには、いくつかの方法が考えられます。
プログラムの実行中にスタック トレースを取得しようとするのではなく、割り込みを発生させて出力を解析します。これは、シェル スクリプト、またはアプリをサブプロセスとして呼び出す別の Python スクリプトを使用して行うことができます。C++ 固有の質問に対するこの回答では、基本的な考え方が説明され、かなり徹底的に擁護されています。
- 実際には、出力を解析するのではなく
sys.excepthook
、スタック トレースをログに記録する事後分析ルーチンを ( を使用して) 登録することができます。残念ながら、Python には例外が発生した時点から続行する方法がないため、ログ記録後に実行を再開することはできません。
- 実際には、出力を解析するのではなく
実行中のプログラムから実際にスタック トレースを取得するには、実装をハックする必要がある場合があります
。したがって、本当にそうしたい場合は、大部分が Python で記述された Python 実装であるpypyをチェックしてみる価値があるかもしれません。これをpypyで行うことがどれほど便利かはわかりません。基本的にすべての命令にフックを導入する必要があるため、特に便利ではないと思いますが、これは非常に非効率的だと思います。また、スタックトレースを開始したい状態に到達するまでに非常に長い時間がかからない限り、最初のオプションよりも大きな利点はないと思います。Python 自体のデバッグを容易にするためのデバッガー用の一連のマクロが存在します。
gdb
gdb は外部プロセス (この場合は、アプリケーションを実行している python のインスタンス) にアタッチして、ほとんど何でも実行できます。このマクロpystack
は、現在の実行時点での Python スタックのバックトレースを取得するようです。この手順を自動化するのはかなり簡単だと思います。なぜなら、(最悪の場合) テキストをgdb
usingexpect
などに入力するだけで済むからです。
Pythonには、説明したことを行うために必要なものがすべて含まれており、インタープリターをハックする必要はありません。
traceback
関数と組み合わせてモジュールを使用するだけsys._current_frames()
です。必要なのは、たとえば UNIX シグナルや別のスレッドを使用して、必要なトレースバックを必要な頻度でダンプする方法だけです。
コードをすぐに開始するには、この commitで行われていることを正確に実行できます。
そのコミットからモジュールをコピーする
threads.py
か、少なくともスタック トレース ダンプ機能 (ZPL ライセンス、非常にリベラル) をコピーします。シグナルハンドラーに接続します。たとえば、
SIGUSR1
次に、コードを実行し、必要に応じて SIGUSR1 で「kill」するだけです。
タイミングのために別のスレッドを使用して、単一のスレッドの単一の関数が同じ手法で時々「サンプリング」される場合、Products.LongRequestLoggerのコードとそのテストを分析することをお勧めしますNexediの雇用):
これが適切な「統計的」プロファイリングであるかどうかにかかわらず、 intuited が参照するMike Dunlaveyの回答は、これが非常に強力な「パフォーマンス デバッグ」手法であるという説得力のある議論をしています。パフォーマンスの問題の原因。
Python 用の外部統計プロファイラーを実装するには、別のプロセスに問い合わせるための一般的なデバッグ ツールと、インタープリターの状態を把握するための Python 固有のツールが必要になります。
これは一般的に簡単な問題ではありませんが、GDB 7 と関連する CPython 分析ツールから始めてみることをお勧めします。