Skip to content

Performance & Hardware

Engram runs comfortably on modest hardware, but a few choices — GPU vs CPU for transcription, where you put the staging directory, and how many matches run in parallel — make a large difference to how fast a stack of discs gets through the pipeline. This page explains the knobs that already exist and how to plan hardware around them.

The expensive stages are ripping (disk + optical drive throughput, handled by MakeMKV) and episode matching (audio transcription via faster-whisper). Everything else — identification, organization, the dashboard — is cheap by comparison.

Hardware at a glance

These are practical recommendations, not enforced minimums. Engram will start and run on less.

Component Works on Recommended Why it matters
CPU Any modern 64-bit CPU 4+ physical cores More cores let you raise max_concurrent_matches so several titles transcribe at once.
RAM ~4 GB 8 GB+ The Whisper model plus ripping buffers; more headroom helps when matching several titles in parallel.
GPU None — CPU is fully supported NVIDIA GPU with CUDA Optional. Speeds up matching only (not ripping). Auto-detected when present.
Storage (staging) HDD / NAS SSD on the same volume as your library Transcription re-reads each file, and same-volume organization is an instant rename instead of a full copy.

GPU acceleration (faster-whisper ASR)

Episode matching transcribes each ripped title with faster-whisper, which runs on NVIDIA CUDA via CTranslate2. GPU transcription is several times faster than CPU for the same model — the single biggest lever on matching throughput.

GPU acceleration is opt-in and available on Windows and Linux with an NVIDIA GPU. macOS and AMD GPUs have no GPU path in the engine and always run on CPU (int8).

Enable it

In Settings → Matching → GPU Acceleration:

  1. When an NVIDIA GPU is detected, Engram offers a one-time Download & enable (after you accept the NVIDIA CUDA EULA). The required cuDNN + cuBLAS libraries (~1.2 GB) are not bundled into the build — they're fetched on demand into ~/.engram/cuda/, where they persist across app updates (like your database and subtitle cache).
  2. The download runs in the background; you can keep using Engram while it completes.
  3. Restart the backend to activate. Matching then runs on the GPU using the best compute type your card supports — float16, or int8_float16/float32 on older GPUs (e.g. Pascal) that can't do float16. CPU continues to use int8.

This works in the prebuilt standalone build — the CUDA libraries are downloaded at runtime, not compiled in. (Developers running from source can instead install them via pip with uv sync --extra gpu; see below.)

Docker

In a container, GPU access additionally requires the host NVIDIA driver, the NVIDIA Container Toolkit, and running with --gpus all. With those in place the same in-app download applies. See the Docker guide.

Verify which backend is active

Engram exposes the resolved ASR runtime at GET /api/asr-status (also shown as the ASR badge on the dashboard). The device field is the effective device — what transcription actually runs on — so the badge can't claim CUDA while silently falling back to CPU:

curl http://localhost:8000/api/asr-status
{
  "device": "cuda",
  "compute_type": "float16",
  "model": "small",
  "workers": 4,
  "cpu_threads": null,
  "max_concurrent_matches": 4,
  "gpu_detected": true,
  "gpu_enabled": true,
  "gpu_runtime_installed": true,
  "gpu_state": "active"
}

gpu_state tells you exactly where you stand:

  • active — running on the GPU.
  • available_not_enabled / available_not_installed — an NVIDIA GPU is present but acceleration is off, or the runtime hasn't been downloaded yet. The dashboard badge shows CPU · GPU available →; click it to open Settings.
  • downloading / installing — the CUDA runtime download is in progress.
  • unsupported_os — macOS or another platform with no NVIDIA path.
  • unavailable — a supported OS with no NVIDIA GPU.

Running from source (developers)

When running from source you can install the CUDA libraries via pip instead of the in-app download:

cd backend
uv sync --extra gpu

Engram falls back to these pip-installed libraries automatically, so the GPU Acceleration setting reports the runtime already installed — just enable it and restart.

Whisper model

The matcher currently uses the small model (≈465 MB, English-capable, good accuracy on CPU). It is hardcoded — there is no user-facing model selector yet. For reference, faster-whisper models trade size for accuracy and speed:

Model Disk size Quality Speed GPU
tiny 75 MB basic fastest not required
base 145 MB good fast not required
small (default) 465 MB better medium not required
medium 1.5 GB best slow recommended
large-v3 3 GB best slowest 10 GB+ VRAM

The model downloads once on first use and is cached locally; larger models also use proportionally more memory (VRAM on GPU, RAM on CPU).

Storage: SSD vs HDD vs NAS

Ripped and imported MKVs land in the staging directory (staging_path) first, then get moved into your library when a job completes.

Keep staging and your library on the same volume

Organization uses an atomic shutil.move(). On the same filesystem that's an instant rename — no data is copied. Across different volumes (e.g. staging on your system SSD, library on a NAS) it becomes a full copy-then-delete of every file, which is slow and uses temporary double space. Put staging_path, library_movies_path, and library_tv_path on the same drive when you can.

Beyond the move, transcription reads each title's audio repeatedly while sampling it. That makes staging I/O latency matter:

  • SSD — recommended for staging. Fast random reads keep matching fed.
  • HDD — works fine; expect somewhat slower matching and (cross-volume) organization.
  • NAS / network share — usable for the final library, but avoid it for staging: network latency and seek times slow both transcription and the copy fallback. If you must stage on a NAS, expect noticeably longer matching.

Sizing the staging directory

Staging needs roughly (number of discs ripping at once) × (disc size) of free space, plus headroom for the copy fallback if your library is on another volume. A dual-layer Blu-ray rip can be 30–50 GB; a DVD is a few GB. Staging is reclaimed automatically per the staging_cleanup_policy setting (default: delete on success).

Concurrency tuning

max_concurrent_matches (default 2) controls how many titles transcribe in parallel. It's the main throughput knob once ripping is done.

How it works under the hood:

  • One shared Whisper model serves all matches (using faster-whisper's num_workers), so raising the value adds CPU/RAM pressure, not duplicated model weights/VRAM.
  • The value is clamped to your hardware by resolve_asr_runtime(): on CPU it's capped at your physical core count (and CPU threads are divided across workers to avoid oversubscription); on GPU it's capped at 4 parallel streams.
  • It also sizes the matching admission semaphore, so at most that many titles show MATCHING at once; the rest wait in QUEUED. (You'll see this on the dashboard during a multi-title disc or bulk import.)

Guidance:

  • CPU-only, multi-core: raising it to ~4–8 (within your core count) speeds up bulk work.
  • GPU: keep it modest to avoid VRAM spikes; the GPU cap of 4 already bounds it.

Takes effect after a restart

num_workers is fixed when the Whisper model loads, so changes to max_concurrent_matches apply on the next backend restart.

Bulk imports and large libraries

There's no special batch parallelism for big imports — many files and seasons are naturally serialized by the matching semaphore, so steady-state matching throughput is roughly max_concurrent_matches titles at a time. Practical advice for migrating a large library:

  • Raise max_concurrent_matches to suit your cores/GPU before starting.
  • Make sure the precomputed subtitle cache is in place (it ships and installs on first run) so matching isn't waiting on subtitle downloads.
  • Kick off large imports when you don't need the machine, and watch the dashboard ASR badge to confirm workers > 1.

See the Import Watch Folder guide for how to feed Engram a whole library of pre-ripped files.

Troubleshooting performance

Symptom Likely cause What to check
Many titles MATCHING but only one progresses; low CPU Only one ASR worker is active GET /api/asr-status — if workers is 1, raise max_concurrent_matches and restart
Matching slower than expected on a capable PC Running on CPU unexpectedly device in /api/asr-status; verify your CUDA install / use a --extra gpu source build
Organization step is slow / uses lots of temp space Staging and library are on different volumes Move them onto the same filesystem so the move is an atomic rename
Identification stalls or is slow Network latency to TMDB / subtitle / TheDiscDB services This affects identification only, not ripping; check connectivity
Staging fills up the disk Concurrent rips × disc size exceeds free space Free space, or stagger rips; confirm staging_cleanup_policy