mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-16 11:01:56 +00:00
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>
117 lines
5.1 KiB
Markdown
117 lines
5.1 KiB
Markdown
% 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.
|