Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ jobs:
- uses: actions/checkout@v4

- name: Install build dependencies
# Build-Depends in debian/control is the single list of what the build
# needs; mk-build-deps installs exactly that, so the two cannot drift.
run: |
apt-get update
apt-get install -y --no-install-recommends \
build-essential devscripts debhelper dh-python \
python3-all python3-setuptools fakeroot
apt-get install -y --no-install-recommends build-essential devscripts equivs fakeroot
cd /tmp && mk-build-deps --install --remove \
--tool "apt-get -y --no-install-recommends" "$GITHUB_WORKSPACE/debian/control"

- name: Build the package
run: make deb
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
include src/hpc_eff/config.ini.example
recursive-include src/hpc_eff/utils *.py *.sql
recursive-include src/hpc_eff/pipeline *.py
recursive-include examples *.py
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ killed; they run under a lower clock ceiling while conditions are bad.
| [docs/cluster-rollout.md](docs/cluster-rollout.md) | Many nodes, upgrades, uninstall. |
| [docs/configuration.md](docs/configuration.md) | Every key of `/etc/hpc_eff/config.ini`. |
| [docs/regulation-modes.md](docs/regulation-modes.md) | What each mode does with its input: the rating maths, the thermal bands. |
| [docs/plugins.md](docs/plugins.md) | The score/action pipeline: built-in plugins, writing your own, the JSON contract. |
| [docs/monitoring.md](docs/monitoring.md) | Database schema, `state.json`, useful queries. |
| [docs/troubleshooting.md](docs/troubleshooting.md) | Symptom-first fault finding. |

Expand Down Expand Up @@ -125,6 +126,22 @@ CPU regulation is mutually exclusive: a node is driven either by carbon/price
or by temperature, never both. Details:
[docs/regulation-modes.md](docs/regulation-modes.md).

### Plugins

Every evaluation is a pipeline of plugins: `read` → `score` → `act` → `record`.
Without extra config it behaves exactly as above. To change it, add a
`[PIPELINE]` section, for example CO₂ alone (no price) driving the CPU cap:

```ini
[PIPELINE]
score = co2
act = cpu_freq
```

Your own score or action is any executable that reads JSON on stdin and prints
JSON on stdout. Contract, built-in plugins, security rules and starter files:
[docs/plugins.md](docs/plugins.md).

---

## Data sources
Expand Down
2 changes: 1 addition & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Source: hpc-eff
Section: utils
Priority: optional
Maintainer: CESNET <pailozian@cesnet.cz>
Build-Depends: debhelper (>= 12), dh-python, python3-all, python3-setuptools
Build-Depends: debhelper (>= 12), dh-python, python3-all, python3-setuptools, python3-numpy, python3-requests
Standards-Version: 4.6.0
X-Python3-Version: >= 3.9

Expand Down
1 change: 1 addition & 0 deletions debian/install
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
src/hpc_eff/config.ini.example etc/hpc_eff/
examples/plugins usr/share/doc/hpc-eff/examples/
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
| [cluster-rollout.md](cluster-rollout.md) | Many nodes, upgrades, uninstall, first-week health checks. |
| [configuration.md](configuration.md) | Every section and key of `/etc/hpc_eff/config.ini`, with defaults and units. |
| [regulation-modes.md](regulation-modes.md) | What each mode does with its input: the rating maths, the thermal bands. |
| [plugins.md](plugins.md) | The score/action pipeline: built-in plugins, writing your own, the JSON contract. |
| [monitoring.md](monitoring.md) | Database schema, `state.json`, and the SQL worth running once it is live. |
| [troubleshooting.md](troubleshooting.md) | Symptom-first: what to check when a step above does not work. |

Expand Down
32 changes: 31 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ regulator actually reads:
| `[TEMPERATURE_SOURCE]` | n/a | yes |
| `[CPU_THERMO]` | n/a | yes |
| `[GPU_POWER]` | n/a | yes |
| `[PIPELINE]`, `[plugin:NAME]` | optional | optional |

