Files
felhom.eu/documentation/audits/sizing-check-2026-10-14/CHECK.md
T

195 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Sizing check 2026-10-14 — do the estimator's numbers hold on a second machine, with apps together?
Box: demo-hp (AMD Ryzen Embedded V1756B, 4 cores / 8 threads, 29,994 MiB), guest 9201. Tools: the sizing bench
(`sizing-2026-10-13/tools/`: `bench.py`, `guest_sampler.sh`, `host_sampler.sh`, `actions.sh`) pointed at demo-hp — only the
box constants change. „Page says" figures are computed with `scripts/test_build_sizing_web.py`'s mirror of `sizing.js`
on `website/assets/sizing-data.json` (no JavaScript runtime on DooPlex). Deploys through the product; path fields take
their default (the enrolled drive). The box already runs 11 apps of its own (Home Assistant and Paperless among them);
they stay, and they are measured as they are.
## Predictions (written 00:20 UTC, before any deploy)
| Item | Page says | Prediction |
|---|---|---|
| „Just files and passwords" at rest (nextcloud + vaultwarden) | typical 314 + 44 MB; peak 525 + 99 MB | measured rest below the page's typical (N100 figures were taken idle) — 250–400 MB together |
| Immich during a 200-photo import, with the others busy too | peak 3,061 MB | 2.0–3.0 GB (the HP's faster CPU ends the ML jobs sooner, the peak is the same model loading) |
| Jellyfin forced transcode | peak 373 MB | 300–600 MB (`used` counts the file cache of the video) |
| Paperless 20 scans (consume folder) | peak 659 MB | 600–900 MB (OCR workers) |
| The set's real peak, all working at once, vs the page's sum of peaks (5,045 MB + platform 470) | 5,515 MB | **the real simultaneous peak is 60–80 % of the sum** — the page's „all at peak at once" is pessimistic, as it says |
| Platform (controller, traefik, cloudflared, filebrowser) | 470 MB | 350–500 MB |
## R1 — the numbers together (evidence `evidence/R1-set/`, summary `set-summary.json`)
Windows (UTC): rest A 00:18:02–00:48:02 (files + passwords only; the 00:30 db-dump falls inside); **together**
00:51:00–00:54:44 (Immich 200-photo import + its ML jobs, Jellyfin scan + forced 1080p transcode, Nextcloud 50 × 10 MiB
WebDAV upload — all three at once); Paperless 20 scans 01:01:40–01:08:33 (alone: the bench first put the scans in a
sub-folder, which Paperless does not read — moved at 01:01:40); rest B 01:08:40–01:29:30. `used` = memory.current −
inactive_file, per app summed over its containers (the sizing run's definition). No OOM kill anywhere (`memory.events`).
| App | Page typical | HP rest (median) | Diff | Page peak | HP peak (`used`) | Diff | HP `memory.peak` (incl. file cache) |
|---|---|---|---|---|---|---|---|
| immich | 1,356 | 1,557 | +15 % | 3,061 | 3,290 (during the import) | +7 % | 4,366 |
| jellyfin | 191 | 188 | −2 % | 373 | 448 (transcode) | +20 % | 497 |
| nextcloud | 314 | 229 | −27 % | 525 | 290 | **−45 %** | 808 |
| home-assistant (the box's own) | 318 | 352 | +11 % | 328 | 434 (after the 00:09 start) | **+32 %** | 441 |
| vaultwarden | 44 | 37 | −16 % | 99 | 40 | **−60 %** | 45 |
| paperless-ngx (the box's own) | 568 | 645 | +14 % | 659 | 755 (OCR) | +15 % | 903 |
| platform containers (controller, traefik, cloudflared, filebrowser) | 255 of the page's 470 (the other ~220 MB are the Docker daemons, not in any container — `build_sizing_web.py`) | 262 (rest B) – 347 (rest A) | +3 to +36 % | — | 386 | — | — |
| The set | Page (site rule) | Measured on the HP | Difference |
|---|---|---|---|
| „Just files and passwords": typical (sum) | 358 (+ platform 470 = 828) | 210 at rest (rest A); 265 after use | **−41 %** / −26 % |
| „Just files and passwords": peak | 624 (+ 470 = 1,094) | 326 (the 00:30 db-dump) | **−48 %** |
| „Family starter set": typical (sum) | 2,791 | 3,007 (rest B) | +8 % |
| „Family starter set": peak — the page's sum of peaks vs the **real** peak with three heavy apps busy at once | 5,045 (+ 470 = 5,515) | **4,900** at 00:52:35 (Paperless at rest then; with its OCR at the same time it would be ~5,100) | −3 % (≈ −0 % with Paperless) |
| platform | 470 (containers 255 + Docker daemons ~220) | containers 262–386; the daemons not sampled | the container part matches; the whole not measured |
| host's share (page: box − guest) | 32 GB box: 4,708 MB (box − guest 28,060 MiB) | not separable here: the HP host also runs Tester 1's 8 GB VM. Host used (MemTotal − MemAvailable) 13.4 GB in rest B, of which the guest's anon 3.8 GB | — |
**Prediction check:** „the real simultaneous peak is 60–80 % of the sum" — **wrong**. It was 97 %. Immich's import
peak alone is 65 % of the set's peak, and it coincides with Jellyfin's transcode and Nextcloud's upload as soon as a
family uses the box at the same time. The page's „all at peak at once" is not pessimistic for this set; it is about
right. The light apps (Nextcloud, Vaultwarden) are over-stated (corrected 07:30: an earlier draft compared the platform's containers with the whole 470 MB, which includes the Docker daemons); Immich, Jellyfin, Home Assistant are
under-stated.
### Second opinions for free — the box's own apps, sampled in the same run
Five of the 24 weakest page figures (source `telemetry` or `onboarding` **and** the sources disagree,
`sizing-2026-10-13/evidence/apps-table.json`) are apps this box already runs; R1 sampled them all night.
| App | Page source | Page typical | HP rest (median, rest B) | Diff | Page peak | HP peak (`used`, whole run, incl. the 00:09 start) | Diff |
|---|---|---|---|---|---|---|---|
| bookstack | telemetry | 159 | 148 | −7 % | 225 | 222 | −1 % |
| calibre-web | telemetry | 191 | 161 | −16 % | 413 | 242 | **−41 %** |
| kimai | telemetry | 163 | 155 | −5 % | 240 | 250 | +4 % |
| privatebin | telemetry | 40 | 38 | −5 % | 59 | 60 | +2 % |
| bentopdf | telemetry | 5 | 10 | +100 % (5 MB) | 10 | 15 | +50 % (5 MB) |
## R3 — are the page's three answers true on an 8 GB box?
**Where (decided by CC, 03:15):** scratch guest **9202**, not 9201. 9201 runs 11 apps of its own (2.6 GB at rest) that the
page's selection does not include; on a 4 GB guest they would decide the result. 9202 holds only the platform and a
Paperless — what the page models: the box plus the selected apps. Paperless is stopped for the first two selections and
started for the family set (it is part of it). **Memory:** `pct set 9202 --memory 4096` (the installer's
`autosize_guest_caps()` for an 8 GB box, = the page's `guestMib(8)`; was 25,898), swap 512 (Proxmox's default; the
installer sets none). **Restart:** the dashboard's restart answered 503 „agent not configured" — 9202 has no agent link
by design — so `pct reboot 9202`.
**Predictions (03:19, before any deploy):**
| Selection | Page says on 8 GB | Prediction |
|---|---|---|
| „Just files and passwords" | fits well | fits: no OOM kill, no swap, upload as fast as on 9201 |
| Immich alone | fits, but tight | works: no OOM kill; some swap during the ML jobs; the import 10–50 % slower than on 9201 |
| „Family starter set" | does not fit | real harm while all work at once: swap full, at least one OOM kill (most likely Immich's machine learning) or an app restart, the actions much slower |
### R3 results (evidence `evidence/R3-8gb/`, `evidence/R3b-family/`; counters from the guest cgroup `lxc/9202`)
The deploy itself warned from the second app on: „Az alkalmazások csúcsterhelése meghaladhatja a rendelkezésre álló
memóriát…" (Immich alone and every family app; not for files + passwords) — the product's own check agrees with the page.
„Hit the 4 GB limit" (`memory.events max`) happens in every selection — that is the file cache being reclaimed, not harm.
| Selection | Page says on 8 GB | OOM kills | Swap (512 MB) | The action | Every app answers? | Measured result |
|---|---|---|---|---|---|---|
| „Just files and passwords" | fits well | **0** | 19 MB | Nextcloud 50 × 10 MiB upload: 28 s, 50/50 | yes | **fits well — true** |
| Immich alone | fits, but tight | **14** — all in Immich's machine-learning container, at its own 1.5 GiB catalog limit (the same limit was reached on the big guest without a kill) | **full** (512 MB peak) | 200-photo import + jobs: 295 s (big guest: 221 s with two other apps busy), 200/200 | yes | **tight — true**; it works, slower, with ML workers killed and restarted |
| „Family starter set", run 1 (5 of 6: Nextcloud refused at install — its old data from run 1 was kept, 409 `kept_data_choice`) | does not fit | +2 | full; load average **151** on 4 cores | Immich upload 196/200 in 7.5 min (`immich-server` restarted); Paperless 20/20 | yes, after | harm |
| „Family starter set", run 2 (all 6, `R3b-family`) | does not fit | +4 (20 since the start) | full | Immich **116/200** (84 failed; `immich-server` restarted); Jellyfin transcode **1,322 s** (big guest: 87 s); Nextcloud 49/50 (one 503); Paperless **0/20** in 30 min | yes, after the work | **does not fit — true**: real harm |
**All three answers held on the 8 GB box.** The prediction for „Immich alone" (no OOM kill) was wrong: the ML container is
killed at its own limit when the guest is short of memory.
## R2 — the night backup next to the family set (evidence `evidence/R2-night/`, 01:32–02:51 UTC)
Tier 2 (01:30, 12 s) fell between the two samplings; Tier 1 (00:30, the database dumps) fell in R1's rest A. The
apps on 9201 at the time: the box's 11 + the bench's 4 (immich, jellyfin, nextcloud, vaultwarden).
| Window (UTC) | Controller container (Tier 3's restic runs inside it) | All apps in the guest (`used`) | Host used (MemTotal − MemAvailable) | Host CPU busy |
|---|---|---|---|---|
| quiet, 01:35–02:14 | 189 MB median, 209 max | 4,370 median | 13,323 median | 9 % median |
| Tier 3 restic → Storage Box, 02:15–02:18 (3 min 27 s, 11 apps, 120 snapshots) | 170 median, **308 max** (+~120 MB) | 3,901 median, 4,361 max | 12,943 median, 13,463 max | 30 % median, 69 % max |
| whole-guest vzdump on the HOST, 02:42–02:51 (cut by R3) | 84 median (the quiesce pauses apps) | 3,654 median | 13,480 median, **14,619 max** (+~1.1 GB, on the host) | 25 % median, 100 % max |
| Tier 1 db dumps, 00:30 (R1 rest A) | — | „files + passwords" peaked at 326 MB then (+~115 MB over its rest) | — | — |
**What the 1.5 headroom is for, measured:** inside the guest the backups add little — about 120 MB for Tier 3's restic and
about 115 MB for a database dump; apps do not grow during them. The big one, the whole-guest vzdump + zstd, runs **on the
host**, outside the guest's memory: +1.1 GB of host memory. On an 8 GB box the host keeps about 4 GB (box − guest), so it
fits there. So the backups use a small part of the headroom; on this box the headroom was really used by the apps' own
peaks working at once (R1) — and on 4 GB that is not enough (R3).
## R4 — second opinions for the weakest figures (evidence `evidence/R4-b1..b4/`, `summary.json` from the sizing run's `analyze.py`)
The 24 weakest page figures (`apps-table.json`: source `onboarding` or `telemetry` **and** the sources disagree): 3 were
measured in R1 (immich, nextcloud, vaultwarden), 5 are the box's own apps (table above), the other **16** ran here in four
batches on scratch guest 9202 at full memory (06:00–07:25 UTC): deployed through the product, 15 min at rest, removed
(no leftovers). These are **light batches — no action** (as the sizing run's light batches): the rest figure is a fair
second opinion; the „peak" here is only the start-up peak, so a page peak that includes real work reads higher.
| App | Page source | Page typical | HP rest | Diff | Page peak | HP peak (rest batch, no action) | Diff | OOM |
|---|---|---|---|---|---|---|---|---|
| grafana | onboarding | 220 | 269 | +22 % | 435 | 383 | -12 % | 0 |
| grimmory | onboarding | 346 | 451 | **+30 %** | 1095 | 624 | -43 % | 0 |
| karakeep | onboarding | 361 | 372 | +3 % | 1050 | 643 | -39 % | 0 |
| mealie | onboarding | 273 | 226 | -17 % | 431 | 240 | -44 % | 0 |
| n8n | onboarding | 321 | 351 | +9 % | 550 | 578 | +5 % | 0 |
| sparkyfitness | onboarding | 305 | 316 | +4 % | 664 | 410 | -38 % | 0 |
| uptime-kuma | onboarding | 103 | 118 | +15 % | 227 | 119 | -48 % | 0 |
| wishlist | onboarding | 115 | 118 | +3 % | 184 | 121 | -34 % | 0 |
| crafty-controller | onboarding | 78 | 79 | +1 % | 84 | 80 | -5 % | 0 |
| emby | onboarding | 142 | 136 | -4 % | 146 | 142 | -3 % | 0 |
| gitea | onboarding | 74 | 76 | +3 % | 136 | 89 | -35 % | 0 |
| grocy | onboarding | 30 | 33 | +10 % | 114 | 34 | -70 % | 0 |
| lubelogger | onboarding | 53 | 56 | +6 % | 113 | 65 | -42 % | 0 |
| metube | onboarding | 62 | 62 | +0 % | 329 | 63 | -81 % | 0 |
| qbittorrent | onboarding | 163 | 18 | **-89 %** | 318 | 18 | -94 % | 0 |
| transmission | onboarding | 6 | 6 | +0 % | 22 | 7 | -68 % | 0 |
At rest, 14 of 16 agree within ±30 %. Two differ: **grimmory +30 %** (451 vs 346) and **qbittorrent −89 %** (18 vs 163 —
idle with no torrent; the page's figure is from a household's onboarding note with torrents running, so the HP figure is
the weaker one here). No OOM kill.
## Apps that differ from the page by more than 30 % (one line each)
| App | Figure | Page | HP | Basis |
|---|---|---|---|---|
| nextcloud | peak | 525 | 290 (−45 %) | 50 × 10 MiB upload, alone and with others |
| vaultwarden | peak | 99 | 40 (−60 %) | light use |
| home-assistant | peak | 328 | 434 (+32 %) | the start after a boot |
| calibre-web | peak | 413 | 242 (−41 %) | the box's own, all night |
| grimmory | typical | 346 | 451 (+30 %) | rest batch |
| qbittorrent | typical | 163 | 18 (−89 %) | rest batch, no torrents |
| bentopdf | typical / peak | 5 / 10 | 10 / 15 | +5 MB only |
## Proposal — for the operator; nothing on the website changed tonight
**One answerable question:** should the page's figures move with tonight's measurements?
| Option | What changes | Cost | If nothing is done |
|---|---|---|---|
| **A (recommended)** — small figure update | Immich peak 3,061 → 3,300; Jellyfin peak 373 → 450; Home Assistant peak 328 → 435; Nextcloud peak 525 → 300; Vaultwarden peak 99 → 45; Grimmory typical 346 → 450. Keep the headroom (1.5), the platform (470) and every verdict | one data edit + the page's data file rebuilt; the „Family starter set" peak moves +144 MB (5,515 → 5,659): its verdicts stay (8 GB no, 12 GB tight, 16 GB well) | the page stays inside ±10 % for the family set; three apps keep a peak that reads low |
| B — also a sentence for Immich on 8 GB | „Immich works on 8 GB, but its face and search jobs restart under memory pressure" next to the „tight" verdict | one string in two languages | a household on 8 GB with Immich sees slow, restarting background jobs with no explanation |
**The three answers on an 8 GB box were all true** (R3): files + passwords fit well (0 OOM kills), Immich alone is tight
(it works; 14 OOM kills in its ML container, swap full), the family set does not fit (84 of 200 photo uploads failed,
transcode 15× slower, Paperless did nothing in 30 min). The headroom of 1.5 is not too strict: the family set's real
simultaneous peak was 97 % of the page's sum. Register row R-1009.
## 2026-10-14 — the operator's „raise only" ruling, built and STOPPED before the push
The rule was built as a source (`raise-only-source.patch` for `sizing-2026-10-13/tools/build_sizing.py`; the HP figures
from the evidence by `tools/hp_figures.py` → `hp-figures.json`, 27 apps, `used` basis). It raises 23 figures and lowers none
(Immich typical 1,356 → 1,557 and peak 3,061 → 3,290; Jellyfin peak 373 → 448; Home Assistant 318 → 352 / 328 → 434;
Paperless 568 → 645 / 659 → 755; Grimmory typical 346 → 451; and 17 small ones). The presets keep their verdicts (family
5,515 → 6,021 MB: 8 GB no, 12 GB tight, 16 GB well; files + passwords 1,094 unchanged; Immich alone 3,531 → 3,760: 8 GB tight).
**But one verdict of the `SIZING.md` §5 table changes:** „Household set without Immich" on 8 GB — **fits well → fits, but
tight**. Its peak becomes 2,731 MB; × 1.5 = 4,096.5 MB against the 8 GB guest's 4,096 MB: **0.5 MB over**. Not one figure
does it: without the Jellyfin raise, or the Home Assistant raise, or the Paperless raise, it stays „fits well". By the
task's STOP rule the website was **not** pushed; the data changes were reverted (nothing half-built is committed).
| Option | What happens | Cost |
|---|---|---|
| A — publish the raise as ruled; accept the one changed verdict | „5 apps without Immich on 8 GB" reads „fits, but tight"; `SIZING.md` §5 and the test case updated | the page is 0.5 MB pessimistic there |
| B — raise only, but round the HP figures to the nearest 10 MB **down** | to be checked: it may still flip | one rule sentence |
| C — keep today's figures | nothing changes; the HP's higher figures stay unused | the page reads low for Immich, Jellyfin, Home Assistant, Paperless |