Periodic stack-trace sampler for Python performance profiling.
Project description
pysttl
pysttl (Python Sampling Thread Trace Logger) は、Python アプリケーションのパフォーマンスのボトルネックを特定するためのスタックトレース定期サンプラーです。SIGALRM を利用して指定間隔ごとに全スレッドのスタックトレースを取得し、JSON Lines 形式でログファイルに追記します。
得られたログを解析することで、どの関数・どの行で時間を費やしているかを統計的に把握できます (poor-man's profiler の発想)。
動作要件
- Python 3.11 以上
- POSIX 系 OS (Linux / macOS) — 内部で
signal.SIGALRMを使用するため、Windows では動作しません。 start()はメインスレッドからのみ呼び出せます (signal.signal()の制約)。signal.SIGALRM/signal.setitimer(ITIMER_REAL, ...)を内部で利用するため、同じシグナル/タイマーを使う他のコードとは併用できません。
インストール
pip install pysttl
ローカルチェックアウトから直接インストールする場合:
pip install .
開発用の追加依存 (ビルド/PyPI アップロード用) も入れる場合:
pip install -e '.[dev]'
使い方
1. コンテキストマネージャ (推奨)
import pysttl
with pysttl.trace():
do_heavy_work()
ブロックを抜けると自動的に stop() が呼ばれ、SIGALRM ハンドラと setitimer の状態は呼び出し前に復元されます。trace() は PYSTTL_ENABLE を見ません(明示的にプロファイルしたいブロック向け)。
2. 関数 API
環境変数 PYSTTL_ENABLE が設定されていて、かつ空でない場合にだけ start() がサンプリングを開始します。未設定なら何もせず、例外も発生しません。アプリに pysttl.start() を常時置き、デバッグ実行時だけ PYSTTL_ENABLE=1 のように付与する使い方を想定しています。
ログファイルの親ディレクトリが無い場合は自動作成します。
サンプリング開始に成功した場合、プロセス終了時に atexit で stop() が呼ばれるため、stop() は省略できます。
import pysttl
# 例: PYSTTL_ENABLE=1 python app.py
pysttl.start()
do_heavy_work()
パスや間隔を明示する例:
import pysttl
pysttl.start(log_file_path="/tmp/backtrace.log", interval=1.0)
try:
do_heavy_work()
finally:
pysttl.stop()
3. デフォルト値の上書き
log_file_path と interval のデフォルト値はモジュール属性として公開されており、外部から上書き可能です。start() / trace() は呼び出し時にその時点の値を参照します。
import pysttl
pysttl.DEFAULT_LOG_FILE_PATH = "/var/log/myapp/backtrace.log"
pysttl.DEFAULT_INTERVAL = 0.5 # 500ms 間隔でサンプル
# PYSTTL_ENABLE を付与したデバッグ実行時のみ有効
pysttl.start()
引数を明示的に渡した場合はそちらが優先されます。
出力フォーマット
ログは JSON Lines で書き出されます。1 行 = 1 サンプル = その時点の全スレッドのスタックトレースです。
{
"threads": [
{
"backtrace": [
"<FrameSummary file '/path/to/main.py', line 14 in main>",
"<FrameSummary file '/path/to/core.py', line 80 in busy_loop>"
],
"datetime": "2026-05-08T21:00:00.123456",
"thread_name": "MainThread",
"thread_ident": 140123456789
}
]
}
backtrace は呼び出し元 → 呼び出し先の順 (root -> leaf) に並んでいます。
解析 CLI
pysttl-parse は pysttl が出力した JSON Lines ログを解析し、スタックツリーとステップランキングを出力します。
# ファイルを解析して結果を保存
pysttl-parse < /tmp/backtrace.log > log/tree.txt
# パイプ経由でも利用可能
cat /tmp/backtrace.log | pysttl-parse
出力には以下の2セクションが含まれます。
### Stack trace log analysis tree### Step load ranking
壊れた JSON 行は警告を stderr に出力し、解析は継続します。
API リファレンス
| シンボル | 種別 | 説明 |
|---|---|---|
pysttl.start(log_file_path=None, interval=None) |
関数 | PYSTTL_ENABLE が有効なときのみサンプリング開始。それ以外は no-op(例外なし)。None の引数は対応する DEFAULT_* を参照。 |
pysttl.stop() |
関数 | サンプリング停止 + SIGALRM ハンドラ復元。未起動なら no-op。 |
pysttl.trace(log_file_path=None, interval=None) |
コンテキストマネージャ | サンプリングの開始/停止。PYSTTL_ENABLE は不要。 |
pysttl.DEFAULT_LOG_FILE_PATH |
定数 (str) | 既定の出力先。初期値 "/tmp/backtrace.log"。 |
pysttl.DEFAULT_INTERVAL |
定数 (float) | 既定のサンプリング間隔 [秒]。初期値 1.0。 |
pysttl.PYSTTL_ENABLE_ENV |
定数 (str) | 参照する環境変数名。値は "PYSTTL_ENABLE"。 |
制限事項
signal.SIGALRMをpysttlが占有するため、signal.alarm()やsetitimer(ITIMER_REAL, ...)を別途使用するコードと併用できません。- シグナルハンドラ内でファイル I/O (JSON シリアライズ + 追記書き込み) を行うため、I/O が遅い環境では実際の処理スレッドを意図せずブロックする可能性があります。本番常用ではなく調査用途を想定しています。
start()が既に有効な状態で再度start()した場合は no-op です。出力先や間隔を変えるときはいったんstop()してから再度start()してください。
ビルドと公開
# ビルド (sdist + wheel を dist/ に生成)
python -m build
# 動作確認用に別 venv へインストール
pip install dist/pysttl-*.whl
# PyPI へアップロード (要 ~/.pypirc)
twine upload dist/*
uv ユーザーは uv build / uv publish も利用可能です。
ライセンス
MIT License。詳細は pyproject.toml を参照してください。
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pysttl-0.1.3.tar.gz.
File metadata
- Download URL: pysttl-0.1.3.tar.gz
- Upload date:
- Size: 7.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a1ff71f2c6313b82ad4a8f7cafe4322a6a68cebb7c9c566df43bed6d44c6a1d2
|
|
| MD5 |
1d6d4249806b6907c52aec4525c6b828
|
|
| BLAKE2b-256 |
126830aa7005bb1808228d8312687d16d74852fa26c9c4ad53868825b102648c
|
File details
Details for the file pysttl-0.1.3-py3-none-any.whl.
File metadata
- Download URL: pysttl-0.1.3-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8de8015e4e8a6c01f021503e85bf6d3671b4e5da63d550b6f7759fa98218bc8
|
|
| MD5 |
cfdaebf85cab395183c16a3aa42d9021
|
|
| BLAKE2b-256 |
8629d3c92c974e0a74a0e6974bcf4a799417b4529f14c9f22f15cf9fee5ece3b
|