AI delivery · Systems performance

Find out whether Rust will fix your bottleneck before anyone rewrites it

If you have a measured performance, memory or reliability bottleneck and someone has proposed Rust, you can commission a profiling-first engagement. I reproduce the workload, profile it, and tell you whether Rust is warranted or a simpler fix exists. If Rust is the answer, I build the narrowest change that works and prove it with a correctness-preserving comparison.

This is a good fit if…

  • A Python service in your AI stack is CPU-bound in one place, such as tokenisation, parsing, scoring or serialisation, and scaling out is getting expensive.
  • An engineer has proposed rewriting a service in Rust and you want an independent view, grounded in profiles, before committing the team.
  • You already run Rust in production and a service is slower, larger in memory or less stable under load than it should be.
  • Memory limits on edge devices or small containers are forcing awkward trade-offs in a component that could be compiled.

Look elsewhere if…

  • The bottleneck is model inference on GPUs or LLM provider latency. Use AI infrastructure, inference and cost optimisation.
  • You want a Rust engineer under your own manager for an ongoing roadmap. Hire an AI platform engineer on contract instead.
  • You have no measurement yet, only a sense that things are slow. Start by instrumenting; I can help, but the decision needs data first.

What you get

Rust systems engineering and profiling

  • A reproducible benchmark of the workload that matters, runnable by your team.
  • Profiles that locate where time and memory actually go, with a written interpretation.
  • A decision record: Rust, a fix in the existing language, an architectural change, or no change, with the reasoning.
  • If Rust is warranted, the narrowest working change: an extension module, a library or a service, behind your existing interface.
  • A comparison showing the new path produces the same results as the old one on agreed inputs, plus the measured difference.

How it runs

  1. 01

    Reproduce the workload

    We agree the workload and metric that matter, such as p99 latency, throughput per core or peak memory, and I build a benchmark that reproduces it outside production.

  2. 02

    Profile and decide

    I profile the existing system and write a decision record. Often the fix is algorithmic, a caching or batching change, or a library swap; Rust is recommended only when the profile supports it.

  3. 03

    Build the narrowest change

    If Rust is warranted, I implement the hot path as a Rust extension or service behind the current interface, with tests, benchmarks and fallbacks.

  4. 04

    Prove equivalence and hand over

    A correctness comparison against the original on agreed inputs, benchmarks in CI to catch regressions, and a handover to the engineers who will maintain it.

What needs to be in place

  • A description of the bottleneck and any existing measurements, dashboards or incident history.
  • Access to the code, and a way to run the workload outside production, or permission to build one.
  • Representative input data or a generator that matches production shape.
  • An engineer on your side who will own the result and is willing to read some Rust.

Not included

  • A blanket rewrite of a system into Rust. The work targets the measured bottleneck.
  • Speed-up figures promised before profiling. The decision record reports what was measured.
  • Maintaining the Rust code indefinitely. Ownership passes to your team at handover.
  • Out-of-hours production support unless agreed separately.

Rust is a remedy, not a diagnosis

Rust earns its place in production systems where predictable latency, low memory use and safe concurrency matter, and it has become a common way to speed up the CPU-heavy parts of Python AI stacks. That makes it an easy answer to propose whenever something is slow. It is not always the right one. A rewrite costs months, splits your codebase across two languages, and sometimes moves the bottleneck rather than removing it.

This engagement starts from the other end. Before anyone writes Rust, we reproduce the problem, measure it and find out where the time and memory actually go. Then the decision is made on evidence. My published guide to Rust in production AI systems sets out the same reasoning in more depth.

What the work involves

Reproducing the workload. A benchmark that exercises the slow path with production-shaped inputs and measures the metric you care about. Without it, nobody can say whether a change helped.

Profiling. CPU sampling and flame graphs to find hot functions, allocation profiling for memory growth, and lock and scheduler analysis for concurrent services. For Python services, profiling shows whether the time is in Python code, in native libraries already, or waiting on I/O, and only the first case is a candidate for Rust.

Deciding. The decision record lists the options the profile supports, with expected effect and cost. Typical outcomes:

  • a fix in the existing language (better algorithm, batching, caching, a faster library);
  • a narrow Rust extension module called from Python for one hot path;
  • a Rust library or service behind an existing interface;
  • or no change, because the bottleneck is elsewhere.

Building. If Rust is warranted, I implement the narrowest change: typically an extension built with PyO3 or a small service, behind the interface the rest of your system already uses, with a fallback to the old path during rollout.

Proving. An equivalence test and benchmarks that run in CI. For existing Rust services, the same profile-first approach applies to async runtime configuration, allocation patterns, data layout and contention.

My recent work has been in this area: performance-critical components of an AI agent stack in regulated financial services, and Rust-accelerated drop-in components for production AI stacks at Neul Labs.

The signature deliverable

You receive Rust systems engineering and profiling: the benchmark, the profiles, the decision record and, where warranted, the change with its equivalence test. Illustrative example of a decision record summary:

OptionProfile evidenceExpected effectCost and riskRecommendation
Batch tokeniser callsMost of request time in per-item calls with fixed overheadLarge reduction in call overheadSmall change, no new languageDo first
Rust extension for scoring loopPure-Python loop dominates remaining CPU timeSubstantial reduction in CPU per requestSmall Rust module, needs one ownerDo if batching is not enough
Rewrite service in RustMost remaining time is network and database waitLittle effect on latencyMonths of work, two codebasesDo not do

Illustrative example. Not taken from a client engagement.

How acceptance is judged

Acceptance is set before the build: the benchmark and target metric, the equivalence test and its tolerance, and the operational checks (memory under load, behaviour when the extension fails). Your platform lead accepts the decision record and, if commissioned, the build against those measures.

Ownership and handover

All code, benchmarks and profiles live in your repository. Benchmarks run in CI so regressions are caught after I leave. The engineer who will own the Rust code pairs with me on the build and receives a walk-through of the design, the build tooling and the release process.

When to choose something else

If the bottleneck is model serving, GPU use or provider latency, see AI infrastructure, inference and cost optimisation or reducing LLM cost and latency. For ongoing Rust capacity under your own manager, see hire a contract AI engineer.

Questions buyers ask

What if the profile shows Rust is not the answer?

Then the decision record says so, with the alternative. That is a useful result: it saves a rewrite. Many bottlenecks are a poor algorithm, unbatched I/O, repeated serialisation or a slow library call, and can be fixed in the existing language. You pay for the profiling and decision, not for a Rust build you do not need.

Our team does not know Rust. Will we be able to maintain it?

That is part of the decision. A small extension module with a stable interface, good tests and a benchmark is maintainable by a team that reads Rust occasionally. A large service is a different commitment. I keep the Rust surface as small as the problem allows and pair with your engineer during the build.

How do you show the new code gives the same answers?

We agree an equivalence test before the build: the inputs, the outputs to compare and the tolerance, for example exact match for parsing or a bounded difference for floating-point scoring. Both paths run on the same inputs in CI, and any difference fails the build.

How is this priced?

As scoped delivery, shown in the engagement model on this page. Profiling and the decision record come first and can stand alone. If Rust is warranted, the build is scoped from what the profile showed, so you are not committing to implementation before the evidence exists.

Share a systems bottleneck

A short, non-confidential description is enough to start. I read every brief personally and reply within two business days, including when the answer is that I am not the right fit.

Step 1 of 2 · The basics