Skip to content

render-examples/python-memray-profiling

Repository files navigation

Memray Profiling for Native Python Modules on Render

This example shows a realistic way to profile memory use from native Python extensions on Render:

  • A FastAPI service exposes an authenticated endpoint that captures a Memray profile for a single request.
  • The profiled workload uses NumPy and pandas, which exercise native code paths and temporary allocations that are hard to spot with Python-only tracers.
  • Render stores the .bin capture and generated flamegraph on a persistent disk so the artifacts survive restarts and redeploys.
  • Dependencies are managed with uv, using pyproject.toml and a checked-in uv.lock.

Files

  • app.py: FastAPI app with the authenticated profiling endpoints.
  • workload.py: A customer analytics workload that allocates heavily in NumPy and pandas.
  • offline_profile.py: A CLI entrypoint for one-off memray run --native captures.
  • pyproject.toml / uv.lock: Project metadata and locked dependencies for uv.
  • render.yaml: Render Blueprint for deploying the example with a persistent disk.

Why this pattern works well on Render

Using memray.Tracker(..., native_traces=True) around a single request lets you capture one expensive path without running the entire service under a profiler all day. That is a better fit for a production-like Render service than starting the server itself with memray run.

The service also writes captures to /var/data/memray, which is on a persistent disk in render.yaml. That matters because Memray captures can be large and you usually want them available after the request completes.

Local development

Create a virtual environment, install dependencies, and start the service:

uv sync
export MEMRAY_PROFILE_TOKEN=local-dev-token
uv run uvicorn app:app --reload

Trigger a profile:

curl -X POST http://127.0.0.1:8000/profile/native \
  -H 'Content-Type: application/json' \
  -H 'X-Profile-Token: local-dev-token' \
  -d '{"rows": 400000, "customers": 35000, "top_n": 12}'

List available captures:

curl http://127.0.0.1:8000/profiles \
  -H 'X-Profile-Token: local-dev-token'

Open the generated flamegraph from the output path returned by the API, or download it directly:

curl -OJ http://127.0.0.1:8000/profiles/<run-id>/flamegraph \
  -H 'X-Profile-Token: local-dev-token'

One-off CLI capture

If you want the simplest possible Memray command on a Render shell, use the shared workload directly:

uv run memray run --native -o /var/data/memray/manual-run.bin \
  python offline_profile.py --rows 400000 --customers 35000 --top-n 12

Then generate the HTML report on the same machine:

uv run memray flamegraph -o /var/data/memray/manual-run.html /var/data/memray/manual-run.bin

Deploying on Render

  1. Create a new Blueprint service from this repository.
  2. Render provisions the MEMRAY_PROFILE_TOKEN environment variable automatically.
  3. After the service is live, copy the token value from the dashboard.
  4. Trigger the profiling endpoint against your Render URL:
curl -X POST https://your-service.onrender.com/profile/native \
  -H 'Content-Type: application/json' \
  -H 'X-Profile-Token: <token-from-render>' \
  -d '{"rows": 400000, "customers": 35000, "top_n": 12}'
  1. Download the capture or flamegraph:
curl -OJ https://your-service.onrender.com/profiles/<run-id>/capture \
  -H 'X-Profile-Token: <token-from-render>'

curl -OJ https://your-service.onrender.com/profiles/<run-id>/flamegraph \
  -H 'X-Profile-Token: <token-from-render>'

Notes

  • MEMRAY_MAX_ROWS limits how large a single capture request can be.
  • Only one profile runs at a time. The service returns 409 if another capture is already in progress.
  • Native symbol resolution is best when you generate the report on the same Render instance that created the capture.
  • Render automatically makes uv available for Python services when uv.lock is present in the repo root.

About

An example of memray profiling on Render

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages