# Performance

Fregata is shaped to do as little work on the CPU as possible. The
ideal idle profile on a 4–6 camera install:

- **CPU**: 4-8 % across all cores. Most of it is ffmpeg parsing
  RTSP and nginx serving the web UI.
- **GPU**: ~0 %. Detection runs on the ANE, not the GPU.
- **ANE**: barely visible in `powermetrics` or `macmon` because individual
  inferences are 1–2 ms.
- **Memory**: 1–2 GB resident, several minutes after startup.

If your numbers are noticeably off that, this page is the right
place to start.

## Where to look first

The web UI's **System** tab has live charts for:

- **Detector inference time** — the per-frame ms for each detector.
  Should plateau in the 1–2 ms range on an M4 ANE.
- **Camera FPS** — actual decoded FPS per camera.
- **Process CPU** — broken out by sub-process (per-camera ffmpeg, nginx, go2rtc).

## "My CPU is at 100 %"

### 1. Detector fell off the ANE

If `Detector inference time` is 50+ ms, you're on CPU. Restart and
check the warmup log; common culprit is an unsupported op in a
custom model.

### 2. Software decode

If your camera's RTSP isn't H.264 or HEVC (e.g. MJPEG), VideoToolbox
can't accelerate the decode. ffmpeg falls back to software, and the
CPU pays. The fix is usually one of:

- Switch the camera's stream to H.264 in its own settings.
- Run the camera through go2rtc with a transcode step (Frigate's
  `go2rtc` config block can do this).

### 3. Detection FPS is too high

A surprisingly common source of unnecessary CPU is `detect.fps`
left at the camera's native rate (often 25 or 30 FPS). Inference
runs at this rate per camera — independent of the recording
stream, which always captures at the camera's native FPS for
playback.

:::note[In no-sub-stream mode: tune FPS in `config.yml`, not on the camera]
In the default **no-sub-stream** setup (one stream per camera,
used for both detection and recording): **don't lower the FPS
in the camera's own settings** to try to slow detection down.
The camera should keep streaming at its native FPS (15, 25, 30,
whatever) so the recording captures playback-quality video.
Tune `detect.fps` in `config.yml` instead.

If you're running a **separate detection sub-stream**, the
sub-stream's own FPS in the camera firmware is the right knob
to turn down — but the main / recording stream still belongs
at native FPS.
:::

**Don't set `detect.fps` above 10.** Even though the ANE has the
headroom, going higher offers no detection-accuracy benefit
(detections are per-frame, not per-second), and it trips
Frigate's own config validator, which logs `"Recommended value
is 5"` on every camera with `detect.fps > 10`. The work is real
ANE cycles and heat for no actual improvement.

5 FPS is plenty for most scenes; 10 FPS makes sense if
you have fast-moving objects such as cars racing down a busy street. Pick the lowest value that catches
what you need.

```yaml
cameras:
  driveway:
    detect:
      fps: 10
```

For deeper guidance on `detect.fps` and on `detect.width` /
`detect.height` (matching detection to your camera's main-stream
resolution — Fregata runs detection on the full stream by
default, no sub-stream needed), see
[Detection tuning → Detection resolution and FPS](/guides/detection-tuning/#detection-resolution-and-fps).

If `detect.fps` is already sensible and CPU is still pegged on
older hardware, *then* consider a separate low-resolution
sub-stream for detection — the rare case where the two-input
pattern is actually useful on Fregata. See
[Cameras — Sub-streams: optional power saver](/reference/cameras/#sub-streams-optional-power-saver).

## Recordings encoder

Fregata's default ffmpeg presets on macOS:

- **Decode (every input):** `-hwaccel videotoolbox`
- **Recording encode (default):** `h264_videotoolbox -allow_sw 1`
- **Re-stream (RTSP, for go2rtc):** `h264_videotoolbox -allow_sw 1`

The `-allow_sw 1` flag means the encoder will fall back to software
if VideoToolbox can't service the request. On healthy hardware that
fall-back never fires, but it's a reasonable safety net.

## RAM-disk cache

Fregata buffers high-frequency intermediate files (detection
frames, preview snapshots, IPC sockets, the nginx and go2rtc
caches) in a RAM-backed volume rather than hammering the SSD.
There are **two backings**, and **you pick one in the welcome
wizard's "Memory for recordings" step** on first launch:

| Option in the wizard | Backing |
| --- | --- |
| **Smart memory · recommended** | tmpfs (sparse, demand-paged) |
| **Basic RAM disk** | HFS+ disk image (pre-allocated, wired) |

The default (if you haven't completed the wizard yet) is
**Smart memory**. Whichever mode is in effect is logged at
startup &mdash; look for `Cache backing: …` in the Frigate log.

If you picked **Smart memory** but the privileged helper isn't
approved or fails to mount at runtime, Fregata transparently
falls back to the **Basic RAM disk** for that session.

### Smart memory (tmpfs — sparse, demand-paged)

A tmpfs RAM filesystem with a sparse 1 GB cap that only charges
memory for the bytes actually written. A largely-idle 4-camera
install will sit at well under 100 MB; even a busy install will never need more than 1 GB in a healthy state.

The mount lives at a deliberately-hidden path under
`~/Library/Caches/com.3rdbitlabs.fregata/temp` so that Finder
and Spotlight don't surface it. The menu-bar tray's
**Settings → Folders → Open Cache Folder** item is disabled
while Smart memory is active, for the reason in the next
callout.

:::danger
**Do not open the Smart memory mount in Finder.** A Finder
vnode walk into the in-memory volume has been observed to trip
an Apple tmpfs-kext kernel panic on macOS 26 in testing &mdash;
the entire OS hangs and the Mac reboots. That's why the mount
path is hidden and why the tray's Open Cache Folder item is
disabled in this mode.

If you somehow navigate there with **Go → Go to Folder…**, close the Finder window immediately: do not list
the contents from Finder, do not right-click anything inside,
and do not write to it from the GUI. The cache volume is
managed entirely by Fregata; you never need to touch it.

This is a macOS kernel bug, not a Fregata bug. We've worked around it by moving the folder to an unlikely to access path. Once macOS fixes this bug (we reported it) we will adjust the mount path.
:::

### Basic RAM disk (HFS+ disk image — pre-allocated, wired)

An HFS+ disk image attached via `hdiutil`, mounted at
`~/Fregata/temp`. Unlike Smart memory, this backing
**pre-allocates its entire size as wired RAM** the moment it
mounts, whether or not anything's written to it &mdash; that's
the trade-off in exchange for not needing a privileged helper.

To keep wired-memory cost reasonable, Fregata computes the size
from your camera config &mdash; a 4-camera 1080p install ends up
around 256 MB.

You can override the size:

- **Tray → Settings → Environment Variables** → set
  `FRIGATE_CACHE_SIZE_MB=1024` (or whatever) and restart.
  Sets the ceiling for the auto-sized formula (1024 MB is the
  hard upper bound regardless).
- Leave it unset (the default) to let the launcher pick.

This setting does NOT apply to Smart memory &mdash; that mode's
1 GB sparse cap is fixed.

Both backings unmount automatically when Fregata quits. You
don't need to manage either one manually.

:::caution
Don't drop the cache size below ~200 MB even on a one-camera
install. The previewer and IPC sockets need a working set big
enough to keep up with the recording pipeline.
:::

## Thermals on laptops

Fregata is unusually thermal-friendly because the ANE and the media
engine run cool. Even on a fanless MacBook Air, a 6-camera install
won't push the chassis past warm.

## Perf checklist

When something feels slow, work top-to-bottom:

1. **Inference tier** — ANE (1–4 ms) ✅, GPU (5–15 ms) ⚠️, CPU
   (40+ ms) ❌. 
2. **Decode acceleration** — verify the input codec is H.264 or
   HEVC. `mediainfo` or ffprobe will tell you.
3. **Disk write speed** — `iostat -d 5 5` while recording. If
   write latency is >50 ms, the disk is the bottleneck.
4. **Network jitter** — `mtr` from the Mac to each camera.
   Anything above 5 ms on a LAN is a sign of bad Wi-Fi.
5. **Process count** — open Activity Monitor, group by process
   name. Ten ffmpeg processes for ten cameras is fine; thirty for
   ten cameras means you're decoding more streams than you should.
6. **Detection FPS vs camera FPS** — match `detect.fps` to a sane
   number (5 is plenty for most outdoor cameras). Add a sub-stream
   only if that's not enough.

If you want a hand reading the output, see
[Troubleshooting](/guides/troubleshooting/) or open a discussion on
GitHub with the perf logs attached.
