mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-13 01:21:58 +00:00
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:
co-authored by
Christin
Claude Opus 5.5
parent
3651d33915
commit
ecec39fcd8
@@ -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.
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user