A fast Rust-backed reader for Cadence binary PSF files, with a clean numpy API
Project description
psfox
A fast Rust-backed reader for Cadence binary PSF files, with a clean numpy API.
The Cadence psf-parser (pure Python) is slow and memory-hungry — it OOM-crashes on large
files because it stores every sample as an individual Python object. psfox is a Rust core
(PyO3 + maturin) that reads the same files much faster and with low RAM, returning numpy
arrays directly.
Performance
Measured against the pinned pure-Python psf-parser (each parser in a fresh subprocess, median
of repeated runs):
| Dataset | Size | psfox | psf-parser | speedup | psfox peak RSS |
|---|---|---|---|---|---|
| noise (struct-typed) | ~634 MB | ~1.2 s | ~60 s | ~49× | ~1.3 GB |
| AC (complex) | ~133 MB | ~0.34 s | ~17 s | ~51× | ~0.27 GB |
Small files (S-parameter, DC) parse in single-digit milliseconds (tens of times faster). The
output is bit-identical to psf-parser (exact, NaN/Inf-aware) on every tested file, and the
memory ceiling is low enough to parse a 600 MB+ file on a 4 GB machine without OOM.
What it reads
psfbin 1.1, big-endian: swept and non-swept analyses; real and complex vectors; and struct/composite types → numpy structured arrays. Common analysis types (noise, AC, DC, S-parameter) are supported. Out of scope (for now): PSF ASCII, PSF-XL/transient, and multi-sweep / family / corner files.
Requirements
- Python ≥ 3.9
- numpy ≥ 1.23 — a runtime dependency (the reader returns numpy arrays). It is declared in the package metadata, so installing psfox pulls numpy in automatically.
Install
Not on PyPI yet. Once published, the install is simply:
uv add psfox # or: pip install psfox
Until then, install from a prebuilt wheel (no Rust toolchain needed). Build it once with maturin:
maturin build --release
# -> target/wheels/psfox-0.1.0-cp39-abi3-<platform>.whl
Then install that wheel into any Python ≥ 3.9 environment (numpy is pulled in automatically):
pip install psfox-0.1.0-cp39-abi3-<platform>.whl
Notes:
- The wheel is abi3 (
cp39-abi3): one wheel works for Python 3.9, 3.10, … 3.13+ — no rebuild per Python version. - A wheel is platform-specific (Linux / macOS / Windows × architecture). A wheel built on one OS will not install on another; build it on the target platform, cross-build a Linux wheel from any host (see below), or wait for a public cross-platform release.
To build from source instead (needs the Rust toolchain), see CONTRIBUTING.md in the repository.
Cross-building a Linux wheel
psfox has no system C dependencies — the only native code is the Rust core, built as an abi3
extension — so a manylinux wheel can be cross-compiled from any host (Windows, macOS, Linux)
using zig as the linker. No Docker or virtual machine required:
rustup target add x86_64-unknown-linux-gnu # one-time: add the Linux target
pip install ziglang # the zig toolchain, shipped as a Python package
maturin build --release --target x86_64-unknown-linux-gnu --zig --compatibility manylinux2014
# -> target/wheels/psfox-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
The manylinux2014 tag links against an old glibc, so the wheel installs on essentially any modern
Linux distribution.
On Windows, maturin may not auto-detect the zig that ships inside the ziglang package (it fails
with Failed to find zig). If so, put that package's folder on PATH for the build:
$env:PATH = "$PWD\.venv\Lib\site-packages\ziglang;$env:PATH"
Because the wheel is cross-compiled, smoke-test import psfox on an actual Linux host (or WSL) — it
cannot run on the machine that built it.
Usage
import psfox
psf = psfox.read_psf("path/to/data.sp")
print(psf) # <Psf sweeps=1 traces=16 values=0>
print(psf.header["PSFversion"]) # header is a plain dict
# Sweep axes and traces are numpy arrays
for sw in psf.sweeps:
print(sw.name, sw.data.dtype, sw.data.shape) # e.g. freq float64 (700,)
t = psf.traces[0]
print(t.name, t.data.dtype, t.data.shape) # e.g. s11 complex128 (700,)
# Non-swept DC -> .values (Python scalars), no traces/sweeps
dc = psfox.read_psf("path/to/data.dc")
print(len(dc.values), dc.values[0].name, dc.values[0].data) # e.g. 5349 'net1' -7.7e-04
# Struct traces -> numpy structured array, one float64 field per contribution
noise = psfox.read_psf("path/to/data.noise")
tr = noise.traces[0]
if tr.data.dtype.names is not None: # struct vs flat discriminator
print(tr.data.dtype.names[:3]) # e.g. ('<dev>.thermal', '<dev>.shot', ...)
print(tr.data[tr.data.dtype.names[0]]) # float64[N] for that contribution
Run a script with the project environment: uv run python your_script.py (or activate .venv).
API
| Object | Attributes |
|---|---|
read_psf(path) -> Psf |
parse a psfbin file |
Psf |
.header (dict), .sweeps (list[Sweep]), .traces (list[Trace]), .values (list[Value]) |
Sweep, Trace |
.name (str), .data (numpy array) |
Value |
.name (str), .data (Python scalar) |
psfox.__version__ |
version string |
- flat vs struct trace:
trace.data.dtype.names is None→ flat (float64[N]/complex128[N]); notNone→ struct (one namedfloat64field per contribution). - swept vs non-swept: swept analyses populate
.traces(+.sweeps); non-swept DC populates.values. - real vs complex is inferred per trace from the file, not assumed file-wide.
Type stubs and a py.typed marker ship with the package, so editors give autocomplete and type
checking; help(psfox.read_psf) shows the inline docstrings.
Distribution
psfox is built with maturin + PyO3 — the same stack as polars and pydantic-core — and is
distributed as a Python wheel (.whl). The remaining step toward a pip install psfox that
"just works" everywhere is a CI-built wheel matrix + a PyPI publish. Thanks to abi3, that matrix is
one wheel per platform rather than one per platform × Python version.
Contributing
Build, test, and benchmark instructions live in CONTRIBUTING.md.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 psfox-0.1.0.tar.gz.
File metadata
- Download URL: psfox-0.1.0.tar.gz
- Upload date:
- Size: 51.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51a969bf8fad368ffe12a19b0c2b704e29c8b996818d1b4433efa20e15aaf434
|
|
| MD5 |
f45653a1f6a6ca8fc3eed5f4d645d784
|
|
| BLAKE2b-256 |
c8c379d4d3945c887c87bd008418f6516f5a71ee478f068878ac733cf3e5b006
|
Provenance
The following attestation bundles were made for psfox-0.1.0.tar.gz:
Publisher:
publish.yml on Zwelckovich/psfox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
psfox-0.1.0.tar.gz -
Subject digest:
51a969bf8fad368ffe12a19b0c2b704e29c8b996818d1b4433efa20e15aaf434 - Sigstore transparency entry: 1756024440
- Sigstore integration time:
-
Permalink:
Zwelckovich/psfox@fce8b0e2c2e7b122cd238d4af3328676719e81b1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Zwelckovich
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fce8b0e2c2e7b122cd238d4af3328676719e81b1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file psfox-0.1.0-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: psfox-0.1.0-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 166.7 kB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
698e2f2bda8cf03782c431bb0d7d036df198df08e40a7b8a4445008077d4929a
|
|
| MD5 |
bb5bcb97634c62a7ec43ad0bb9d8220f
|
|
| BLAKE2b-256 |
42f53e85d078324680428edb546ec0612ad190099710ee61a1fa8a7d2ccbc882
|
Provenance
The following attestation bundles were made for psfox-0.1.0-cp39-abi3-win_amd64.whl:
Publisher:
publish.yml on Zwelckovich/psfox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
psfox-0.1.0-cp39-abi3-win_amd64.whl -
Subject digest:
698e2f2bda8cf03782c431bb0d7d036df198df08e40a7b8a4445008077d4929a - Sigstore transparency entry: 1756024594
- Sigstore integration time:
-
Permalink:
Zwelckovich/psfox@fce8b0e2c2e7b122cd238d4af3328676719e81b1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Zwelckovich
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fce8b0e2c2e7b122cd238d4af3328676719e81b1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file psfox-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: psfox-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 280.8 kB
- Tags: CPython 3.9+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc279df8a124adf55fa6eb1f517e6fc3eecac6338b680f9f7630b2625a47c8d4
|
|
| MD5 |
7bd8b6dd8bf49f107d946dab74a05324
|
|
| BLAKE2b-256 |
f8952d500617687727fabc68a17a15cdb6fa08ace3dfb3f17979e71c3750c008
|
Provenance
The following attestation bundles were made for psfox-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish.yml on Zwelckovich/psfox
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
psfox-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
bc279df8a124adf55fa6eb1f517e6fc3eecac6338b680f9f7630b2625a47c8d4 - Sigstore transparency entry: 1756024525
- Sigstore integration time:
-
Permalink:
Zwelckovich/psfox@fce8b0e2c2e7b122cd238d4af3328676719e81b1 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Zwelckovich
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fce8b0e2c2e7b122cd238d4af3328676719e81b1 -
Trigger Event:
push
-
Statement type: