Skip to content
Capability · Performance engineering

Measure the bottleneck before changing the language

Neul Labs profiles Python, Rust, Go and mixed-language systems, isolates the limiting path and implements the smallest change that improves the target workload without losing correctness, compatibility or operability.

A four-step measurement loop

The benchmark is a decision instrument. It should survive the optimisation and detect when a later change gives the gain back.

  1. 1

    Define the workload

    Freeze representative inputs, versions, hardware, concurrency, warm-up, correctness conditions and the business constraint the measurement should answer.

  2. 2

    Measure the baseline

    Profile before rewriting. Separate CPU, allocation, I/O, locking, serialisation, network and database time and retain raw results.

  3. 3

    Change the smallest hot path

    Select algorithm, batching, caching, concurrency or a native boundary only where the profile supports it. Keep compatibility and rollback explicit.

  4. 4

    Re-test and explain

    Run the same workload, verify outputs and resource use, report variance and trade-offs, and turn the benchmark into a regression guard.

Analyse

Profile and model

Flame graphs, allocation and lock analysis, database and I/O timing, concurrency behaviour, call-volume and data-shape analysis.

Implement

Optimise the boundary

Algorithms, batching, caching, data layout, pooling, native extensions, protocol changes or simpler deployment where evidence supports them.

Transfer

Leave a regression guard

Pinned harness, correctness oracle, raw measurements, decision record, CI threshold, release notes and operating guidance.

Native boundary checklist

When Rust or Go earns its place

A native component should remove more complexity than it introduces across builds, packaging, debugging and support.

Stable hot path

The expensive operation is frequent, measurable and unlikely to be redesigned immediately.

Clear interface

Data crossing the boundary is compact, typed and does not require repeated Python object conversion.

Correctness oracle

The original behaviour or a formal invariant can detect compatibility regressions.

Packaging plan

Supported platforms, wheels or binaries, toolchains, fallbacks and upgrades are owned.

Operational gain

The change improves a relevant constraint such as p95 latency, throughput, memory or compute cost.

Honest trade-off

The report includes build size, maintenance, variance, unsupported cases and negative results.

Public examples of the engineering shape

Repository claims remain workload-specific. Inspect the source, benchmark setup and version before relying on any number.

Rust + Python

fast-litellm

A PyO3 acceleration layer for LiteLLM. Replaces the hottest Python paths — HTTP connection pooling, rate limiting, response normalisation — with thread-safe Rust. No API changes; one import.

Rust + Python

fast-langgraph

A Rust performance layer for LangGraph. Drop-in components accelerate checkpoint serialization (737× on 235 KB state), state updates (45.9×), LLM caching and executor management — while passing 85 of 88 upstream LangGraph tests.

Rust + Python

fast-crewai

Rust-backed acceleration shim for CrewAI. Targets the serialization layer, the tool dispatcher, and the embedded knowledge store. Zero changes to existing CrewAI projects.

Rust + Python

fast-axolotl

A drop-in Rust acceleration shim for the Axolotl fine-tuning toolkit. Import it before Axolotl and four data-pipeline hot paths (streaming readers, parallel SHA-256 dedup, token packing, batch padding) swap to Rust — 77× on Parquet streaming.

Rust

rjest

rjest keeps a Rust daemon (jestd) running in the background, caching SWC transforms and pre-warming Node.js workers. Warm runs land around 14ms. It reads your existing jest.config.* with zero changes and supports the standard Jest CLI flags.

Rust

rninja

A Rust-powered drop-in for Ninja. It parses the same build.ninja and mirrors the core flags, adding a content-addressed action cache (sled), a tokio async scheduler, and an optional remote cache — 2–5× on warm incremental builds.

Questions people ask

When should Python code move to Rust?

Only when measurement identifies a stable hot path where native code can reduce CPU, allocation, serialisation or contention without making the interface and deployment cost worse. Vectorised libraries, batching, caching or a better algorithm can be the better answer.

What makes a performance benchmark reproducible?

The repository or report should identify code and dependency versions, hardware and operating system, input data, setup and warm-up, number of runs, summary statistic, correctness check and known limitations. A single best run is not enough.

Can you guarantee a particular speedup?

No. Results depend on workload, versions, hardware, concurrency, data shape and surrounding systems. We agree a baseline and decision threshold, then report what the controlled comparison actually shows.

Does performance engineering include cost and memory?

Yes when they are relevant constraints. Latency, throughput, CPU, memory, storage, network, model tokens, GPU use and operating complexity can trade against each other, so the measurement plan defines which matter.

Bring the slow path and the workload that matters

Include current versions, hardware, representative inputs, desired threshold and any correctness or compatibility constraints.

admin@neullabs.com