Skip to main content

In-process CPython frame stack sampler

Project description

Echion

Near-zero-overhead, in-process CPython frame stack sampler with async support

Synopsis

Echion is an in-process CPython frame stack sampler. It can achieve near-zero-overhead, similar to Austin, by sampling the frame stack of each thread without holding the GIL. Native stacks can be sampled too, but the overhead is higher.

Echion is also the first example of a high-performance sampling async profiler for CPython.

Installation

Currently Echion is available to install from PyPI with

pip install echion

Alternativey, if a wheel is not available for your combination of platform and architecture, it can be installed from sources with

pip install git+https://github.com/p403n1x87/echion

Compilation requires a C++ compiler and static versions of the libunwind and lzma libraries.

Usage

The following is the output of the echion --help command.

usage: echion [-h] [-i INTERVAL] [-c] [-n] [-o OUTPUT] [-s] [-w] [-v] [-V] ...

In-process CPython frame stack sampler

positional arguments:
  command               Command string to execute.

options:
  -h, --help            show this help message and exit
  -i INTERVAL, --interval INTERVAL
                        sampling interval in microseconds
  -c, --cpu             sample on-CPU stacks only
  -x EXPOSURE, --exposure EXPOSURE
                        exposure time, in seconds
  -n, --native          sample native stacks
  -o OUTPUT, --output OUTPUT
                        output location (can use %(pid) to insert the process ID)
  -p PID, --pid PID     Attach to the process with the given PID
  -s, --stealth         stealth mode (sampler thread is not accounted for)
  -w WHERE, --where WHERE
                        where mode: display thread stacks of the given process
  -v, --verbose         verbose logging
  -V, --version         show program's version number and exit

The output is written to a file specified with the --output option. Curretly, this is in the format of the normal Austin format, that is collapsed stacks with metadata at the top. This makes it easy to re-use existing visualisation tools, like the Austin VS Code extension.

Compatibility

Supported platforms: Linux (amd64, i686), Darwin (amd64, aarch64)

Supported interpreters: CPython 3.8-3.11

Notes

Attaching to a process (including in where mode) requires extra permissions. On Unix, you can attach to a running process with sudo. On Linux, one may also set the ptrace scope to 0 with sudo sysctl kernel.yama.ptrace_scope=0 to allow attaching to any process. However, this is not recommended for security reasons.

Where mode

The where mode is similar to Austin's where mode, that is Echion will dump the stacks of all running threads to standard error. This is useful for debugging deadlocks and other issues that may occur in a running process.

When running or attaching to a process, you can also send a SIGQUIT signal to dump the stacks of all running threads. The result is similar to the where mode. You can normally send a SIGQUIT signal with the CTRL+\ key combination.

Why Echion?

Sampling in-process comes with some benefits. One has easier access to more information, like thread names, and potentially the task abstraction of async frameworks, like asyncio, gevent, ... . Also available is more accurate per-thread CPU timing information.

Currently, Echion supports sampling asyncio-based applications, but not in native mode. This makes Echion the very first example of an async profiler for CPython.

Echion relies on some assumptions to collect and sample all the running threads without holding the GIL. This makes Echion very similar to tools like Austin. However, some features, like multiprocess support, are more complicated to handle and would require the use of e.g. IPC solutions. Furthermore, Echion normally requires that you install it within your environment, wheareas Austin can be installed indepdendently.

How it works

On a fundamental level, there is one key assumption that Echion relies upon:

The interpreter state object lives as long as the CPython process itself.

All unsafe memory reads are performed indirectly via copies of data structure obtained with the use of system calls like process_vm_readv. This is essentially what allows Echion to run its sampling thread without the GIL.

As for attaching to a running process, we make use of the hypno library to inject Python code that bootstraps Echion into the target process.

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

echion-0.2.0.tar.gz (705.1 kB view hashes)

Uploaded Source

Built Distributions

echion-0.2.0-cp311-cp311-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

echion-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (743.0 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

echion-0.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl (730.4 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ i686

echion-0.2.0-cp311-cp311-macosx_11_0_arm64.whl (78.0 kB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

echion-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl (82.7 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ x86-64

echion-0.2.0-cp311-cp311-macosx_10_9_universal2.whl (124.5 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ universal2 (ARM64, x86-64)

echion-0.2.0-cp310-cp310-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

echion-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (745.3 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

echion-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl (731.9 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ i686

echion-0.2.0-cp310-cp310-macosx_11_0_arm64.whl (77.6 kB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

echion-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl (82.2 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ x86-64

echion-0.2.0-cp310-cp310-macosx_10_9_universal2.whl (123.5 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ universal2 (ARM64, x86-64)

echion-0.2.0-cp39-cp39-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

echion-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (744.4 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

echion-0.2.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl (731.0 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ i686

echion-0.2.0-cp39-cp39-macosx_11_0_arm64.whl (77.5 kB view hashes)

Uploaded CPython 3.9 macOS 11.0+ ARM64

echion-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl (82.2 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ x86-64

echion-0.2.0-cp39-cp39-macosx_10_9_universal2.whl (123.5 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ universal2 (ARM64, x86-64)

echion-0.2.0-cp38-cp38-musllinux_1_1_x86_64.whl (1.3 MB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

echion-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (744.3 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

echion-0.2.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl (730.8 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ i686

echion-0.2.0-cp38-cp38-macosx_11_0_arm64.whl (77.5 kB view hashes)

Uploaded CPython 3.8 macOS 11.0+ ARM64

echion-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl (82.2 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ x86-64

echion-0.2.0-cp38-cp38-macosx_10_9_universal2.whl (123.4 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ universal2 (ARM64, x86-64)

Supported by

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