---

Expand Down Expand Up @@ -158,7 +159,7 @@ weight_co2=0.4

| Key | Default | Meaning |
|---|---|---|
| `rating_type` | `price` | `price` \| `average` \| `max`: see [regulation-modes.md](regulation-modes.md#choosing-rating_type) |
| `rating_type` | `price` | `price` \| `co2` \| `average` \| `max`: see [regulation-modes.md](regulation-modes.md#choosing-rating_type) |
| `weight_price` | `0.6` | Used by `average` only, normalised against `weight_co2` |
| `weight_co2` | `0.4` | Used by `average` only |

Expand Down Expand Up @@ -310,6 +311,35 @@ constantly. Set both pairs against that range.

---

## `[PIPELINE]` and `[plugin:NAME]`: choosing and extending the steps

Optional. Replaces the `[MODE] control_mode` presets with an explicit list of
plugins per stage.

```ini
[PIPELINE]
score = co2
act = cpu_freq

[plugin:threshold_score] # only for your own executables
exec = /etc/hpc_eff/plugins/threshold_score.py
timeout = 30
```

| Key | Default | Meaning |
|---|---|---|
| `read`, `score`, `act` | empty | Comma-separated plugin names, run in order |
| `record` | `db_log, state_json` | Same, for the persistence stage |
| `[plugin:NAME] exec` | built-in `NAME` | Absolute path to an executable, or `builtin:NAME` |
| `[plugin:NAME] timeout` | `30` | Seconds before the plugin is killed |
| other `[plugin:NAME]` keys | none | Passed to the plugin as-is |

An invalid pipeline aborts the run with `Config error: ...` before any plugin
starts. Built-in plugin names, the JSON contract and the security rules:
[plugins.md](plugins.md).

---

## Next

[regulation-modes.md](regulation-modes.md): what each mode does with these
Expand Down
10 changes: 7 additions & 3 deletions docs/monitoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,14 @@ A JSON file, rewritten in full on every run:
"score_name": "SPEC2017",
"score_value": 3.8,
"power_cmd": "ipmitool dcmi power reading",
"plugins": { "power": "power_reader.py", "price": "energy_price.py",
"co2": "co2_value.py", "temperature": "cpu_thermo.py" }
"plugins": { "read": ["power", "cpufreq"], "score": ["price", "co2", "combine"],
"act": ["cpu_freq"], "record": ["db_log", "state_json"] }
},
"current": {
"timestamp": "2026-08-21T10:00:03Z",
"rating": 5, "rating_price": 6, "rating_co2": 4,
"selected_freq_khz": 2600000,
"summary": "Price 2431 is average; Combined rating 5 (price 6, CO2 4)",
"action_price": "Price 2431 is average; Combined rating 5 (price 6, CO2 4)",
"price": 2431, "co2_current": 412, "co2_median": 448, "co2_grade": 4,
"power_w": 287, "cpu_freq_current": 2712
Expand All @@ -108,11 +109,14 @@ The example above is a `co2`-mode node. A `temperature`-mode node carries
`temperature`, `thermo_freq_limit`, and `action_temp` instead, plus the `gpu_*`
fields on GPU nodes; the price and rating keys are absent entirely.

`action_price` (and `action_temp` in `temperature` mode) is the human-readable
`summary` (and `action_temp` in `temperature` mode) is the human-readable
summary of what the run decided: the fastest thing to eyeball when something
looks wrong. **`action_temp` exists only here, not in the database**, so it is
the only place a thermal failure explains itself.

`action_price` is a **deprecated** copy of `summary`, written only when the
`price` plugin runs. It will be removed in a later release; read `summary`.

Each run reads the whole file, replaces `current`, prepends the new entry to
`history` (trimmed to `history_length`), refreshes `static`, and writes the
whole file back. If the file does not exist yet, it is created with empty
Expand Down
Loading
Loading