docs: add a guide for running EOS on small devices (#1379)

Collect the settings that bring EOS from about 290 MB idle / 400-450 MB
during a GENETIC run down to about 140 MB, with the measurements behind
them: fitness cache, timezone override and SciPy-free self-consumption
tables (#1376, #1377, #1378), autosave for SD/eMMC storage, and the glibc
allocator and BLAS environment. Includes run times on a Raspberry Pi 4 and
an x86 VM with data of a real installation.

Co-authored-by: Christin <christin@BigBrother.bikini.bottom.zone>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Christin
2026-10-11 08:40:47 +02:00
committed by GitHub
co-authored by Christin Claude Opus 5.5
parent 3651d33915
commit ecec39fcd8
2 changed files with 117 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
% SPDX-License-Identifier: Apache-2.0
(smalldevices-page)=
# Running EOS on Small Devices
EOS runs on single-board computers with 512 MB to 1 GB of RAM and on eMMC or SD storage.
With the default configuration it needs about 290 MB at idle and 400–450 MB while a GENETIC
run is in progress. The settings on this page bring that down to about 140 MB, without
changing the optimization result.
All figures below were measured with GENETIC at 300 individuals × 400 generations and
15-minute slots; the individual measurements state their conditions.
## Summary
| Setting | Effect | Plan |
|---|---|---|
| `optimization.genetic.fitness_cache_max_entries: 0` [^pr1376] | −110 to −160 MB peak per run | identical |
| `general.timezone_override` [^pr1377] | −28 MB at startup (no timezone lookup) | identical |
| `optimization.self_consumption_interpolator: numpy` [^pr1378] | −37 MB after the first run (no SciPy) | identical |
| `database.autosave_interval_sec: null` | storage writes from ~13 MB/min to ~1 KiB/min | identical, see notes |
| `PYTHONMALLOC=malloc` (environment) | memory is returned after each run (glibc) | identical |
| `OPENBLAS_NUM_THREADS=1` (environment) | no per-core BLAS buffers | identical |
[^pr1376]: Added by [#1376](https://github.com/Akkudoktor-EOS/EOS/pull/1376).
[^pr1377]: Added by [#1377](https://github.com/Akkudoktor-EOS/EOS/pull/1377), which also imports
optional heavy packages on first use (−123 MB at startup without any configuration change).
[^pr1378]: Added by [#1378](https://github.com/Akkudoktor-EOS/EOS/pull/1378).
Example configuration:
```json
{
"general": { "timezone_override": "Europe/Berlin" },
"optimization": {
"self_consumption_interpolator": "numpy",
"genetic": { "fitness_cache_max_entries": 0 }
},
"database": { "autosave_interval_sec": null }
}
```
Environment of the EOS process (for example in the systemd unit):
```ini
Environment=PYTHONMALLOC=malloc
Environment=MALLOC_ARENA_MAX=2
Environment=MALLOC_TRIM_THRESHOLD_=131072
Environment=MALLOC_MMAP_THRESHOLD_=131072
Environment=OPENBLAS_NUM_THREADS=1
```
## Measurements
### Memory, all settings combined
Linux arm64 (Debian 13, glibc, Python 3.13), one CPU per container, server-like process
(EOSdash off), 48 h horizon, 77 kWh battery with direct marketing; "with EV" adds an
electric vehicle and a dynamic tariff.
| | Idle | Peak during a run | Peak with EV |
|---|---|---|---|
| `main` (default settings) | 282–288 MB | 401 MB | 451 MB |
| all settings above | 136 MB | 142 MB | 144 MB |
With the fitness cache disabled, the memory no longer depends on the number of planned
devices: with an EV and five home appliances the peak was 144 MB (about 300 MB with the
unbounded cache). More devices only cost run time.
### Fitness cache
Same platform, two consecutive runs, `MALLOC_ARENA_MAX=2`, measured together with the lazy
imports (server baseline 136.5 MB before the first run):
| Scenario | `fitness_cache_max_entries` | Peak RSS (anon) | Run time | Best fitness |
|---|---|---|---|---|
| base | `null` (unbounded) | 289.3 MB (231.3) | 89.5 s | −17.473689741050 |
| base | `0` | 179.5 MB (121.1) | 88.7 s | −17.473689741050 |
| with EV | `null` (unbounded) | 340.0 MB (282.0) | 131.6 s | −13.851295466546 |
| with EV | `0` | 181.3 MB (123.3) | 133.2 s | −13.851295466546 |
Only 6–15 % of the cache lookups hit. A Raspberry Pi 4 with real installation data (see below)
showed the same picture: the unbounded cache made a run about 3.5 % faster and cost 100 MB.
### Run time on real hardware
Data of a real installation (77 kWh battery, direct marketing, 24 h control horizon at
15 minutes), all settings above:
| Device | Run time | Peak RSS |
|---|---|---|
| Raspberry Pi 4 Model B (2 GB, Cortex-A72), fitness cache off | 623–636 s | 195 MB |
| Raspberry Pi 4 Model B, fitness cache unbounded | 602–609 s | 294 MB |
| x86 VM, 2 vCPU (container, with EV) | 173 s | 127 MB |
On a Raspberry Pi 4 a run therefore takes about 10 minutes. With a 15-minute `ems.interval`
the device is busy about 70 % of the time; a longer interval leaves more headroom.
### Storage writes
With the default `database.autosave_interval_sec` the measurement and prediction databases are
written every few seconds. On an installation that pushes its forecasts and measurements from
an external system this amounted to 12–14 MB per minute; with autosave disabled about
1 KiB per minute remained. On SD cards and small eMMC this is the main source of wear.
Disabling autosave means that data pushed to EOS is lost when EOS restarts. That is fine when an
external system (an energy manager, Home Assistant, Node-RED) pushes forecasts and measurements
again; it is not suitable when EOS fetches and keeps its own history.
### Allocator
On glibc, Python keeps memory freed after a run in its own pools. Measured on an x86 VM with an
unbounded fitness cache, `PYTHONMALLOC=malloc` together with the trim thresholds above lowered
the idle memory from about 295 MB to 238 MB, and after each run EOS fell back to about 260 MB
instead of staying at its peak. With the fitness cache disabled the difference is small
(about 5 MB), because the large per-run allocations no longer happen.
+1
View File
@@ -31,6 +31,7 @@ develop/install.md
akkudoktoreos/configuration.md
develop/update.md
akkudoktoreos/upgrade-genetic.md
akkudoktoreos/smalldevices.md
develop/revert.md
akkudoktoreos/adapter/adapterhomeassistant.md
akkudoktoreos/adapter/adapternodered.md