Skip to main content

Python profiler using USDT probes for low-overhead performance monitoring with bpftrace

Project description

🐍 pyusdt 🐝

A Python profiler using USDT (User-level Statically Defined Tracing) probes for low-overhead performance monitoring.

Overview

pyusdt instruments Python code execution with USDT probes that can be traced using bpftrace. It uses Python's sys.monitoring API for efficient function-level tracing.

This tool is particularly designed to enable bpftrace workflows where traces need to span both kernel and userspace, allowing you to correlate Python function calls with kernel events in a single trace session.

Zero-overhead when not traced: pyusdt uses dynamic callback registration combined with USDT semaphores. When no tracer is attached, monitoring callbacks are not registered with sys.monitoring, resulting in essentially zero performance impact on your Python code. When bpftrace or another tracer attaches, callbacks are automatically enabled within ~100ms.

Requirements

  • Python 3.12+ (for sys.monitoring API)
  • Linux with USDT support
  • bpftrace

Building

Make sure gcc and Python development headers are installed. Compile the USDT probe extension:

make

This creates libpyusdt.so, a Python C extension module with embedded USDT probes.

Usage

Run any Python script with USDT monitoring:

python -m pyusdt <script.py> [args...]

Example:

python -m pyusdt sleep.py

Configuration

Adjust the polling interval for tracer detection (default: 100ms):

# Check for attached tracers every 50ms
PYUSDT_CHECK_MSEC=50 python -m pyusdt sleep.py

# Check every 500ms (lower overhead, slower tracer detection)
PYUSDT_CHECK_MSEC=500 python -m pyusdt sleep.py

Tracing with bpftrace

Use the included bpftrace script to trace function calls:

sudo bpftrace sample.bt -c "python -m pyusdt sleep.py"

Or attach to a running process:

# In terminal 1:
python -m pyusdt sleep.py

# In terminal 2:
sudo bpftrace sample.bt -p $(pgrep -f "python -m pyusdt")

Testing

Run the test suite:

make test

How it Works

  1. libpyusdt.so - Python C extension module with USDT probe definitions and sys.monitoring integration
  2. pyusdt/__init__.py - Minimal Python wrapper that imports the C extension
  3. pyusdt/__main__.py - Entry point for python -m pyusdt execution
  4. sample.bt - bpftrace script to display traced function calls
  5. usdt.h - Header-only USDT library from libbpf/usdt

When the pyusdt module is imported, the C extension starts a background thread that polls USDT semaphores to detect when a tracer (like bpftrace) attaches. Only when a tracer is active does pyusdt register callbacks with Python's sys.monitoring API (see PEP 669). When the tracer detaches, callbacks are automatically unregistered.

The following monitoring events are captured and exposed as USDT probes when tracing is active:

  • PY_START - Function entry
  • PY_RESUME - Generator/coroutine resumption
  • PY_RETURN - Function return with return value
  • PY_YIELD - Generator yield with yielded value
  • CALL - Function calls
  • LINE - Line-by-line execution

Each event triggers its corresponding USDT probe with relevant context (function name, filename, line number, and event-specific data).

Zero-Overhead Design

pyusdt achieves true zero overhead when not being traced through:

  1. USDT Semaphores: The libbpf/usdt library uses kernel-managed semaphores that are incremented when tracers attach
  2. Dynamic Callback Registration: A background thread polls semaphores every 100ms and only registers sys.monitoring callbacks when needed
  3. Automatic Enable/Disable: When bpftrace attaches, monitoring activates within ~100ms; when it detaches, monitoring stops immediately

This means you can leave pyusdt enabled in production with virtually no performance impact until you need to trace.

References

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

pyusdt-0.1.0.tar.gz (24.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pyusdt-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (29.9 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ ARM64

pyusdt-0.1.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (29.0 kB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

pyusdt-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (29.9 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ ARM64

pyusdt-0.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (29.1 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

File details

Details for the file pyusdt-0.1.0.tar.gz.

File metadata

  • Download URL: pyusdt-0.1.0.tar.gz
  • Upload date:
  • Size: 24.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyusdt-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1bad5503fbb563f5a26c3d1becb19464f6c430582ae6aa9d982bd1ef06aa104a
MD5 9bcdc1205747c1ecb90a490e3b8f9903
BLAKE2b-256 b7ec92d10b973a2a74fb93da26da81fe4d24ddb92a2452f6d8af9de8da042ddb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyusdt-0.1.0.tar.gz:

Publisher: release.yml on natoscott/pyusdt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyusdt-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyusdt-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3bb2ee910dd38ef6320c21ae54cb39b880775a8fdb1c7c3a680a69fd570056df
MD5 b96e2cf522b3199589941d66cfa07e59
BLAKE2b-256 b9764acd7505efffe4ce12737cf855841d8550faaf23e610798385fa2c66fceb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyusdt-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on natoscott/pyusdt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyusdt-0.1.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyusdt-0.1.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9bc29f6c094def4619106b2bd9dac2aeb895b20878ea97e5d37817fa485c9d12
MD5 d28193ffc9433d924e85187f5ef8902f
BLAKE2b-256 8dd7bae2805c19261540b75504d96821acd51da29b2b00d004f7f738f4f43870

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyusdt-0.1.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on natoscott/pyusdt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyusdt-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for pyusdt-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 c6265a45e2841569f86437955a944a59d7699ca4597b00c207b2bc45e2052053
MD5 c062c39bfaa1b153c3dde9037a8cfd78
BLAKE2b-256 ef90f5354134a08d7b04b98dc1988db2f2caffb2166eb0a8d32a9d1e22df1ff7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyusdt-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on natoscott/pyusdt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyusdt-0.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pyusdt-0.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a10b4b624890d2400007ae224bad96ac72952d8a0be01f36cf34e4f4c67a4694
MD5 d15f1e5bc70e13949f9d8a9495427aaf
BLAKE2b-256 09a1ec8c109b5277eec0f4d33e5159096c244fe55c5847c4e19e513f7175bc72

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyusdt-0.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on natoscott/pyusdt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page