diff --git a/README.md b/README.md index 9e76892..67289cb 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@

CPU scheduling that learns inside the Linux kernel.

+Lertick always owns its scheduling model. New installations automatically exchange +compatible, fresh advice with a running Lerwatt; no peer-specific install flag is +required. Missing or removed peers leave scheduling independent. Neither project +starts, replaces or retrains the other. [Automatic coordination](docs/INTEGRATION.md). + ## Performance at a glance **Lertick online mode recorded 50.34% lower short-burst completion p99 than Linux EEVDF in our VM benchmark.** Mixed-contention tests also expose clear regressions: diff --git a/deploy.sh b/deploy.sh index b42f9b9..9141038 100755 --- a/deploy.sh +++ b/deploy.sh @@ -20,7 +20,7 @@ Usage: ./deploy.sh COMMAND [OPTIONS] restart Restart this service; never stop another scheduler. enable Start now and enable this service at boot. disable Stop now and disable this service at boot. - integration [on|off|status] Persist optional Lerwatt coordination (default off). + integration [auto|on|off|status] Persist optional Lerwatt coordination (default auto). update Build/verify a candidate before stopping/replacing this service. rollback Restore the previous complete release, preserving service intent. uninstall Disable/stop this service and remove its installed files. @@ -106,8 +106,8 @@ validate_options() case $command in plan|run|trial) validate_options "$@" ;; integration) - [ "$#" -le 1 ] || fail 'integration accepts on, off or status' - case ${1:-status} in on|off|status) ;; *) fail 'integration accepts on, off or status' ;; esac + [ "$#" -le 1 ] || fail 'integration accepts auto, on, off or status' + case ${1:-status} in auto|on|off|status) ;; *) fail 'integration accepts auto, on, off or status' ;; esac ;; report) for arg in "$@"; do case $arg in --include-logs|--help) ;; *) fail "unsupported report option: $arg" ;; esac; done ;; *) [ "$#" -eq 0 ] || fail "$command does not accept options" ;; @@ -115,7 +115,7 @@ esac if [ "$command" = plan ]; then printf 'Run plan (not executed; requires a compatible idle sched_ext kernel):\n' if [ "$duration" -eq 0 ]; then set -- --summary-only --sample-ms 60000 "$@"; fi - for word in sudo "$loader" --mode online --duration 0 --track-all --cpuperf auto "$@"; do + for word in sudo "$loader" --mode online --duration 0 --track-all --cpuperf auto --lerwatt-auto "$@"; do escaped=$(printf '%s' "$word" | sed "s/'/'\\\\''/g"); printf " '%s'" "$escaped" done printf '\nNo scheduler was loaded or attached.\n'; exit 0 @@ -274,9 +274,9 @@ if [ "$duration" -eq 0 ]; then else printf 'Lertick: starting finite foreground scheduler; Ctrl-C detaches it.\n' >&2; fi [ -z "$pending_signal" ] || finish_run "$pending_status" if [ "$stats_requested" = yes ]; then - "$loader" --mode online --duration "$base_duration" --track-all --cpuperf auto "$@" & + "$loader" --mode online --duration "$base_duration" --track-all --cpuperf auto --lerwatt-auto "$@" & else - "$loader" --mode online --duration "$base_duration" --track-all --cpuperf auto "$@" >/dev/null & + "$loader" --mode online --duration "$base_duration" --track-all --cpuperf auto --lerwatt-auto "$@" >/dev/null & fi child=$! [ -z "$pending_signal" ] || stop_run "$pending_status" diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 5d21154..80b3419 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -385,8 +385,8 @@ overlay from the read-only base. ## CPU frequency targets and the Lerwatt plug-in -Native service setup is now available through `lertick integration on` and -Lerwatt's `./deploy.sh install --lertick`. Models and release versions remain +New managed services and foreground helper runs discover optional Lerwatt advice +automatically; ordinary installations need no peer-specific flag. Models and release versions remain independent; compatible model-only updates do not change the contract ABI. See [setup, ownership and ABI compatibility](INTEGRATION.md) before using the raw-loader research commands below. @@ -402,7 +402,7 @@ lowers idle CPUs' targets. `auto` selects `util` when any policy's a VM without cpufreq, `auto` keeps the previous behavior. The registered event records `cpuperf` and `cpuperf_reason`; snapshots then add a `cpus` array. -`--lerwatt` pins `lw_contract` and `lt_demand` under `/sys/fs/bpf/lertick/` +`--lerwatt-auto` enables best-effort discovery and keeps ordinary scheduling if publication is unavailable. It does not force `cpuperf util` merely because no peer is present. The advanced strict `--lerwatt` mode pins `lw_contract` and `lt_demand` under `/sys/fs/bpf/lertick/` before attaching, publishes demand every 100 ms, and unpins them at exit; a pin failure aborts before the default scheduler is replaced. Clusters are the cpufreq policies sorted by first CPU. Without real policies, Lertick uses a diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 14a369b..c4af518 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -138,7 +138,7 @@ lertick trial --mode shadow --duration 30 \ The default bounds are 0.5–5 ms after eight valid labels, with a 2 ms fallback. They bound newly assigned budgets, not exact execution time or the remaining budget of an already running task. Lower prediction error has not established a general throughput or latency advantage; consult the [recorded comparisons](PHASE2_RESULTS.md) and [long-window confirmation](../results/model-confirmation/README.md). -The helper forwards `--mode`, `--duration`, `--sample-ms` and `--stats-json`; tracking and CPU-performance defaults are fixed for this simple path. Optional persistent Lerwatt coordination uses `lertick integration on`; follow the [shared integration guide](INTEGRATION.md) to configure both projects. For targeted tracking, partial switching, full research snapshots or model experiments, use the advanced loader instructions in [deployment and reproduction](DEPLOYMENT.md). Model tracking and the set of scheduled tasks are distinct: selecting a TGID for learning alone does not isolate scheduling to that process. +The helper forwards `--mode`, `--duration`, `--sample-ms` and `--stats-json`; tracking and CPU-performance defaults are fixed for this simple path. New installations automatically discover compatible Lerwatt advice; no integration-enable command is needed. Existing saved opt-outs remain respected. Follow the [shared integration guide](INTEGRATION.md) to configure both projects. For targeted tracking, partial switching, full research snapshots or model experiments, use the advanced loader instructions in [deployment and reproduction](DEPLOYMENT.md). Model tracking and the set of scheduled tasks are distinct: selecting a TGID for learning alone does not isolate scheduling to that process. ## Telemetry and permissions diff --git a/docs/INTEGRATION.md b/docs/INTEGRATION.md index 0b339e0..674fba3 100644 --- a/docs/INTEGRATION.md +++ b/docs/INTEGRATION.md @@ -2,7 +2,7 @@ [← Project home](../README.md) · [Lertick](https://github.com/Denny-Lin/lertick) · [Lerwatt](https://github.com/Denny-Lin/lerwatt) -Use each controller on its own, or enable an optional local link. **Lertick owns scheduling; Lerwatt owns CPU power constraints.** They exchange demand and limits while keeping their models, training and service lifecycles separate. +Each controller works on its own and discovers an optional compatible local peer automatically. **Lertick owns scheduling; Lerwatt owns CPU power constraints.** They exchange demand and limits while keeping their models, training and service lifecycles separate. ```mermaid flowchart LR @@ -16,34 +16,60 @@ flowchart LR linkStyle default stroke:#86868b,stroke-width:1.5px ``` -## Enable the link +## Automatic discovery -First satisfy each project's native Linux requirements. Lerwatt needs usable CPUFreq controls and temperature inputs. Lertick additionally needs a compatible running sched_ext kernel, BTF and its BPF toolchain. Installing these services does not install or change the kernel. A compatible running kernel needs no reboot for activation; changing kernels can require one. +Install each project normally after satisfying its native Linux requirements. +Lerwatt needs CPUFreq controls, temperature inputs and Linux userspace BPF +headers. Lertick also needs a supported running sched_ext kernel, BTF and its +BPF toolchain. Neither installer changes the kernel or installs its peer. -From the **Lerwatt checkout**, as your normal user: +From the Lerwatt checkout, as your normal user: ```sh ./deploy.sh check -./deploy.sh install --lertick --period-ms 100 -lerwatt status +./deploy.sh install ``` -This builds the BPF-capable daemon locally, then installs, enables and starts Lerwatt. Usable Linux userspace BPF headers are required; Lerwatt's contract uses raw BPF syscalls without libbpf. Its service configuration stores `contract=auto`. Coordination accepts a **10–100 ms** control period; the default is 100 ms. A normal independent installation keeps `contract=off` and the BPF-free build. - -From the **Lertick checkout**, as your normal user: +From the Lertick checkout, as your normal user: ```sh ./deploy.sh install -lertick integration on lertick enable -lertick status ``` -Lertick installation adds files without starting or enabling its service. `integration on` saves the optional link setting; `enable` starts now and at boot. Changing integration on an already running managed Lertick service restarts that service with verified settings, preserving its prior active/enabled intent. It does not restart Lerwatt. - -**Either project may start first.** An absent or incompatible peer leaves the other operating independently. Neither unit requires the peer through `Requires=` or `BindsTo=`, and neither project starts, stops, upgrades or restarts the peer. - -## Check or turn off coordination +New Lerwatt installations save `contract=auto` and build the BPF-capable daemon; +new Lertick installations save `lerwatt=auto`. No `--lertick` installation flag +or `integration on` command is needed. Lertick installation still does not start +or enable scheduling: `enable` is the user's normal service activation, not a +peer-specific step. A plain upgrade preserves saved settings, including explicit +`off` opt-outs from earlier versions. For such a saved opt-out, choose auto once +with `./deploy.sh install --lertick` or `lertick integration auto` respectively. + +**Either project may start first.** A service may be installed without running; +installation files alone do not prove a usable peer. Connection requires the +real maps plus matching ABI, topology, attachment session and fresh records. +Missing, stopped, removed, expired or incompatible peers leave local operation +independent. Running peers reconnect automatically; uninstalling a peer does not +stop the remaining controller. Neither service has `Requires=` or `BindsTo=` on +the other, and neither starts, stops, upgrades or retrains its peer. + +Discovery is separate from prediction. Lerwatt keeps its own learned thermal +model and MPC, Lertick keeps its own scheduler model. Peer appearance/disappearance +never changes the selected prediction algorithm or private weights. New Lerwatt +installs use nominal MPC; cooperative prediction can be selected separately +with `--prediction cooperative` and retains all reliability gates. Earlier +saved cooperative choices are preserved. Installing Lertick does not make +Lerwatt forecasts more accurate. + +Lertick's automatic mode is best effort: inability to discover topology, obtain +an attachment identity or publish maps leaves ordinary scheduling available. +It never overwrites foreign pins. Transport unavailable at initial attachment +requires a later local Lertick restart after the environment is repaired; this +is distinct from an absent peer, which connects later without restart. Raw +loader `--lerwatt` retains strict failure behavior for diagnostics. Raw loader +users can select `--lerwatt-auto`; normal helper/service runs do so automatically. + +## Inspect or override discovery ```sh lerwatt status @@ -53,21 +79,27 @@ lertick status sudo systemctl show lerwatt.service lertick.service --property=StatusText ``` -Configured `auto`/`on` means the link is requested. Inspect current worker status and logs for **connected**, **waiting** or **off**; an enabled service or saved setting alone does not prove a fresh compatible exchange. Waiting can mean the peer has not started, its records expired, or its ABI/topology/session is incompatible. Do not interpret a counter from an older run as proof of a current connection. +Configured `auto` means discovery is enabled; it does not mean connected. +Worker status/logs report **connected**, **waiting** or **off**. Waiting includes +an absent/inactive peer and rejected stale/incompatible records. Do not interpret +an older counter or an installed executable as current connectivity. Coordination +uses a 10–100 ms control period, with 100 ms the default. -To keep both controllers but remove their optional link, run this from the Lerwatt checkout: +Advanced explicit opt-outs remain available: ```sh +# From the Lerwatt checkout: ./deploy.sh install --no-lertick -``` - -Then: - -```sh +# Only the Lertick managed service: lertick integration off ``` -Plain Lerwatt reinstallation and Lertick updates preserve their saved integration settings. Lerwatt stores its setting in `/etc/lerwatt/lerwatt.conf`; Lertick uses `/etc/lertick/integration.conf`. Both are private root-owned data files, parsed without sourcing shell code. Turning off coordination does not disable either controller's own learning. +These choices affect exchange, not either controller's learning. They do not +change Lerwatt's selected nominal/cooperative predictor. Lertick changes only +its own service when a managed integration setting is explicitly changed. +The strict legacy `lertick integration on` mode remains available. Configuration +is root-private strict data in `/etc/lerwatt/lerwatt.conf` and +`/etc/lertick/integration.conf`, never sourced as shell commands. ## Control ownership diff --git a/results/automatic-discovery/README.md b/results/automatic-discovery/README.md new file mode 100644 index 0000000..a59d4a0 --- /dev/null +++ b/results/automatic-discovery/README.md @@ -0,0 +1,121 @@ +# Automatic independent peer discovery + +Validation snapshots: Lerwatt base `cc8b65f`, Lertick base `5ce8a3c`, both on +`automatic-peer-discovery`. Each controller retains its own learning, controls +and lifecycle. No peer-specific installation flag is needed for new managed +installations. [Shared protocol and usage](../../docs/INTEGRATION.md). + +## Implemented behavior + +- New Lerwatt installations build the BPF-capable daemon and save + `contract=auto`. No peer is installed or started by Lerwatt. Its own learned + thermal model and MPC continue while waiting for a compatible running peer. +- New Lertick installations save `lerwatt=auto`. Normal service/foreground + helper runs expose optional advice without an integration-enable command. + Installing Lertick still does not start/enable scheduling; the normal local + `lertick enable` command does that. Automatic mode preserves the previous + governor-based CPUperf selection rather than forcing util just for discovery. +- Real maps plus fresh matching ABI 2, topology and attachment identities are + required. File/package presence is not connection proof. Either startup order, + peer stop and return, expired records and incompatible data retain independent + operation. Neither project starts, stops or retrains its peer. +- Discovery never changes the selected predictor. New Lerwatt installs retain + nominal independent MPC; cooperative prediction can be selected separately. + Saved cooperative choices remain selected with or without Lertick. This + supersedes the short-lived coupling between `--lertick` and prediction default. + Existing saved settings, including explicit off opt-outs, survive upgrades. +- Automatic Lertick discovery preserves existing pins. If topology/identity or + map publication is unavailable, it schedules independently. A writable BPF + guard disables advice consumption before attach after publication failure, + including a partial-publication case. The legacy strict `--lerwatt` diagnostic + path retains its existing semantics; it is not the normal auto mode. +- An absent peer can join later without restart. A failed local transport setup + (for example conflicting pins) remains unavailable until its environment is + repaired and Lertick is locally restarted. Unknown pins are not force-cleaned. + A compatible peer's appearance is not evidence of better forecast accuracy. + +## Validation + +[Linux build/model/deployment/e2e log](linux-build-and-tests.log) passed, including +both projects' required deployment and ABI checks. The peer's 56 compiled ABI +values match; the shared contract layout and integration guide are unchanged +between the two tested sources. [Source identity](source-identity.json) verifies +62 Lerwatt and 45 Lertick source/test/protocol files against the VM. + +Real PID 1 service tests proved new defaults without explicit prediction/link +opt-in, absent-peer waiting, unlimited ready operation, recovery/restoration, +independent enablement intent, update/rollback and uninstall behavior. See +[initial lifecycle log](initial-live-pair.log) and +[final kernel/lifecycle log](status-fixture-failure.log); the latter's lifecycle +checks pass, but its subsequent obsolete status-label fixture fails as recorded +below. The final paired test is separately successful. + +The [final live test](final-live-pair.log), [machine-readable result](result.json) +passed nine real sched_ext/BPF checks on Ubuntu 24.04.5 ARM64, kernel +`7.0.0-38-generic`, systemd 255 and eight vCPUs: + +1. Lerwatt-first automatic connection, with actual BPF contract consumption. +2. Scheduler restart with a new session and automatic reconnection. +3. Changing scheduler online/EWMA mode leaves Lerwatt's PID running. +4. Frozen demand expires; resuming its publisher restores fresh exchange. +5. Lerwatt restart restores controls, expires advice and reconnects. +6. Changing Lerwatt's temporal/adaptive forecaster leaves Lertick's PID/session. +7. Lertick-first automatic connection. +8. Final control restoration, default-scheduler fallback and owned-pin cleanup. +9. A conflicting test-owned pin retains its map identity; automatic mode still + registers an independent scheduler, reports off, and applies no contract. + +All hardware controls were temporary simulator files. Kernel sched_ext/BPF and +PID 1 were real. Production services and physical CPU controls were not changed; +no VM reboot was performed. Final sched_ext state is disabled. Raw artifacts +remain retained in the VM and an ignored local archive; see [archive identity](raw-archive.json). + +## Performance and retained failures + +The [60 finite-work rows](finite-jobs.jsonl) reproduce earlier Linux outcomes +excluding CPU timing. All work completes, but the same two cooperative pairs +still regress in makespan by 0.02 and 0.07 seconds. The strict nonregression gate +is still failed, not waived: [summary](control-summary.json). No prediction +thresholds or learning parameters were tuned in this change. There is no new +hardware energy, throughput, model accuracy or overhead claim; default discovery +adds bookkeeping whose physical-machine cost still needs measurement. + +Failures remain recorded: + +- Old service/default and foreground-argv fixtures expected off/no-auto; the first + runs failed. Their expectations now test the new behavior while retaining + explicit off/on transaction coverage. [Service failure](first-service-fixture-failure.log), + [argv failure](old-argv-fixture-failure.log), + [fixed service](portable-service-fixtures.log), + [fixed foreground](portable-foreground-fixtures.log). +- The first conflicting-pin test exposed the legacy preparation routine deleting + the test-owned same-name pin. Auto mode now uses a separate non-destructive + preparation path; it never invokes that stale-pin cleanup. Its test cleanup + also handles an already absent owned directory. [Failed run](first-conflict-failure.log). +- After the production fix, the test waited for the wrong status prefix because + its custom unit name lacked the scheduler classifier. The fixture name was + corrected and a periodic runtime snapshot is now required before checking zero + applied advice. [Failed fixture](status-fixture-failure.log), + [final pass](final-live-pair.log). +- A local macOS plug-in compile attempt failed on Linux-only integer/header + dependencies (`__u32`, `sys/statfs.h`), and is not counted as a pass. The Linux + native plug-in, CPUperf and actual kernel tests pass. No platform-porting claim + is made. The first two shell fixture sequences also continued to a documentation + check after an earlier failure; those earlier failures are retained, not + inferred successful from the enclosing shell exit code. Later validations use + `set -e` or individually checked results. + +Shared weights, joint retraining, physical energy savings, universal hardware +compatibility and long-duration reliability are not established by these tests. + +## CI fixture timing follow-up + +The initial musl/BusyBox CI failed an update transaction because the stub-only +service fixture exceeded its fixed 15-second subprocess limit; other platforms +passed. [CI failure excerpt](ci-musl-failure.log) preserves the timeout. The +fixture now allows 45 seconds and reports the last 12 stub events if it still +times out. All transaction assertions remain. No production watchdog, kernel +thermal setting, learning gate or performance acceptance criterion changed. +This is not a runtime speedup claim. The matching revision passed the full +[Linux service fixture](linux-service-fixture-followup.log); CI must pass this +revision before merge. diff --git a/results/automatic-discovery/ci-musl-failure.log b/results/automatic-discovery/ci-musl-failure.log new file mode 100644 index 0000000..ed7c9aa --- /dev/null +++ b/results/automatic-discovery/ci-musl-failure.log @@ -0,0 +1,50 @@ +2026-11-02T17:34:53.3529830Z (62/72) Installing cfdisk (2.41.6-r1) +2026-11-02T17:34:53.3598514Z (63/72) Installing umount (2.41.6-r1) +2026-11-02T17:34:53.3663964Z (64/72) Installing flock (2.41.6-r1) +2026-11-02T17:34:53.3735985Z (65/72) Installing lsblk (2.41.6-r1) +2026-11-02T17:34:53.3830577Z (66/72) Installing libcap-ng (0.8.5-r0) +2026-11-02T17:34:53.3904490Z (67/72) Installing setpriv (2.41.6-r1) +2026-11-02T17:34:53.3969703Z (68/72) Installing lscpu (2.41.6-r1) +2026-11-02T17:34:53.4064862Z (69/72) Installing logger (2.41.6-r1) +2026-11-02T17:34:53.4142784Z (70/72) Installing partx (2.41.6-r1) +2026-11-02T17:34:53.4218291Z (71/72) Installing fstrim (2.41.6-r1) +2026-11-02T17:34:53.4299460Z (72/72) Installing findmnt (2.41.6-r1) +2026-11-02T17:34:53.4381436Z Executing busybox-1.37.0-r20.trigger +2026-11-02T17:34:53.4464693Z OK: 293 MiB in 88 packages +2026-11-02T17:34:53.5459397Z mkdir -p build +2026-11-02T17:34:53.5482540Z cc -Isrc/userspace -O2 -std=gnu11 -Wall -Wextra -Werror tests/test_loader_runtime.c src/userspace/runtime.c -o build/test_loader_runtime +2026-11-02T17:34:53.8562611Z python3 tests/check_integration_abi.py +2026-11-02T17:34:53.9594018Z Integration ABI 2 golden check passed (56 values). +2026-11-02T17:34:53.9684474Z build/test_loader_runtime +2026-11-02T17:34:53.9818330Z loader runtime: private output, lock ownership, idle-state guard, readiness notify and maintenance lifetime passed +2026-11-02T17:34:53.9821555Z sh tests/test_deploy.sh +2026-11-02T17:35:46.4816372Z test_deploy: plan/check/verify, indefinite/finite defaults, signals, trust paths, maintenance, staging and build fingerprints passed (stubs only) +2026-11-02T17:35:46.4896827Z sh tests/test_service.sh +2026-11-02T17:37:51.4804581Z Traceback (most recent call last): +2026-11-02T17:37:51.4806631Z File "", line 162, in +2026-11-02T17:37:51.4807536Z File "", line 96, in run +2026-11-02T17:37:51.4808300Z File "/usr/lib/python3.12/subprocess.py", line 550, in run +2026-11-02T17:37:51.4809244Z stdout, stderr = process.communicate(input, timeout=timeout) +2026-11-02T17:37:51.4810045Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2026-11-02T17:37:51.4810884Z File "/usr/lib/python3.12/subprocess.py", line 1209, in communicate +2026-11-02T17:37:51.4814888Z stdout, stderr = self._communicate(input, endtime, timeout) +2026-11-02T17:37:51.4816335Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2026-11-02T17:37:51.4817202Z File "/usr/lib/python3.12/subprocess.py", line 2116, in _communicate +2026-11-02T17:37:51.4826043Z self._check_timeout(endtime, orig_timeout, stdout, stderr) +2026-11-02T17:37:51.4828508Z File "/usr/lib/python3.12/subprocess.py", line 1253, in _check_timeout +2026-11-02T17:37:51.4833472Z raise TimeoutExpired( +2026-11-02T17:37:51.4835818Z subprocess.TimeoutExpired: Command '['/tmp/lertick-service-fixtures-z46ppmz6/source/scripts/service_manager.sh', '/tmp/lertick-service-fixtures-z46ppmz6/prefix', 'update', '/tmp/lertick-service-fixtures-z46ppmz6/source']' timed out after 15 seconds +2026-11-02T17:37:51.4921639Z make: *** [Makefile:61: test-deployment] Error 1 +2026-11-02T17:37:51.9770854Z ##[error]Process completed with exit code 2. +2026-11-02T17:37:51.9919922Z Post job cleanup. +2026-11-02T17:37:52.0831988Z [command]/usr/bin/git version +2026-11-02T17:37:52.0882111Z git version 2.56.0 +2026-11-02T17:37:52.0927350Z Temporarily overriding HOME='/home/runner/work/_temp/2e16060e-2014-4a7c-82d8-cb90e20e31cb' before making global git config changes +2026-11-02T17:37:52.0928753Z Adding repository directory to the temporary git global config as a safe directory +2026-11-02T17:37:52.0933421Z [command]/usr/bin/git config --global --add safe.directory /home/runner/work/lertick/lertick +2026-11-02T17:37:52.0983900Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand +2026-11-02T17:37:52.1025441Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :" +2026-11-02T17:37:52.1350502Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +2026-11-02T17:37:52.1399332Z [command]/usr/bin/git submodule foreach --recursive sh -c "git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :" +2026-11-02T17:37:52.1828243Z Cleaning up orphan processes +2026-11-02T17:37:52.2310638Z ##[warning]Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ diff --git a/results/automatic-discovery/control-summary.json b/results/automatic-discovery/control-summary.json new file mode 100644 index 0000000..46d52cc --- /dev/null +++ b/results/automatic-discovery/control-summary.json @@ -0,0 +1,49 @@ +{ + "paired_runs": 30, + "all_work_completed": true, + "pairs_with_regressions": 2, + "corrected_queries": 2, + "limits": [ + "One simulated board model; no hardware energy or Linux superiority claim.", + "Finite FIFO work is fully drained; historical served percentages are not used.", + "Correction queries are evaluations, not distinct decisions or savings.", + "Controller CPU time is simulator-harness measurement, not a real-time guarantee.", + "Descriptive paired differences, not statistical significance." + ], + "same_outcomes_as_prior_excluding_cpu_timing": true, + "regressions": [ + { + "pattern": 4, + "seed": 7, + "joint": false, + "delta": { + "makespan_s": 0.01999999999998181, + "simulated_board_j": -0.259262999999919, + "job_p99_s": 0.01999999999998181, + "point_mae_c": 0.0028409999999999824, + "ceiling_moves": 0 + }, + "regressions": [ + "makespan_s", + "job_p99_s", + "point_mae_c" + ] + }, + { + "pattern": 4, + "seed": 99, + "joint": false, + "delta": { + "makespan_s": 0.06999999999993634, + "simulated_board_j": -0.12945599999966362, + "job_p99_s": 0.05999999999994543, + "point_mae_c": -0.0020789999999999975, + "ceiling_moves": 0 + }, + "regressions": [ + "makespan_s", + "job_p99_s" + ] + } + ] +} diff --git a/results/automatic-discovery/final-live-pair.log b/results/automatic-discovery/final-live-pair.log new file mode 100644 index 0000000..075316a --- /dev/null +++ b/results/automatic-discovery/final-live-pair.log @@ -0,0 +1,8 @@ +integration: Lerwatt-first startup connected; BPF consumed contracts +integration: online-to-EWMA scheduler change reconnected while Lerwatt stayed running +integration: frozen demand expired and resumed without stale control +integration: temporal-to-adaptive predictor change preserved Lertick PID and session +integration: reverse startup order connected +integration: conflicting pin preserved; auto mode scheduled independently +{"environment": {"kernel": "7.0.0-38-generic", "architecture": "aarch64", "os_release": "PRETTY_NAME=\"Ubuntu 24.04.5 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.5 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\n", "systemd": "systemd 255 (255.4-1ubuntu8.18)"}, "hardware": "temporary RK3588 simulated CPU-control files; real sched_ext/BPF", "checks": {"lerwatt_first_continuous_connection": true, "lertick_restart_new_session_reconnects": true, "independent_scheduler_policy_change": true, "frozen_demand_expires_and_recovers": true, "lerwatt_restart_restores_expires_reconnects": true, "independent_power_predictor_change": true, "lertick_first_connection": true, "final_control_restore_scheduler_fallback_pin_cleanup": true, "foreign_pin_preserved_auto_falls_back_without_advice": true}, "result": "passed"} +integration artifacts: /var/tmp/lertick-power-integration-s07845od diff --git a/results/automatic-discovery/finite-jobs.jsonl b/results/automatic-discovery/finite-jobs.jsonl new file mode 100644 index 0000000..489b575 --- /dev/null +++ b/results/automatic-discovery/finite-jobs.jsonl @@ -0,0 +1,60 @@ +{"pattern":0,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":405.22,"simulated_board_j":3064.103829,"peak_c":81.307,"job_p99_s":45.29,"point_mae_c":0.618066,"reference_mae_c":0.934517,"forecast_points":12006,"correction_queries":0,"queries":15565,"ceiling_moves":15,"frequency_transitions":5032,"control_cpu_s":0.003446} +{"pattern":0,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":405.22,"simulated_board_j":3064.103829,"peak_c":81.307,"job_p99_s":45.29,"point_mae_c":0.618066,"reference_mae_c":0.934517,"forecast_points":12006,"correction_queries":0,"queries":15565,"ceiling_moves":15,"frequency_transitions":5032,"control_cpu_s":0.003817} +{"pattern":0,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":419.52,"simulated_board_j":3140.746146,"peak_c":81.307,"job_p99_s":59.98,"point_mae_c":0.60829,"reference_mae_c":0.908556,"forecast_points":12435,"correction_queries":0,"queries":14279,"ceiling_moves":18,"frequency_transitions":5389,"control_cpu_s":0.003588} +{"pattern":0,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":419.52,"simulated_board_j":3140.746146,"peak_c":81.307,"job_p99_s":59.98,"point_mae_c":0.60829,"reference_mae_c":0.908556,"forecast_points":12435,"correction_queries":0,"queries":14279,"ceiling_moves":18,"frequency_transitions":5389,"control_cpu_s":0.003681} +{"pattern":0,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":402.76,"simulated_board_j":3056.050846,"peak_c":81.307,"job_p99_s":42.82,"point_mae_c":0.598512,"reference_mae_c":0.901395,"forecast_points":11931,"correction_queries":0,"queries":15553,"ceiling_moves":15,"frequency_transitions":5019,"control_cpu_s":0.003332} +{"pattern":0,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":402.76,"simulated_board_j":3056.050846,"peak_c":81.307,"job_p99_s":42.82,"point_mae_c":0.598512,"reference_mae_c":0.901395,"forecast_points":11931,"correction_queries":0,"queries":15553,"ceiling_moves":15,"frequency_transitions":5019,"control_cpu_s":0.003601} +{"pattern":1,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":503.04,"simulated_board_j":3412.501516,"peak_c":82.23,"job_p99_s":142.79,"point_mae_c":0.709844,"reference_mae_c":1.032735,"forecast_points":14940,"correction_queries":0,"queries":16479,"ceiling_moves":15,"frequency_transitions":1587,"control_cpu_s":0.004321} +{"pattern":1,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":503.04,"simulated_board_j":3412.501516,"peak_c":82.23,"job_p99_s":142.79,"point_mae_c":0.709844,"reference_mae_c":1.032735,"forecast_points":14940,"correction_queries":0,"queries":16479,"ceiling_moves":15,"frequency_transitions":1587,"control_cpu_s":0.004525} +{"pattern":1,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":500.66,"simulated_board_j":3394.311558,"peak_c":82.23,"job_p99_s":140.41,"point_mae_c":0.719791,"reference_mae_c":1.044086,"forecast_points":14868,"correction_queries":0,"queries":15913,"ceiling_moves":17,"frequency_transitions":1514,"control_cpu_s":0.004368} +{"pattern":1,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":500.66,"simulated_board_j":3394.311558,"peak_c":82.23,"job_p99_s":140.41,"point_mae_c":0.719791,"reference_mae_c":1.044086,"forecast_points":14868,"correction_queries":0,"queries":15913,"ceiling_moves":17,"frequency_transitions":1514,"control_cpu_s":0.004452} +{"pattern":1,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":497.11,"simulated_board_j":3383.829286,"peak_c":82.23,"job_p99_s":136.86,"point_mae_c":0.718125,"reference_mae_c":1.028734,"forecast_points":14763,"correction_queries":0,"queries":15518,"ceiling_moves":16,"frequency_transitions":1443,"control_cpu_s":0.004362} +{"pattern":1,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":497.11,"simulated_board_j":3383.829286,"peak_c":82.23,"job_p99_s":136.86,"point_mae_c":0.718125,"reference_mae_c":1.028734,"forecast_points":14763,"correction_queries":0,"queries":15518,"ceiling_moves":16,"frequency_transitions":1443,"control_cpu_s":0.00448} +{"pattern":2,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":360.64,"simulated_board_j":2638.146268,"peak_c":81.307,"job_p99_s":1.59,"point_mae_c":0.53184,"reference_mae_c":0.859365,"forecast_points":10668,"correction_queries":0,"queries":10209,"ceiling_moves":6,"frequency_transitions":8519,"control_cpu_s":0.003051} +{"pattern":2,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":360.64,"simulated_board_j":2638.146268,"peak_c":81.307,"job_p99_s":1.59,"point_mae_c":0.53184,"reference_mae_c":0.859365,"forecast_points":10668,"correction_queries":0,"queries":10209,"ceiling_moves":6,"frequency_transitions":8519,"control_cpu_s":0.003251} +{"pattern":2,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":360.63,"simulated_board_j":2630.93397,"peak_c":81.307,"job_p99_s":1.58,"point_mae_c":0.519062,"reference_mae_c":0.849117,"forecast_points":10668,"correction_queries":0,"queries":10066,"ceiling_moves":7,"frequency_transitions":8387,"control_cpu_s":0.003041} +{"pattern":2,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":360.63,"simulated_board_j":2630.93397,"peak_c":81.307,"job_p99_s":1.58,"point_mae_c":0.519062,"reference_mae_c":0.849117,"forecast_points":10668,"correction_queries":0,"queries":10066,"ceiling_moves":7,"frequency_transitions":8387,"control_cpu_s":0.003235} +{"pattern":2,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":360.64,"simulated_board_j":2626.024997,"peak_c":81.307,"job_p99_s":1.59,"point_mae_c":0.536754,"reference_mae_c":0.852969,"forecast_points":10668,"correction_queries":0,"queries":9965,"ceiling_moves":9,"frequency_transitions":8378,"control_cpu_s":0.003089} +{"pattern":2,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":360.64,"simulated_board_j":2626.024997,"peak_c":81.307,"job_p99_s":1.59,"point_mae_c":0.536754,"reference_mae_c":0.852969,"forecast_points":10668,"correction_queries":0,"queries":9965,"ceiling_moves":9,"frequency_transitions":8378,"control_cpu_s":0.003234} +{"pattern":3,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.87,"simulated_board_j":2372.53609,"peak_c":76.692,"job_p99_s":1.05,"point_mae_c":0.843208,"reference_mae_c":0.92945,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.002996} +{"pattern":3,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.87,"simulated_board_j":2372.53609,"peak_c":76.692,"job_p99_s":1.05,"point_mae_c":0.843208,"reference_mae_c":0.92945,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003215} +{"pattern":3,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.87,"simulated_board_j":2372.53609,"peak_c":77.615,"job_p99_s":1.05,"point_mae_c":0.850526,"reference_mae_c":0.92373,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.00296} +{"pattern":3,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.87,"simulated_board_j":2372.53609,"peak_c":77.615,"job_p99_s":1.05,"point_mae_c":0.850526,"reference_mae_c":0.92373,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003194} +{"pattern":3,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.87,"simulated_board_j":2372.53609,"peak_c":77.615,"job_p99_s":1.05,"point_mae_c":0.860971,"reference_mae_c":0.929357,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003067} +{"pattern":3,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.87,"simulated_board_j":2372.53609,"peak_c":77.615,"job_p99_s":1.05,"point_mae_c":0.860971,"reference_mae_c":0.929357,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003214} +{"pattern":4,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":980.4,"simulated_board_j":6295.971093,"peak_c":81.307,"job_p99_s":610.53,"point_mae_c":0.478139,"reference_mae_c":0.640429,"forecast_points":29259,"correction_queries":0,"queries":35913,"ceiling_moves":36,"frequency_transitions":42,"control_cpu_s":0.008729} +{"pattern":4,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":980.4,"simulated_board_j":6295.971093,"peak_c":81.307,"job_p99_s":610.53,"point_mae_c":0.478139,"reference_mae_c":0.640429,"forecast_points":29259,"correction_queries":0,"queries":35913,"ceiling_moves":36,"frequency_transitions":42,"control_cpu_s":0.008973} +{"pattern":4,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":979.53,"simulated_board_j":6294.123159,"peak_c":81.307,"job_p99_s":609.65,"point_mae_c":0.483719,"reference_mae_c":0.643218,"forecast_points":29235,"correction_queries":0,"queries":36274,"ceiling_moves":32,"frequency_transitions":40,"control_cpu_s":0.008612} +{"pattern":4,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":979.55,"simulated_board_j":6293.863896,"peak_c":81.307,"job_p99_s":609.67,"point_mae_c":0.48656,"reference_mae_c":0.646034,"forecast_points":29235,"correction_queries":1,"queries":36309,"ceiling_moves":32,"frequency_transitions":40,"control_cpu_s":0.008985} +{"pattern":4,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":981.83,"simulated_board_j":6300.32949,"peak_c":81.307,"job_p99_s":611.96,"point_mae_c":0.484815,"reference_mae_c":0.641113,"forecast_points":29304,"correction_queries":0,"queries":36617,"ceiling_moves":28,"frequency_transitions":38,"control_cpu_s":0.008705} +{"pattern":4,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":981.9,"simulated_board_j":6300.200034,"peak_c":81.307,"job_p99_s":612.02,"point_mae_c":0.482736,"reference_mae_c":0.639256,"forecast_points":29304,"correction_queries":1,"queries":36652,"ceiling_moves":28,"frequency_transitions":38,"control_cpu_s":0.008887} +{"pattern":0,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":418.79,"simulated_board_j":3046.446255,"peak_c":82.23,"job_p99_s":57.07,"point_mae_c":0.631586,"reference_mae_c":0.92619,"forecast_points":12411,"correction_queries":0,"queries":14238,"ceiling_moves":9,"frequency_transitions":3805,"control_cpu_s":0.003428} +{"pattern":0,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":418.79,"simulated_board_j":3046.446255,"peak_c":82.23,"job_p99_s":57.07,"point_mae_c":0.631586,"reference_mae_c":0.92619,"forecast_points":12411,"correction_queries":0,"queries":14238,"ceiling_moves":9,"frequency_transitions":3805,"control_cpu_s":0.003683} +{"pattern":0,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":418.22,"simulated_board_j":3046.942437,"peak_c":82.23,"job_p99_s":56.5,"point_mae_c":0.614085,"reference_mae_c":0.917913,"forecast_points":12396,"correction_queries":0,"queries":14225,"ceiling_moves":9,"frequency_transitions":3819,"control_cpu_s":0.003401} +{"pattern":0,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":418.22,"simulated_board_j":3046.942437,"peak_c":82.23,"job_p99_s":56.5,"point_mae_c":0.614085,"reference_mae_c":0.917913,"forecast_points":12396,"correction_queries":0,"queries":14225,"ceiling_moves":9,"frequency_transitions":3819,"control_cpu_s":0.003767} +{"pattern":0,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":417.74,"simulated_board_j":3045.880971,"peak_c":82.23,"job_p99_s":56.02,"point_mae_c":0.635798,"reference_mae_c":0.921273,"forecast_points":12381,"correction_queries":0,"queries":14210,"ceiling_moves":9,"frequency_transitions":3821,"control_cpu_s":0.003582} +{"pattern":0,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.0,"throttle_steps":0,"makespan_s":417.74,"simulated_board_j":3045.880971,"peak_c":82.23,"job_p99_s":56.02,"point_mae_c":0.635798,"reference_mae_c":0.921273,"forecast_points":12381,"correction_queries":0,"queries":14210,"ceiling_moves":9,"frequency_transitions":3821,"control_cpu_s":0.003655} +{"pattern":1,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":538.75,"simulated_board_j":3492.476423,"peak_c":82.23,"job_p99_s":178.5,"point_mae_c":0.85818,"reference_mae_c":1.035502,"forecast_points":16011,"correction_queries":0,"queries":19311,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004728} +{"pattern":1,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":538.75,"simulated_board_j":3492.476423,"peak_c":82.23,"job_p99_s":178.5,"point_mae_c":0.85818,"reference_mae_c":1.035502,"forecast_points":16011,"correction_queries":0,"queries":19311,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004976} +{"pattern":1,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":538.75,"simulated_board_j":3497.10333,"peak_c":82.23,"job_p99_s":178.5,"point_mae_c":0.727766,"reference_mae_c":1.009315,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1854,"control_cpu_s":0.004852} +{"pattern":1,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":538.75,"simulated_board_j":3497.10333,"peak_c":82.23,"job_p99_s":178.5,"point_mae_c":0.727766,"reference_mae_c":1.009315,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1854,"control_cpu_s":0.004843} +{"pattern":1,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":538.75,"simulated_board_j":3492.806164,"peak_c":82.23,"job_p99_s":178.5,"point_mae_c":0.739498,"reference_mae_c":1.012688,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004624} +{"pattern":1,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.0,"throttle_steps":0,"makespan_s":538.75,"simulated_board_j":3492.806164,"peak_c":82.23,"job_p99_s":178.5,"point_mae_c":0.739498,"reference_mae_c":1.012688,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004845} +{"pattern":2,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":381.49,"simulated_board_j":2672.639652,"peak_c":79.461,"job_p99_s":21.48,"point_mae_c":0.591575,"reference_mae_c":0.884357,"forecast_points":11292,"correction_queries":0,"queries":13125,"ceiling_moves":5,"frequency_transitions":8114,"control_cpu_s":0.003232} +{"pattern":2,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":381.49,"simulated_board_j":2672.639652,"peak_c":79.461,"job_p99_s":21.48,"point_mae_c":0.591575,"reference_mae_c":0.884357,"forecast_points":11292,"correction_queries":0,"queries":13125,"ceiling_moves":5,"frequency_transitions":8114,"control_cpu_s":0.003394} +{"pattern":2,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":365.22,"simulated_board_j":2633.845193,"peak_c":81.307,"job_p99_s":5.21,"point_mae_c":0.552913,"reference_mae_c":0.857648,"forecast_points":10806,"correction_queries":0,"queries":12639,"ceiling_moves":5,"frequency_transitions":7936,"control_cpu_s":0.003106} +{"pattern":2,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":365.22,"simulated_board_j":2633.845193,"peak_c":81.307,"job_p99_s":5.21,"point_mae_c":0.552913,"reference_mae_c":0.857648,"forecast_points":10806,"correction_queries":0,"queries":12639,"ceiling_moves":5,"frequency_transitions":7936,"control_cpu_s":0.003325} +{"pattern":2,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":382.51,"simulated_board_j":2645.604875,"peak_c":78.538,"job_p99_s":22.5,"point_mae_c":0.587389,"reference_mae_c":0.843609,"forecast_points":11325,"correction_queries":0,"queries":13158,"ceiling_moves":4,"frequency_transitions":7514,"control_cpu_s":0.003341} +{"pattern":2,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.0,"throttle_steps":0,"makespan_s":382.51,"simulated_board_j":2645.604875,"peak_c":78.538,"job_p99_s":22.5,"point_mae_c":0.587389,"reference_mae_c":0.843609,"forecast_points":11325,"correction_queries":0,"queries":13158,"ceiling_moves":4,"frequency_transitions":7514,"control_cpu_s":0.003442} +{"pattern":3,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.92,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.05,"point_mae_c":0.843901,"reference_mae_c":0.930119,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003024} +{"pattern":3,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.92,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.05,"point_mae_c":0.843901,"reference_mae_c":0.930119,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003225} +{"pattern":3,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.92,"simulated_board_j":2372.551126,"peak_c":77.615,"job_p99_s":1.05,"point_mae_c":0.850204,"reference_mae_c":0.923388,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.002987} +{"pattern":3,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.92,"simulated_board_j":2372.551126,"peak_c":77.615,"job_p99_s":1.05,"point_mae_c":0.850204,"reference_mae_c":0.923388,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003229} +{"pattern":3,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.92,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.05,"point_mae_c":0.859807,"reference_mae_c":0.928173,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003079} +{"pattern":3,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008,"throttle_steps":0,"makespan_s":359.92,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.05,"point_mae_c":0.859807,"reference_mae_c":0.928173,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003307} +{"pattern":4,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":1009.87,"simulated_board_j":6372.262955,"peak_c":82.23,"job_p99_s":639.99,"point_mae_c":0.515443,"reference_mae_c":0.640917,"forecast_points":30144,"correction_queries":0,"queries":39322,"ceiling_moves":11,"frequency_transitions":30,"control_cpu_s":0.009039} +{"pattern":4,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":1009.87,"simulated_board_j":6372.262955,"peak_c":82.23,"job_p99_s":639.99,"point_mae_c":0.515443,"reference_mae_c":0.640917,"forecast_points":30144,"correction_queries":0,"queries":39322,"ceiling_moves":11,"frequency_transitions":30,"control_cpu_s":0.009519} +{"pattern":4,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":1008.94,"simulated_board_j":6348.257503,"peak_c":82.23,"job_p99_s":639.06,"point_mae_c":0.503787,"reference_mae_c":0.630852,"forecast_points":30117,"correction_queries":0,"queries":39294,"ceiling_moves":15,"frequency_transitions":31,"control_cpu_s":0.008985} +{"pattern":4,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":1008.94,"simulated_board_j":6348.257503,"peak_c":82.23,"job_p99_s":639.06,"point_mae_c":0.503787,"reference_mae_c":0.630852,"forecast_points":30117,"correction_queries":0,"queries":39294,"ceiling_moves":15,"frequency_transitions":31,"control_cpu_s":0.00944} +{"pattern":4,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":988.27,"simulated_board_j":6315.551787,"peak_c":82.23,"job_p99_s":618.39,"point_mae_c":0.515453,"reference_mae_c":0.644973,"forecast_points":29496,"correction_queries":0,"queries":38676,"ceiling_moves":10,"frequency_transitions":27,"control_cpu_s":0.008785} +{"pattern":4,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.8,"throttle_steps":0,"makespan_s":988.27,"simulated_board_j":6315.551787,"peak_c":82.23,"job_p99_s":618.39,"point_mae_c":0.515453,"reference_mae_c":0.644973,"forecast_points":29496,"correction_queries":0,"queries":38676,"ceiling_moves":10,"frequency_transitions":27,"control_cpu_s":0.009106} diff --git a/results/automatic-discovery/first-conflict-failure.log b/results/automatic-discovery/first-conflict-failure.log new file mode 100644 index 0000000..e7fe5dd --- /dev/null +++ b/results/automatic-discovery/first-conflict-failure.log @@ -0,0 +1,65 @@ +clang-18 -Ivendor -Isrc -Isrc/shared -Ibuild -I/home/ubuntu/lertick-pr/build/deps/install/include -DLERTICK_VERSION=\"source\" -O2 -g -target bpf -mcpu=v3 -Wall -Wno-compare-distinct-pointer-types -D__TARGET_ARCH_arm64 -Ivendor/bpf-compat -I/usr/include/aarch64-linux-gnu -c src/bpf/scx_lertick.bpf.c -o build/scx_lertick.bpf.o +In file included from src/bpf/scx_lertick.bpf.c:23: +In file included from vendor/scx/common.bpf.h:21: +build/vmlinux.h:69147:2: warning: declaration does not declare anything [-Wmissing-declarations] + 69147 | struct aes_enckey; + | ^ +build/vmlinux.h:85401:3: warning: declaration does not declare anything [-Wmissing-declarations] + 85401 | struct ns_tree; + | ^ +build/vmlinux.h:108771:2: warning: declaration does not declare anything [-Wmissing-declarations] + 108771 | struct __filename_head; + | ^ +build/vmlinux.h:152894:2: warning: declaration does not declare anything [-Wmissing-declarations] + 152894 | union pipe_index; + | ^ +build/vmlinux.h:171167:4: warning: declaration does not declare anything [-Wmissing-declarations] + 171167 | struct freelist_counters; + | ^ +5 warnings generated. +bpftool gen skeleton build/scx_lertick.bpf.o name scx_lertick > build/scx_lertick.bpf.skel.h.tmp +mv build/scx_lertick.bpf.skel.h.tmp build/scx_lertick.bpf.skel.h +cc -Ivendor -Isrc -Isrc/shared -Ibuild -I/home/ubuntu/lertick-pr/build/deps/install/include -DLERTICK_VERSION=\"source\" -Isrc/userspace -O2 -g -std=gnu11 -Wall -Wextra src/userspace/scx_lertick.c src/userspace/lerwatt_plugin.c src/userspace/runtime.c -o build/scx_lertick -L/home/ubuntu/lertick-pr/build/deps/install/lib -lbpf -lelf -lzstd -pthread -lz -lelf -lz +In file included from vendor/scx/common.h:74, + from src/userspace/scx_lertick.c:28: +vendor/scx/compat.h: In function ‘__COMPAT_read_enum’: +vendor/scx/compat.h:44:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 44 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +vendor/scx/compat.h:55:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 55 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +vendor/scx/compat.h: In function ‘__COMPAT_struct_has_field’: +vendor/scx/compat.h:99:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 99 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +build/test_lerwatt_plugin +{"test":"lerwatt_plugin","status":"passed"} +python3 tests/check_integration_abi.py +Integration ABI 2 golden check passed (56 values). +systemd: installed helper enabled an unlimited validated worker; absent peer reports waiting +systemd: active off/on preserved scheduling and boot intent, and replaced shared maps +systemd: stop/update/rollback preserved enabled-but-stopped intent and private integration setting +systemd: uninstall disabled/detached/removed the validation service; configuration retained +{"result": "passed", "checks": {"install_does_not_start_or_enable": true, "enabled_unlimited_ready_with_optional_peer_absent": true, "active_integration_toggle_restarts_only_owned_service": true, "stop_update_rollback_preserve_configuration_and_intent": true, "uninstall_disables_detaches_removes_and_retains_config": true}, "environment": {"os_release": "PRETTY_NAME=\"Ubuntu 24.04.5 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.5 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\n", "architecture": "aarch64", "kernel": "7.0.0-38-generic", "systemd": "systemd 255 (255.4-1ubuntu8.18)", "elapsed_seconds": 4.76}, "scope": "real sched_ext attachment and PID 1 lifecycle in an opted-in VM; no physical power controls or long hardware run"} +integration: Lerwatt-first startup connected; BPF consumed contracts +integration: online-to-EWMA scheduler change reconnected while Lerwatt stayed running +integration: frozen demand expired and resumed without stale control +integration: temporal-to-adaptive predictor change preserved Lertick PID and session +integration: reverse startup order connected +Traceback (most recent call last): + File "/home/ubuntu/lertick-auto-discovery/tests/test_power_integration.py", line 292, in main + assert row["lerwatt"] is False + ^^^^^^^^^^^^^^^^^^^^^^^ +AssertionError + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/home/ubuntu/lertick-auto-discovery/tests/test_power_integration.py", line 343, in + main() + File "/home/ubuntu/lertick-auto-discovery/tests/test_power_integration.py", line 331, in main + PINS.rmdir() + File "/usr/lib/python3.12/pathlib.py", line 1353, in rmdir + os.rmdir(self) +FileNotFoundError: [Errno 2] No such file or directory: '/sys/fs/bpf/lertick' diff --git a/results/automatic-discovery/first-service-fixture-failure.log b/results/automatic-discovery/first-service-fixture-failure.log new file mode 100644 index 0000000..9604830 --- /dev/null +++ b/results/automatic-discovery/first-service-fixture-failure.log @@ -0,0 +1,3 @@ +Traceback (most recent call last): + File "", line 113, in +AssertionError: (0, 'Lerwatt integration configured: auto\n', '') diff --git a/results/automatic-discovery/initial-live-pair.log b/results/automatic-discovery/initial-live-pair.log new file mode 100644 index 0000000..1616686 --- /dev/null +++ b/results/automatic-discovery/initial-live-pair.log @@ -0,0 +1,19 @@ +test_deploy: plan/check/verify, indefinite/finite defaults, signals, trust paths, maintenance, staging and build fingerprints passed (stubs only) +Integration ABI 2 golden check passed (56 values); peer compiled ABI matches. +systemd: install enabled an unlimited ready worker (nominal) +systemd: stopped worker was recovered and restarted +systemd: missing sensor restored controls; returning sensor recovered service +systemd: uninstall stopped, disabled and restored the validation service +{"result": "passed", "checks": {"installation_prediction_mode": "nominal", "optional_coordination_waits_independently": true, "enabled_unlimited_ready": true, "watchdog_restores_and_restarts": true, "sensor_failure_recovers": true, "uninstall_stops_disables_restores": true}, "hardware": "temporary file fixture"} +systemd: installed helper enabled an unlimited validated worker; absent peer reports waiting +systemd: active off/on preserved scheduling and boot intent, and replaced shared maps +systemd: stop/update/rollback preserved enabled-but-stopped intent and private integration setting +systemd: uninstall disabled/detached/removed the validation service; configuration retained +{"result": "passed", "checks": {"install_does_not_start_or_enable": true, "enabled_unlimited_ready_with_optional_peer_absent": true, "active_integration_toggle_restarts_only_owned_service": true, "stop_update_rollback_preserve_configuration_and_intent": true, "uninstall_disables_detaches_removes_and_retains_config": true}, "environment": {"os_release": "PRETTY_NAME=\"Ubuntu 24.04.5 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.5 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\n", "architecture": "aarch64", "kernel": "7.0.0-38-generic", "systemd": "systemd 255 (255.4-1ubuntu8.18)", "elapsed_seconds": 4.99}, "scope": "real sched_ext attachment and PID 1 lifecycle in an opted-in VM; no physical power controls or long hardware run"} +integration: Lerwatt-first startup connected; BPF consumed contracts +integration: online-to-EWMA scheduler change reconnected while Lerwatt stayed running +integration: frozen demand expired and resumed without stale control +integration: temporal-to-adaptive predictor change preserved Lertick PID and session +integration: reverse startup order connected +{"environment": {"kernel": "7.0.0-38-generic", "architecture": "aarch64", "os_release": "PRETTY_NAME=\"Ubuntu 24.04.5 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.5 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\n", "systemd": "systemd 255 (255.4-1ubuntu8.18)"}, "hardware": "temporary RK3588 simulated CPU-control files; real sched_ext/BPF", "checks": {"lerwatt_first_continuous_connection": true, "lertick_restart_new_session_reconnects": true, "independent_scheduler_policy_change": true, "frozen_demand_expires_and_recovers": true, "lerwatt_restart_restores_expires_reconnects": true, "independent_power_predictor_change": true, "lertick_first_connection": true, "final_control_restore_scheduler_fallback_pin_cleanup": true}, "result": "passed"} +integration artifacts: /var/tmp/lertick-power-integration-qkldozcs diff --git a/results/automatic-discovery/linux-build-and-tests.log b/results/automatic-discovery/linux-build-and-tests.log new file mode 100644 index 0000000..8d8e2ac --- /dev/null +++ b/results/automatic-discovery/linux-build-and-tests.log @@ -0,0 +1,559 @@ +mkdir -p build +cc -DLERWATT_VERSION=\"source\" -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/lerwattd src/hal_fs.c src/hal_discover.c src/hal_sample.c src/hal_actuate.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c src/contract.c src/notify.c src/checkpoint.c src/lerwattd.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -Isim -o build/lerwatt-sim sim/platform_rk3588.c sim/model.c sim/abi.c sim/load.c src/contract.c sim/lerwatt_sim.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -Isim -o build/test_model tests/test_model.c sim/platform_rk3588.c sim/model.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_learn tests/test_learn.c src/learn.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -Isim -o build/test_forecast tests/test_forecast.c sim/platform_rk3588.c sim/model.c src/learn.c src/forecast.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_forecast_feedback tests/test_forecast_feedback.c src/forecast.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_temporal tests/test_temporal.c src/temporal.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -Isim -o build/test_control_forecast tests/test_control_forecast.c sim/platform_rk3588.c sim/model.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_controller tests/test_controller.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_predict tests/test_predict.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -Isim -o build/test_cooperative_loop tests/test_cooperative_loop.c sim/platform_rk3588.c sim/model.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -Isim -o build/test_closed_loop tests/test_closed_loop.c sim/platform_rk3588.c sim/model.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c -lm -lrt +build/test_model +full load, passive cooling, no throttling: die 77.7 C, big 84.9 C, little 81.7 C, CPU heat 6.42 W, board 10.86 W +bare board, full load, step_wise on: big zone 85.9 C, state 4, 4454 throttle steps +idle, fan: board 2.93 W, die 25.9 C +test_model: all checks passed +build/test_learn +test_learn: a=0.0199 c=-0.00836 ambient=24.6 after 197 samples +test_learn: all checks passed +build/test_forecast +{"case":"steps-passive-seed7","seed":7,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4728,"package_persistence_mae_c":0.4346,"hot_mae_c":0.5406,"hot_persistence_mae_c":0.4779,"hot_rmse_c":0.7595,"constant_package_mae_c":0.4728,"constant_hot_mae_c":0.5406,"adaptive_package_mae_c":0.4727,"adaptive_hot_mae_c":0.4686,"adaptive_hot_rmse_c":0.7206,"hot_persistence_rmse_c":0.8249,"all_samples":26853,"all_adaptive_hot_mae_c":0.4686,"all_persistence_hot_mae_c":0.4779,"all_adaptive_hot_rmse_c":0.7206,"selected":[144,2365,0,24344]} +{"case":"burst2-bare-seed99","seed":99,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.3319,"package_persistence_mae_c":0.3130,"hot_mae_c":1.4259,"hot_persistence_mae_c":1.8220,"hot_rmse_c":1.6772,"constant_package_mae_c":1.5748,"constant_hot_mae_c":3.3919,"adaptive_package_mae_c":0.3677,"adaptive_hot_mae_c":0.9361,"adaptive_hot_rmse_c":1.1324,"hot_persistence_rmse_c":2.1463,"all_samples":26853,"all_adaptive_hot_mae_c":0.9361,"all_persistence_hot_mae_c":1.8220,"all_adaptive_hot_rmse_c":1.1324,"selected":[0,0,0,26853]} +{"case":"burst03-fan-35C","seed":7,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.2463,"package_persistence_mae_c":0.2492,"hot_mae_c":0.5163,"hot_persistence_mae_c":0.5151,"hot_rmse_c":0.5778,"constant_package_mae_c":0.5311,"constant_hot_mae_c":2.2938,"adaptive_package_mae_c":0.2549,"adaptive_hot_mae_c":0.4514,"adaptive_hot_rmse_c":0.5352,"hot_persistence_rmse_c":0.7082,"all_samples":26853,"all_adaptive_hot_mae_c":0.4514,"all_persistence_hot_mae_c":0.5151,"all_adaptive_hot_rmse_c":0.5352,"selected":[0,0,0,26853]} +{"case":"steps-bare-15C-seed13579","seed":13579,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4837,"package_persistence_mae_c":0.6210,"hot_mae_c":0.7202,"hot_persistence_mae_c":0.6895,"hot_rmse_c":1.0453,"constant_package_mae_c":0.4369,"constant_hot_mae_c":0.6020,"adaptive_package_mae_c":0.4313,"adaptive_hot_mae_c":0.5242,"adaptive_hot_rmse_c":0.7347,"hot_persistence_rmse_c":0.9608,"all_samples":26853,"all_adaptive_hot_mae_c":0.5242,"all_persistence_hot_mae_c":0.6895,"all_adaptive_hot_rmse_c":0.7347,"selected":[27,4330,68,22428]} +{"case":"burst2-passive-35C-seed2026","seed":2026,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.3827,"package_persistence_mae_c":0.3626,"hot_mae_c":1.3909,"hot_persistence_mae_c":1.8265,"hot_rmse_c":1.6349,"constant_package_mae_c":0.6469,"constant_hot_mae_c":2.1709,"adaptive_package_mae_c":0.3923,"adaptive_hot_mae_c":0.9087,"adaptive_hot_rmse_c":1.1156,"hot_persistence_rmse_c":2.1613,"all_samples":26853,"all_adaptive_hot_mae_c":0.9087,"all_persistence_hot_mae_c":1.8265,"all_adaptive_hot_rmse_c":1.1156,"selected":[0,0,0,26853]} +{"case":"burst03-bare-seed2718","seed":2718,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.3565,"package_persistence_mae_c":0.3453,"hot_mae_c":0.4766,"hot_persistence_mae_c":0.4366,"hot_rmse_c":0.5959,"constant_package_mae_c":1.3834,"constant_hot_mae_c":3.4102,"adaptive_package_mae_c":0.3630,"adaptive_hot_mae_c":0.4160,"adaptive_hot_rmse_c":0.5317,"hot_persistence_rmse_c":0.6725,"all_samples":26853,"all_adaptive_hot_mae_c":0.4160,"all_persistence_hot_mae_c":0.4366,"all_adaptive_hot_rmse_c":0.5317,"selected":[0,0,0,26853]} +{"case":"ramp-passive-seed424242","seed":424242,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4322,"package_persistence_mae_c":0.3828,"hot_mae_c":0.4888,"hot_persistence_mae_c":0.4618,"hot_rmse_c":0.6015,"constant_package_mae_c":0.4322,"constant_hot_mae_c":0.4888,"adaptive_package_mae_c":0.4322,"adaptive_hot_mae_c":0.4411,"adaptive_hot_rmse_c":0.5537,"hot_persistence_rmse_c":0.6893,"all_samples":26853,"all_adaptive_hot_mae_c":0.4411,"all_persistence_hot_mae_c":0.4618,"all_adaptive_hot_rmse_c":0.5537,"selected":[0,1111,0,25742]} +{"case":"alternating-clusters-bare-seed619","seed":619,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4327,"package_persistence_mae_c":0.3646,"hot_mae_c":0.6787,"hot_persistence_mae_c":0.6369,"hot_rmse_c":1.2525,"constant_package_mae_c":0.4327,"constant_hot_mae_c":0.6787,"adaptive_package_mae_c":0.4325,"adaptive_hot_mae_c":0.6507,"adaptive_hot_rmse_c":1.2485,"hot_persistence_rmse_c":1.3378,"all_samples":26853,"all_adaptive_hot_mae_c":0.6507,"all_persistence_hot_mae_c":0.6369,"all_adaptive_hot_rmse_c":1.2485,"selected":[161,5767,0,20925]} +{"case":"regime-changes-bare-seed701","seed":701,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.3936,"package_persistence_mae_c":0.3692,"hot_mae_c":0.8939,"hot_persistence_mae_c":0.9262,"hot_rmse_c":1.1863,"constant_package_mae_c":1.2214,"constant_hot_mae_c":2.6325,"adaptive_package_mae_c":0.4009,"adaptive_hot_mae_c":0.6540,"adaptive_hot_rmse_c":0.8674,"hot_persistence_rmse_c":1.3907,"all_samples":26853,"all_adaptive_hot_mae_c":0.6540,"all_persistence_hot_mae_c":0.9262,"all_adaptive_hot_rmse_c":0.8674,"selected":[1639,0,2138,23076]} +{"case":"duty20-bare-35C-seed883","seed":883,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.6055,"package_persistence_mae_c":0.5665,"hot_mae_c":1.3540,"hot_persistence_mae_c":2.0748,"hot_rmse_c":1.6954,"constant_package_mae_c":1.2501,"constant_hot_mae_c":3.4094,"adaptive_package_mae_c":0.5702,"adaptive_hot_mae_c":1.3540,"adaptive_hot_rmse_c":1.6954,"hot_persistence_rmse_c":2.5945,"all_samples":26853,"all_adaptive_hot_mae_c":1.3540,"all_persistence_hot_mae_c":2.0748,"all_adaptive_hot_rmse_c":1.6954,"selected":[0,0,26853,0]} +{"case":"random-steps-fan-15C-seed9959","seed":9959,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4525,"package_persistence_mae_c":0.3864,"hot_mae_c":0.5930,"hot_persistence_mae_c":0.5537,"hot_rmse_c":0.8690,"constant_package_mae_c":0.4525,"constant_hot_mae_c":0.5930,"adaptive_package_mae_c":0.4525,"adaptive_hot_mae_c":0.5475,"adaptive_hot_rmse_c":0.8364,"hot_persistence_rmse_c":0.9289,"all_samples":26853,"all_adaptive_hot_mae_c":0.5475,"all_persistence_hot_mae_c":0.5537,"all_adaptive_hot_rmse_c":0.8364,"selected":[84,854,0,25915]} +{"case":"burst45-passive-seed1701","seed":1701,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.5226,"package_persistence_mae_c":0.5004,"hot_mae_c":0.9437,"hot_persistence_mae_c":1.0449,"hot_rmse_c":1.7919,"constant_package_mae_c":0.5226,"constant_hot_mae_c":0.9437,"adaptive_package_mae_c":0.5233,"adaptive_hot_mae_c":0.9452,"adaptive_hot_rmse_c":1.7643,"hot_persistence_rmse_c":1.8246,"all_samples":26853,"all_adaptive_hot_mae_c":0.9452,"all_persistence_hot_mae_c":1.0449,"all_adaptive_hot_rmse_c":1.7643,"selected":[1705,1689,0,23459]} +{"case":"varying-period-passive-30C-seed104729","seed":104729,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.3767,"package_persistence_mae_c":0.3537,"hot_mae_c":1.3838,"hot_persistence_mae_c":1.7906,"hot_rmse_c":1.7003,"constant_package_mae_c":0.5736,"constant_hot_mae_c":3.4865,"adaptive_package_mae_c":0.3800,"adaptive_hot_mae_c":1.1864,"adaptive_hot_rmse_c":1.5538,"hot_persistence_rmse_c":2.4416,"all_samples":26853,"all_adaptive_hot_mae_c":1.1864,"all_persistence_hot_mae_c":1.7906,"all_adaptive_hot_rmse_c":1.5538,"selected":[0,0,7003,19850]} +{"case":"asymmetric-steps-bare-20C-seed130363","seed":130363,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.5082,"package_persistence_mae_c":0.6260,"hot_mae_c":1.0907,"hot_persistence_mae_c":0.7791,"hot_rmse_c":1.6013,"constant_package_mae_c":0.4712,"constant_hot_mae_c":0.6758,"adaptive_package_mae_c":0.4735,"adaptive_hot_mae_c":0.6159,"adaptive_hot_rmse_c":0.9496,"hot_persistence_rmse_c":1.1528,"all_samples":26853,"all_adaptive_hot_mae_c":0.6159,"all_persistence_hot_mae_c":0.7791,"all_adaptive_hot_rmse_c":0.9496,"selected":[103,4607,133,22010]} +{"case":"random-fast-bare-35C-seed155921","seed":155921,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.5461,"package_persistence_mae_c":0.5120,"hot_mae_c":1.2352,"hot_persistence_mae_c":0.7033,"hot_rmse_c":1.5878,"constant_package_mae_c":0.4951,"constant_hot_mae_c":0.8580,"adaptive_package_mae_c":0.4958,"adaptive_hot_mae_c":0.6963,"adaptive_hot_rmse_c":1.1118,"hot_persistence_rmse_c":1.1176,"all_samples":26853,"all_adaptive_hot_mae_c":0.6963,"all_persistence_hot_mae_c":0.7033,"all_adaptive_hot_rmse_c":1.1118,"selected":[14217,453,97,12086]} +{"case":"sparse-bursts-fan-seed196613","seed":196613,"replicate":0,"horizon_s":5,"samples":23424,"package_mae_c":0.3096,"package_persistence_mae_c":0.2773,"hot_mae_c":1.0422,"hot_persistence_mae_c":1.2247,"hot_rmse_c":1.6409,"constant_package_mae_c":0.3575,"constant_hot_mae_c":1.3411,"adaptive_package_mae_c":0.3067,"adaptive_hot_mae_c":1.0425,"adaptive_hot_rmse_c":1.6410,"hot_persistence_rmse_c":1.9114,"all_samples":26853,"all_adaptive_hot_mae_c":1.0603,"all_persistence_hot_mae_c":1.2192,"all_adaptive_hot_rmse_c":1.6710,"selected":[0,0,23353,71]} +{"case":"sine-passive-15C-seed262147","seed":262147,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4638,"package_persistence_mae_c":0.4143,"hot_mae_c":0.6726,"hot_persistence_mae_c":0.7397,"hot_rmse_c":0.8534,"constant_package_mae_c":0.4638,"constant_hot_mae_c":0.6726,"adaptive_package_mae_c":0.4640,"adaptive_hot_mae_c":0.6853,"adaptive_hot_rmse_c":0.8690,"hot_persistence_rmse_c":0.9938,"all_samples":26853,"all_adaptive_hot_mae_c":0.6853,"all_persistence_hot_mae_c":0.7397,"all_adaptive_hot_rmse_c":0.8690,"selected":[250,15359,0,11244]} +{"case":"cooling-change-35C-seed327673","seed":327673,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4290,"package_persistence_mae_c":0.3782,"hot_mae_c":0.5225,"hot_persistence_mae_c":0.4122,"hot_rmse_c":0.6474,"constant_package_mae_c":0.4290,"constant_hot_mae_c":0.5225,"adaptive_package_mae_c":0.3997,"adaptive_hot_mae_c":0.4438,"adaptive_hot_rmse_c":0.5866,"hot_persistence_rmse_c":0.6427,"all_samples":26853,"all_adaptive_hot_mae_c":0.4438,"all_persistence_hot_mae_c":0.4122,"all_adaptive_hot_rmse_c":0.5866,"selected":[2483,38,0,24332]} +{"case":"noisy-burst-bare-seed393241","seed":393241,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.6844,"package_persistence_mae_c":0.6813,"hot_mae_c":1.5235,"hot_persistence_mae_c":1.8569,"hot_rmse_c":1.8195,"constant_package_mae_c":1.6232,"constant_hot_mae_c":3.4374,"adaptive_package_mae_c":0.7090,"adaptive_hot_mae_c":1.0777,"adaptive_hot_rmse_c":1.3329,"hot_persistence_rmse_c":2.2316,"all_samples":26853,"all_adaptive_hot_mae_c":1.0777,"all_persistence_hot_mae_c":1.8569,"all_adaptive_hot_rmse_c":1.3329,"selected":[0,0,0,26853]} +{"case":"duty2of7-bare-seed458879","seed":458879,"replicate":0,"horizon_s":5,"samples":26853,"package_mae_c":0.4752,"package_persistence_mae_c":0.4459,"hot_mae_c":1.2071,"hot_persistence_mae_c":2.0813,"hot_rmse_c":1.5079,"constant_package_mae_c":1.2470,"constant_hot_mae_c":4.2069,"adaptive_package_mae_c":0.4727,"adaptive_hot_mae_c":1.2071,"adaptive_hot_rmse_c":1.5079,"hot_persistence_rmse_c":2.6306,"all_samples":26853,"all_adaptive_hot_mae_c":1.2071,"all_persistence_hot_mae_c":2.0813,"all_adaptive_hot_rmse_c":1.5079,"selected":[0,0,26853,0]} +build/test_forecast_feedback +test_forecast_feedback: causality, delayed labels, fallback and clock checks passed +build/test_temporal +test_temporal: delayed labels, causal history, reference fallback and bounds passed (7344 bytes/cluster) +python3 tests/test_runtime_forecast.py +..... +---------------------------------------------------------------------- +Ran 5 tests in 0.007s + +OK +python3 tests/test_runtime_summary.py +.. +---------------------------------------------------------------------- +Ran 2 tests in 0.002s + +OK +python3 tests/test_cooperative_summary.py +... +---------------------------------------------------------------------- +Ran 3 tests in 0.000s + +OK +build/test_control_forecast --temporal --integrated --development +{"case":"steps-passive","replicate":0,"seed":7001,"samples":26853,"persistence_mae_c":0.486501,"current_mae_c":0.484831,"candidate_mae_c":0.484831,"persistence_rmse_c":0.840648,"current_rmse_c":0.741659,"candidate_rmse_c":0.741659,"current_model_ready":26853,"candidate_model_ready":26853,"peak_c":73.0,"throttle_steps":0,"served":0.801200} +{"case":"burst2-bare","replicate":0,"seed":7003,"samples":26853,"persistence_mae_c":1.680119,"current_mae_c":0.944647,"candidate_mae_c":0.747381,"persistence_rmse_c":2.020321,"current_rmse_c":1.165410,"candidate_rmse_c":0.965414,"current_model_ready":26840,"candidate_model_ready":26853,"peak_c":82.2,"throttle_steps":0,"served":0.663236} +{"case":"burst03-fan","replicate":0,"seed":7013,"samples":26853,"persistence_mae_c":0.506751,"current_mae_c":0.449531,"candidate_mae_c":0.449531,"persistence_rmse_c":0.701677,"current_rmse_c":0.533216,"candidate_rmse_c":0.533216,"current_model_ready":26853,"candidate_model_ready":26853,"peak_c":47.2,"throttle_steps":0,"served":0.580275} +{"case":"asymmetric-bare","replicate":0,"seed":7019,"samples":26853,"persistence_mae_c":0.727812,"current_mae_c":0.597914,"candidate_mae_c":0.597914,"persistence_rmse_c":1.097105,"current_rmse_c":0.902890,"candidate_rmse_c":0.902890,"current_model_ready":26853,"candidate_model_ready":26853,"peak_c":82.2,"throttle_steps":0,"served":0.755197} +{"case":"sine-passive","replicate":0,"seed":7027,"samples":26853,"persistence_mae_c":0.743890,"current_mae_c":0.663892,"candidate_mae_c":0.663892,"persistence_rmse_c":0.999014,"current_rmse_c":0.850244,"candidate_rmse_c":0.850244,"current_model_ready":26853,"candidate_model_ready":26853,"peak_c":55.5,"throttle_steps":0,"served":0.792567} +{"case":"regime-changes-bare","replicate":0,"seed":7039,"samples":26853,"persistence_mae_c":0.874370,"current_mae_c":0.644139,"candidate_mae_c":0.587251,"persistence_rmse_c":1.316337,"current_rmse_c":0.872167,"candidate_rmse_c":0.801227,"current_model_ready":26849,"candidate_model_ready":26853,"peak_c":82.2,"throttle_steps":0,"served":0.618728} +build/test_controller +test_controller: fallback, joint allocation and raw-guard checks passed +build/test_predict +control influence: original 2400000, cooperative 1800000, raw guard 1200000 kHz +test_predict: action support, delayed learning, pure queries, backend replacement and MPC influence passed (14368 bytes/predictor) +build/test_closed_loop +| scenario | controller | peak C | s >85C | kernel | ceil | freq | mean W | served | +|------------------------|------------|--------|---------|--------|--------|----------|---------|---------| +| full load, passive | off | 84.1 | 0.0 | 0 | 0 | 16 | 10.61 | 69.38% | +| full load, passive | rule | 81.3 | 0.0 | 0 | 2 | 18 | 10.48 | 68.43% | +| full load, passive | learned | 81.3 | 0.0 | 0 | 2 | 18 | 10.48 | 68.38% | +| big-core load, passive | off | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | rule | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | learned | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| full load, bare board | off | 94.8 | 2293.3 | 5228 | 0 | 10462 | 8.17 | 53.44% | +| full load, bare board | rule | 81.3 | 0.0 | 0 | 11 | 27 | 7.49 | 51.04% | +| full load, bare board | learned | 81.3 | 0.0 | 0 | 14 | 30 | 7.48 | 51.08% | +| burst load, bare board | off | 85.9 | 11.5 | 93 | 0 | 6381 | 6.88 | 68.85% | +| burst load, bare board | rule | 82.2 | 0.0 | 0 | 42 | 5839 | 6.64 | 66.43% | +| burst load, bare board | learned | 82.2 | 0.0 | 0 | 34 | 5873 | 6.66 | 66.52% | + +| held-out case | rule: peak / moves / served | learned: peak / moves / served | +|------------------------|-----------------------------|--------------------------------| +| full passive, seed 7 | 81.3 / 2 / 68.44% | 81.3 / 4 / 68.35% | +| full bare, seed 7 | 81.3 / 10 / 51.04% | 81.3 / 16 / 51.09% | +| burst bare, seed 7 | 82.2 / 39 / 66.51% | 82.2 / 27 / 66.68% | +| burst bare, seed 99 | 82.2 / 38 / 66.62% | 82.2 / 34 / 66.49% | +| full passive, 35 C | 82.2 / 41 / 62.60% | 81.3 / 11 / 62.95% | +| full bare, 35 C | 82.2 / 21 / 44.77% | 81.3 / 12 / 44.38% | +| burst bare, 35 C | 82.2 / 151 / 59.24% | 82.2 / 13 / 60.25% | +| full bare, 15 C | 81.3 / 32 / 55.73% | 79.5 / 10 / 55.22% | +| full passive, warm 60 | 81.3 / 2 / 67.18% | 81.3 / 6 / 67.04% | +| full bare, warm 70 | 82.2 / 51 / 48.98% | 81.3 / 13 / 49.23% | +| burst bare, warm 70 | 82.2 / 61 / 65.23% | 82.2 / 58 / 65.27% | +| 10 s bursts, bare | 82.2 / 110 / 66.05% | 81.3 / 27 / 65.87% | +| 300 ms bursts, bare | 69.3 / 0 / 58.03% | 69.3 / 0 / 58.03% | +| 10 s bursts, passive | 60.1 / 0 / 70.46% | 60.1 / 0 / 70.46% | +| load steps, bare | 82.2 / 31 / 69.42% | 81.3 / 30 / 69.83% | +| load steps, passive | 69.3 / 0 / 79.25% | 69.3 / 0 / 79.25% | +| one cluster, bare | 76.7 / 0 / 99.99% | 76.7 / 0 / 99.99% | +| full, fan | 52.7 / 0 / 69.38% | 52.7 / 0 / 69.38% | +| burst, fan, 35 C | 52.7 / 0 / 68.92% | 52.7 / 0 / 68.92% | + +peak C: hottest passive zone after 300 s. kernel: step_wise throttle steps. ceil: Lerwatt ceiling moves. served: share of demanded work done. +hot start cooling=0 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +test_closed_loop: all checks passed +build/test_closed_loop --cross-cluster +| scenario | controller | peak C | s >85C | kernel | ceil | freq | mean W | served | +|------------------------|------------|--------|---------|--------|--------|----------|---------|---------| +| full load, passive | off | 84.1 | 0.0 | 0 | 0 | 16 | 10.61 | 69.38% | +| full load, passive | rule | 81.3 | 0.0 | 0 | 2 | 18 | 10.48 | 68.43% | +| full load, passive | learned | 81.3 | 0.0 | 0 | 5 | 21 | 10.43 | 68.44% | +| big-core load, passive | off | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | rule | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | learned | 72.1 | 0.0 | 0 | 1 | 12 | 8.76 | 99.99% | +| full load, bare board | off | 94.8 | 2293.3 | 5228 | 0 | 10462 | 8.17 | 53.44% | +| full load, bare board | rule | 81.3 | 0.0 | 0 | 11 | 27 | 7.49 | 51.04% | +| full load, bare board | learned | 81.3 | 0.0 | 0 | 8 | 24 | 7.44 | 50.89% | +| burst load, bare board | off | 85.9 | 11.5 | 93 | 0 | 6381 | 6.88 | 68.85% | +| burst load, bare board | rule | 82.2 | 0.0 | 0 | 42 | 5839 | 6.64 | 66.43% | +| burst load, bare board | learned | 79.5 | 0.0 | 0 | 8 | 5702 | 6.54 | 65.56% | + +| held-out case | rule: peak / moves / served | learned: peak / moves / served | +|------------------------|-----------------------------|--------------------------------| +| full passive, seed 7 | 81.3 / 2 / 68.44% | 81.3 / 2 / 68.19% | +| full bare, seed 7 | 81.3 / 10 / 51.04% | 81.3 / 10 / 50.89% | +| burst bare, seed 7 | 82.2 / 39 / 66.51% | 79.5 / 9 / 65.96% | +| burst bare, seed 99 | 82.2 / 38 / 66.62% | 79.5 / 8 / 65.75% | +| full passive, 35 C | 82.2 / 41 / 62.60% | 81.3 / 7 / 62.97% | +| full bare, 35 C | 82.2 / 21 / 44.77% | 81.3 / 20 / 44.37% | +| burst bare, 35 C | 82.2 / 151 / 59.24% | 79.5 / 12 / 58.95% | +| full bare, 15 C | 81.3 / 32 / 55.73% | 80.4 / 6 / 55.13% | +| full passive, warm 60 | 81.3 / 2 / 67.18% | 81.3 / 6 / 66.85% | +| full bare, warm 70 | 82.2 / 51 / 48.98% | 82.2 / 21 / 47.98% | +| burst bare, warm 70 | 82.2 / 61 / 65.23% | 81.3 / 15 / 64.76% | +| 10 s bursts, bare | 82.2 / 110 / 66.05% | 77.6 / 8 / 64.50% | +| 300 ms bursts, bare | 69.3 / 0 / 58.03% | 69.3 / 0 / 58.03% | +| 10 s bursts, passive | 60.1 / 0 / 70.46% | 60.1 / 0 / 70.46% | +| load steps, bare | 82.2 / 31 / 69.42% | 81.3 / 15 / 68.30% | +| load steps, passive | 69.3 / 0 / 79.25% | 61.0 / 18 / 73.56% | +| one cluster, bare | 76.7 / 0 / 99.99% | 76.7 / 2 / 99.99% | +| full, fan | 52.7 / 0 / 69.38% | 52.7 / 0 / 69.38% | +| burst, fan, 35 C | 52.7 / 0 / 68.92% | 52.7 / 0 / 68.92% | + +peak C: hottest passive zone after 300 s. kernel: step_wise throttle steps. ceil: Lerwatt ceiling moves. served: share of demanded work done. +hot start cooling=0 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +test_closed_loop: all checks passed +build/test_closed_loop --cooperative +| scenario | controller | peak C | s >85C | kernel | ceil | freq | mean W | served | +|------------------------|------------|--------|---------|--------|--------|----------|---------|---------| +| full load, passive | off | 84.1 | 0.0 | 0 | 0 | 16 | 10.61 | 69.38% | +| full load, passive | rule | 81.3 | 0.0 | 0 | 2 | 18 | 10.48 | 68.43% | +| full load, passive | learned | 81.3 | 0.0 | 0 | 2 | 18 | 10.48 | 68.38% | +| big-core load, passive | off | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | rule | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | learned | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| full load, bare board | off | 94.8 | 2293.3 | 5228 | 0 | 10462 | 8.17 | 53.44% | +| full load, bare board | rule | 81.3 | 0.0 | 0 | 11 | 27 | 7.49 | 51.04% | +| full load, bare board | learned | 81.3 | 0.0 | 0 | 10 | 26 | 7.49 | 51.19% | +| burst load, bare board | off | 85.9 | 11.5 | 93 | 0 | 6381 | 6.88 | 68.85% | +| burst load, bare board | rule | 82.2 | 0.0 | 0 | 42 | 5839 | 6.64 | 66.43% | +| burst load, bare board | learned | 82.2 | 0.0 | 0 | 34 | 5873 | 6.66 | 66.52% | + +| held-out case | rule: peak / moves / served | learned: peak / moves / served | +|------------------------|-----------------------------|--------------------------------| +| full passive, seed 7 | 81.3 / 2 / 68.44% | 81.3 / 4 / 68.35% | +| full bare, seed 7 | 81.3 / 10 / 51.04% | 81.3 / 10 / 51.20% | +| burst bare, seed 7 | 82.2 / 39 / 66.51% | 82.2 / 27 / 66.68% | +| burst bare, seed 99 | 82.2 / 38 / 66.62% | 82.2 / 34 / 66.49% | +| full passive, 35 C | 82.2 / 41 / 62.60% | 81.3 / 11 / 62.95% | +| full bare, 35 C | 82.2 / 21 / 44.77% | 81.3 / 12 / 44.38% | +| burst bare, 35 C | 82.2 / 151 / 59.24% | 82.2 / 13 / 60.25% | +| full bare, 15 C | 81.3 / 32 / 55.73% | 79.5 / 10 / 55.22% | +| full passive, warm 60 | 81.3 / 2 / 67.18% | 81.3 / 6 / 67.04% | +| full bare, warm 70 | 82.2 / 51 / 48.98% | 81.3 / 13 / 49.23% | +| burst bare, warm 70 | 82.2 / 61 / 65.23% | 82.2 / 58 / 65.27% | +| 10 s bursts, bare | 82.2 / 110 / 66.05% | 81.3 / 27 / 65.87% | +| 300 ms bursts, bare | 69.3 / 0 / 58.03% | 69.3 / 0 / 58.03% | +| 10 s bursts, passive | 60.1 / 0 / 70.46% | 60.1 / 0 / 70.46% | +| load steps, bare | 82.2 / 31 / 69.42% | 81.3 / 30 / 69.83% | +| load steps, passive | 69.3 / 0 / 79.25% | 69.3 / 0 / 79.25% | +| one cluster, bare | 76.7 / 0 / 99.99% | 76.7 / 0 / 99.99% | +| full, fan | 52.7 / 0 / 69.38% | 52.7 / 0 / 69.38% | +| burst, fan, 35 C | 52.7 / 0 / 68.92% | 52.7 / 0 / 68.92% | + +peak C: hottest passive zone after 300 s. kernel: step_wise throttle steps. ceil: Lerwatt ceiling moves. served: share of demanded work done. +hot start cooling=0 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +test_closed_loop: all checks passed +build/test_closed_loop --cooperative --cross-cluster +| scenario | controller | peak C | s >85C | kernel | ceil | freq | mean W | served | +|------------------------|------------|--------|---------|--------|--------|----------|---------|---------| +| full load, passive | off | 84.1 | 0.0 | 0 | 0 | 16 | 10.61 | 69.38% | +| full load, passive | rule | 81.3 | 0.0 | 0 | 2 | 18 | 10.48 | 68.43% | +| full load, passive | learned | 81.3 | 0.0 | 0 | 5 | 21 | 10.43 | 68.44% | +| big-core load, passive | off | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | rule | 72.1 | 0.0 | 0 | 0 | 12 | 8.76 | 99.99% | +| big-core load, passive | learned | 72.1 | 0.0 | 0 | 1 | 12 | 8.76 | 99.99% | +| full load, bare board | off | 94.8 | 2293.3 | 5228 | 0 | 10462 | 8.17 | 53.44% | +| full load, bare board | rule | 81.3 | 0.0 | 0 | 11 | 27 | 7.49 | 51.04% | +| full load, bare board | learned | 81.3 | 0.0 | 0 | 8 | 24 | 7.44 | 50.89% | +| burst load, bare board | off | 85.9 | 11.5 | 93 | 0 | 6381 | 6.88 | 68.85% | +| burst load, bare board | rule | 82.2 | 0.0 | 0 | 42 | 5839 | 6.64 | 66.43% | +| burst load, bare board | learned | 79.5 | 0.0 | 0 | 8 | 5702 | 6.54 | 65.56% | + +| held-out case | rule: peak / moves / served | learned: peak / moves / served | +|------------------------|-----------------------------|--------------------------------| +| full passive, seed 7 | 81.3 / 2 / 68.44% | 81.3 / 2 / 68.19% | +| full bare, seed 7 | 81.3 / 10 / 51.04% | 81.3 / 10 / 50.89% | +| burst bare, seed 7 | 82.2 / 39 / 66.51% | 79.5 / 9 / 65.96% | +| burst bare, seed 99 | 82.2 / 38 / 66.62% | 79.5 / 8 / 65.75% | +| full passive, 35 C | 82.2 / 41 / 62.60% | 81.3 / 7 / 62.97% | +| full bare, 35 C | 82.2 / 21 / 44.77% | 81.3 / 20 / 44.37% | +| burst bare, 35 C | 82.2 / 151 / 59.24% | 79.5 / 12 / 58.95% | +| full bare, 15 C | 81.3 / 32 / 55.73% | 80.4 / 6 / 55.13% | +| full passive, warm 60 | 81.3 / 2 / 67.18% | 81.3 / 6 / 66.85% | +| full bare, warm 70 | 82.2 / 51 / 48.98% | 82.2 / 21 / 47.98% | +| burst bare, warm 70 | 82.2 / 61 / 65.23% | 81.3 / 15 / 64.76% | +| 10 s bursts, bare | 82.2 / 110 / 66.05% | 77.6 / 8 / 64.50% | +| 300 ms bursts, bare | 69.3 / 0 / 58.03% | 69.3 / 0 / 58.03% | +| 10 s bursts, passive | 60.1 / 0 / 70.46% | 60.1 / 0 / 70.46% | +| load steps, bare | 82.2 / 31 / 69.42% | 81.3 / 15 / 68.30% | +| load steps, passive | 69.3 / 0 / 79.25% | 61.0 / 18 / 73.56% | +| one cluster, bare | 76.7 / 0 / 99.99% | 76.7 / 2 / 99.99% | +| full, fan | 52.7 / 0 / 69.38% | 52.7 / 0 / 69.38% | +| burst, fan, 35 C | 52.7 / 0 / 68.92% | 52.7 / 0 / 68.92% | + +peak C: hottest passive zone after 300 s. kernel: step_wise throttle steps. ceil: Lerwatt ceiling moves. served: share of demanded work done. +hot start cooling=0 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=0 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 full: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=42 burst: peak 82.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=1 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=0 seed=99 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=42 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=7 burst: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 full: peak 83.2 C, 0 throttle steps +hot start cooling=2 policy=1 seed=99 burst: peak 83.2 C, 0 throttle steps +test_closed_loop: all checks passed +build/test_cooperative_loop --full +{"pattern":0,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":405.220,"simulated_board_j":3064.103829,"peak_c":81.307,"job_p99_s":45.290,"point_mae_c":0.618066,"reference_mae_c":0.934517,"forecast_points":12006,"correction_queries":0,"queries":15565,"ceiling_moves":15,"frequency_transitions":5032,"control_cpu_s":0.003446} +{"pattern":0,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":405.220,"simulated_board_j":3064.103829,"peak_c":81.307,"job_p99_s":45.290,"point_mae_c":0.618066,"reference_mae_c":0.934517,"forecast_points":12006,"correction_queries":0,"queries":15565,"ceiling_moves":15,"frequency_transitions":5032,"control_cpu_s":0.003817} +{"pattern":0,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":419.520,"simulated_board_j":3140.746146,"peak_c":81.307,"job_p99_s":59.980,"point_mae_c":0.608290,"reference_mae_c":0.908556,"forecast_points":12435,"correction_queries":0,"queries":14279,"ceiling_moves":18,"frequency_transitions":5389,"control_cpu_s":0.003588} +{"pattern":0,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":419.520,"simulated_board_j":3140.746146,"peak_c":81.307,"job_p99_s":59.980,"point_mae_c":0.608290,"reference_mae_c":0.908556,"forecast_points":12435,"correction_queries":0,"queries":14279,"ceiling_moves":18,"frequency_transitions":5389,"control_cpu_s":0.003681} +{"pattern":0,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":402.760,"simulated_board_j":3056.050846,"peak_c":81.307,"job_p99_s":42.820,"point_mae_c":0.598512,"reference_mae_c":0.901395,"forecast_points":11931,"correction_queries":0,"queries":15553,"ceiling_moves":15,"frequency_transitions":5019,"control_cpu_s":0.003332} +{"pattern":0,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":402.760,"simulated_board_j":3056.050846,"peak_c":81.307,"job_p99_s":42.820,"point_mae_c":0.598512,"reference_mae_c":0.901395,"forecast_points":11931,"correction_queries":0,"queries":15553,"ceiling_moves":15,"frequency_transitions":5019,"control_cpu_s":0.003601} +{"pattern":1,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":503.040,"simulated_board_j":3412.501516,"peak_c":82.230,"job_p99_s":142.790,"point_mae_c":0.709844,"reference_mae_c":1.032735,"forecast_points":14940,"correction_queries":0,"queries":16479,"ceiling_moves":15,"frequency_transitions":1587,"control_cpu_s":0.004321} +{"pattern":1,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":503.040,"simulated_board_j":3412.501516,"peak_c":82.230,"job_p99_s":142.790,"point_mae_c":0.709844,"reference_mae_c":1.032735,"forecast_points":14940,"correction_queries":0,"queries":16479,"ceiling_moves":15,"frequency_transitions":1587,"control_cpu_s":0.004525} +{"pattern":1,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":500.660,"simulated_board_j":3394.311558,"peak_c":82.230,"job_p99_s":140.410,"point_mae_c":0.719791,"reference_mae_c":1.044086,"forecast_points":14868,"correction_queries":0,"queries":15913,"ceiling_moves":17,"frequency_transitions":1514,"control_cpu_s":0.004368} +{"pattern":1,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":500.660,"simulated_board_j":3394.311558,"peak_c":82.230,"job_p99_s":140.410,"point_mae_c":0.719791,"reference_mae_c":1.044086,"forecast_points":14868,"correction_queries":0,"queries":15913,"ceiling_moves":17,"frequency_transitions":1514,"control_cpu_s":0.004452} +{"pattern":1,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":497.110,"simulated_board_j":3383.829286,"peak_c":82.230,"job_p99_s":136.860,"point_mae_c":0.718125,"reference_mae_c":1.028734,"forecast_points":14763,"correction_queries":0,"queries":15518,"ceiling_moves":16,"frequency_transitions":1443,"control_cpu_s":0.004362} +{"pattern":1,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":497.110,"simulated_board_j":3383.829286,"peak_c":82.230,"job_p99_s":136.860,"point_mae_c":0.718125,"reference_mae_c":1.028734,"forecast_points":14763,"correction_queries":0,"queries":15518,"ceiling_moves":16,"frequency_transitions":1443,"control_cpu_s":0.004480} +{"pattern":2,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":360.640,"simulated_board_j":2638.146268,"peak_c":81.307,"job_p99_s":1.590,"point_mae_c":0.531840,"reference_mae_c":0.859365,"forecast_points":10668,"correction_queries":0,"queries":10209,"ceiling_moves":6,"frequency_transitions":8519,"control_cpu_s":0.003051} +{"pattern":2,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":360.640,"simulated_board_j":2638.146268,"peak_c":81.307,"job_p99_s":1.590,"point_mae_c":0.531840,"reference_mae_c":0.859365,"forecast_points":10668,"correction_queries":0,"queries":10209,"ceiling_moves":6,"frequency_transitions":8519,"control_cpu_s":0.003251} +{"pattern":2,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":360.630,"simulated_board_j":2630.933970,"peak_c":81.307,"job_p99_s":1.580,"point_mae_c":0.519062,"reference_mae_c":0.849117,"forecast_points":10668,"correction_queries":0,"queries":10066,"ceiling_moves":7,"frequency_transitions":8387,"control_cpu_s":0.003041} +{"pattern":2,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":360.630,"simulated_board_j":2630.933970,"peak_c":81.307,"job_p99_s":1.580,"point_mae_c":0.519062,"reference_mae_c":0.849117,"forecast_points":10668,"correction_queries":0,"queries":10066,"ceiling_moves":7,"frequency_transitions":8387,"control_cpu_s":0.003235} +{"pattern":2,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":360.640,"simulated_board_j":2626.024997,"peak_c":81.307,"job_p99_s":1.590,"point_mae_c":0.536754,"reference_mae_c":0.852969,"forecast_points":10668,"correction_queries":0,"queries":9965,"ceiling_moves":9,"frequency_transitions":8378,"control_cpu_s":0.003089} +{"pattern":2,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":360.640,"simulated_board_j":2626.024997,"peak_c":81.307,"job_p99_s":1.590,"point_mae_c":0.536754,"reference_mae_c":0.852969,"forecast_points":10668,"correction_queries":0,"queries":9965,"ceiling_moves":9,"frequency_transitions":8378,"control_cpu_s":0.003234} +{"pattern":3,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.870,"simulated_board_j":2372.536090,"peak_c":76.692,"job_p99_s":1.050,"point_mae_c":0.843208,"reference_mae_c":0.929450,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.002996} +{"pattern":3,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.870,"simulated_board_j":2372.536090,"peak_c":76.692,"job_p99_s":1.050,"point_mae_c":0.843208,"reference_mae_c":0.929450,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003215} +{"pattern":3,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.870,"simulated_board_j":2372.536090,"peak_c":77.615,"job_p99_s":1.050,"point_mae_c":0.850526,"reference_mae_c":0.923730,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.002960} +{"pattern":3,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.870,"simulated_board_j":2372.536090,"peak_c":77.615,"job_p99_s":1.050,"point_mae_c":0.850526,"reference_mae_c":0.923730,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003194} +{"pattern":3,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.870,"simulated_board_j":2372.536090,"peak_c":77.615,"job_p99_s":1.050,"point_mae_c":0.860971,"reference_mae_c":0.929357,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003067} +{"pattern":3,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.870,"simulated_board_j":2372.536090,"peak_c":77.615,"job_p99_s":1.050,"point_mae_c":0.860971,"reference_mae_c":0.929357,"forecast_points":10644,"correction_queries":0,"queries":8067,"ceiling_moves":0,"frequency_transitions":7829,"control_cpu_s":0.003214} +{"pattern":4,"seed":42,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":980.400,"simulated_board_j":6295.971093,"peak_c":81.307,"job_p99_s":610.530,"point_mae_c":0.478139,"reference_mae_c":0.640429,"forecast_points":29259,"correction_queries":0,"queries":35913,"ceiling_moves":36,"frequency_transitions":42,"control_cpu_s":0.008729} +{"pattern":4,"seed":42,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":980.400,"simulated_board_j":6295.971093,"peak_c":81.307,"job_p99_s":610.530,"point_mae_c":0.478139,"reference_mae_c":0.640429,"forecast_points":29259,"correction_queries":0,"queries":35913,"ceiling_moves":36,"frequency_transitions":42,"control_cpu_s":0.008973} +{"pattern":4,"seed":7,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":979.530,"simulated_board_j":6294.123159,"peak_c":81.307,"job_p99_s":609.650,"point_mae_c":0.483719,"reference_mae_c":0.643218,"forecast_points":29235,"correction_queries":0,"queries":36274,"ceiling_moves":32,"frequency_transitions":40,"control_cpu_s":0.008612} +{"pattern":4,"seed":7,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":979.550,"simulated_board_j":6293.863896,"peak_c":81.307,"job_p99_s":609.670,"point_mae_c":0.486560,"reference_mae_c":0.646034,"forecast_points":29235,"correction_queries":1,"queries":36309,"ceiling_moves":32,"frequency_transitions":40,"control_cpu_s":0.008985} +{"pattern":4,"seed":99,"joint":false,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":981.830,"simulated_board_j":6300.329490,"peak_c":81.307,"job_p99_s":611.960,"point_mae_c":0.484815,"reference_mae_c":0.641113,"forecast_points":29304,"correction_queries":0,"queries":36617,"ceiling_moves":28,"frequency_transitions":38,"control_cpu_s":0.008705} +{"pattern":4,"seed":99,"joint":false,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":981.900,"simulated_board_j":6300.200034,"peak_c":81.307,"job_p99_s":612.020,"point_mae_c":0.482736,"reference_mae_c":0.639256,"forecast_points":29304,"correction_queries":1,"queries":36652,"ceiling_moves":28,"frequency_transitions":38,"control_cpu_s":0.008887} +{"pattern":0,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":418.790,"simulated_board_j":3046.446255,"peak_c":82.230,"job_p99_s":57.070,"point_mae_c":0.631586,"reference_mae_c":0.926190,"forecast_points":12411,"correction_queries":0,"queries":14238,"ceiling_moves":9,"frequency_transitions":3805,"control_cpu_s":0.003428} +{"pattern":0,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":418.790,"simulated_board_j":3046.446255,"peak_c":82.230,"job_p99_s":57.070,"point_mae_c":0.631586,"reference_mae_c":0.926190,"forecast_points":12411,"correction_queries":0,"queries":14238,"ceiling_moves":9,"frequency_transitions":3805,"control_cpu_s":0.003683} +{"pattern":0,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":418.220,"simulated_board_j":3046.942437,"peak_c":82.230,"job_p99_s":56.500,"point_mae_c":0.614085,"reference_mae_c":0.917913,"forecast_points":12396,"correction_queries":0,"queries":14225,"ceiling_moves":9,"frequency_transitions":3819,"control_cpu_s":0.003401} +{"pattern":0,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":418.220,"simulated_board_j":3046.942437,"peak_c":82.230,"job_p99_s":56.500,"point_mae_c":0.614085,"reference_mae_c":0.917913,"forecast_points":12396,"correction_queries":0,"queries":14225,"ceiling_moves":9,"frequency_transitions":3819,"control_cpu_s":0.003767} +{"pattern":0,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":417.740,"simulated_board_j":3045.880971,"peak_c":82.230,"job_p99_s":56.020,"point_mae_c":0.635798,"reference_mae_c":0.921273,"forecast_points":12381,"correction_queries":0,"queries":14210,"ceiling_moves":9,"frequency_transitions":3821,"control_cpu_s":0.003582} +{"pattern":0,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1636992.000000,"throttle_steps":0,"makespan_s":417.740,"simulated_board_j":3045.880971,"peak_c":82.230,"job_p99_s":56.020,"point_mae_c":0.635798,"reference_mae_c":0.921273,"forecast_points":12381,"correction_queries":0,"queries":14210,"ceiling_moves":9,"frequency_transitions":3821,"control_cpu_s":0.003655} +{"pattern":1,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":538.750,"simulated_board_j":3492.476423,"peak_c":82.230,"job_p99_s":178.500,"point_mae_c":0.858180,"reference_mae_c":1.035502,"forecast_points":16011,"correction_queries":0,"queries":19311,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004728} +{"pattern":1,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":538.750,"simulated_board_j":3492.476423,"peak_c":82.230,"job_p99_s":178.500,"point_mae_c":0.858180,"reference_mae_c":1.035502,"forecast_points":16011,"correction_queries":0,"queries":19311,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004976} +{"pattern":1,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":538.750,"simulated_board_j":3497.103330,"peak_c":82.230,"job_p99_s":178.500,"point_mae_c":0.727766,"reference_mae_c":1.009315,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1854,"control_cpu_s":0.004852} +{"pattern":1,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":538.750,"simulated_board_j":3497.103330,"peak_c":82.230,"job_p99_s":178.500,"point_mae_c":0.727766,"reference_mae_c":1.009315,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1854,"control_cpu_s":0.004843} +{"pattern":1,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":538.750,"simulated_board_j":3492.806164,"peak_c":82.230,"job_p99_s":178.500,"point_mae_c":0.739498,"reference_mae_c":1.012688,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004624} +{"pattern":1,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1548288.000000,"throttle_steps":0,"makespan_s":538.750,"simulated_board_j":3492.806164,"peak_c":82.230,"job_p99_s":178.500,"point_mae_c":0.739498,"reference_mae_c":1.012688,"forecast_points":16011,"correction_queries":0,"queries":19312,"ceiling_moves":10,"frequency_transitions":1829,"control_cpu_s":0.004845} +{"pattern":2,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":381.490,"simulated_board_j":2672.639652,"peak_c":79.461,"job_p99_s":21.480,"point_mae_c":0.591575,"reference_mae_c":0.884357,"forecast_points":11292,"correction_queries":0,"queries":13125,"ceiling_moves":5,"frequency_transitions":8114,"control_cpu_s":0.003232} +{"pattern":2,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":381.490,"simulated_board_j":2672.639652,"peak_c":79.461,"job_p99_s":21.480,"point_mae_c":0.591575,"reference_mae_c":0.884357,"forecast_points":11292,"correction_queries":0,"queries":13125,"ceiling_moves":5,"frequency_transitions":8114,"control_cpu_s":0.003394} +{"pattern":2,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":365.220,"simulated_board_j":2633.845193,"peak_c":81.307,"job_p99_s":5.210,"point_mae_c":0.552913,"reference_mae_c":0.857648,"forecast_points":10806,"correction_queries":0,"queries":12639,"ceiling_moves":5,"frequency_transitions":7936,"control_cpu_s":0.003106} +{"pattern":2,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":365.220,"simulated_board_j":2633.845193,"peak_c":81.307,"job_p99_s":5.210,"point_mae_c":0.552913,"reference_mae_c":0.857648,"forecast_points":10806,"correction_queries":0,"queries":12639,"ceiling_moves":5,"frequency_transitions":7936,"control_cpu_s":0.003325} +{"pattern":2,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":382.510,"simulated_board_j":2645.604875,"peak_c":78.538,"job_p99_s":22.500,"point_mae_c":0.587389,"reference_mae_c":0.843609,"forecast_points":11325,"correction_queries":0,"queries":13158,"ceiling_moves":4,"frequency_transitions":7514,"control_cpu_s":0.003341} +{"pattern":2,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1251792.000000,"throttle_steps":0,"makespan_s":382.510,"simulated_board_j":2645.604875,"peak_c":78.538,"job_p99_s":22.500,"point_mae_c":0.587389,"reference_mae_c":0.843609,"forecast_points":11325,"correction_queries":0,"queries":13158,"ceiling_moves":4,"frequency_transitions":7514,"control_cpu_s":0.003442} +{"pattern":3,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.920,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.050,"point_mae_c":0.843901,"reference_mae_c":0.930119,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003024} +{"pattern":3,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.920,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.050,"point_mae_c":0.843901,"reference_mae_c":0.930119,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003225} +{"pattern":3,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.920,"simulated_board_j":2372.551126,"peak_c":77.615,"job_p99_s":1.050,"point_mae_c":0.850204,"reference_mae_c":0.923388,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.002987} +{"pattern":3,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.920,"simulated_board_j":2372.551126,"peak_c":77.615,"job_p99_s":1.050,"point_mae_c":0.850204,"reference_mae_c":0.923388,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003229} +{"pattern":3,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.920,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.050,"point_mae_c":0.859807,"reference_mae_c":0.928173,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003079} +{"pattern":3,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":1020321.008000,"throttle_steps":0,"makespan_s":359.920,"simulated_board_j":2372.551126,"peak_c":76.692,"job_p99_s":1.050,"point_mae_c":0.859807,"reference_mae_c":0.928173,"forecast_points":10647,"correction_queries":0,"queries":12480,"ceiling_moves":1,"frequency_transitions":7779,"control_cpu_s":0.003307} +{"pattern":4,"seed":42,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":1009.870,"simulated_board_j":6372.262955,"peak_c":82.230,"job_p99_s":639.990,"point_mae_c":0.515443,"reference_mae_c":0.640917,"forecast_points":30144,"correction_queries":0,"queries":39322,"ceiling_moves":11,"frequency_transitions":30,"control_cpu_s":0.009039} +{"pattern":4,"seed":42,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":1009.870,"simulated_board_j":6372.262955,"peak_c":82.230,"job_p99_s":639.990,"point_mae_c":0.515443,"reference_mae_c":0.640917,"forecast_points":30144,"correction_queries":0,"queries":39322,"ceiling_moves":11,"frequency_transitions":30,"control_cpu_s":0.009519} +{"pattern":4,"seed":7,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":1008.940,"simulated_board_j":6348.257503,"peak_c":82.230,"job_p99_s":639.060,"point_mae_c":0.503787,"reference_mae_c":0.630852,"forecast_points":30117,"correction_queries":0,"queries":39294,"ceiling_moves":15,"frequency_transitions":31,"control_cpu_s":0.008985} +{"pattern":4,"seed":7,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":1008.940,"simulated_board_j":6348.257503,"peak_c":82.230,"job_p99_s":639.060,"point_mae_c":0.503787,"reference_mae_c":0.630852,"forecast_points":30117,"correction_queries":0,"queries":39294,"ceiling_moves":15,"frequency_transitions":31,"control_cpu_s":0.009440} +{"pattern":4,"seed":99,"joint":true,"mode":"nominal","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":988.270,"simulated_board_j":6315.551787,"peak_c":82.230,"job_p99_s":618.390,"point_mae_c":0.515453,"reference_mae_c":0.644973,"forecast_points":29496,"correction_queries":0,"queries":38676,"ceiling_moves":10,"frequency_transitions":27,"control_cpu_s":0.008785} +{"pattern":4,"seed":99,"joint":true,"mode":"cooperative","jobs_completed":2880,"backlog":0,"offered_work":2919628.800000,"throttle_steps":0,"makespan_s":988.270,"simulated_board_j":6315.551787,"peak_c":82.230,"job_p99_s":618.390,"point_mae_c":0.515453,"reference_mae_c":0.644973,"forecast_points":29496,"correction_queries":0,"queries":38676,"ceiling_moves":10,"frequency_transitions":27,"control_cpu_s":0.009106} +cc -DLERWATT_VERSION=\"source\" -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -DLW_NO_BPF -o build/lerwattd-standalone src/hal_fs.c src/hal_discover.c src/hal_sample.c src/hal_actuate.c src/controller.c src/learn.c src/forecast.c src/temporal.c src/predict.c src/contract.c src/notify.c src/checkpoint.c src/lerwattd.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_runtime_fs tests/test_runtime_fs.c src/hal_fs.c src/hal_actuate.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_discovery tests/test_discovery.c src/hal_discover.c src/hal_sample.c src/hal_fs.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_notify tests/test_notify.c src/notify.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -o build/test_checkpoint tests/test_checkpoint.c src/checkpoint.c -lm -lrt +cc -O2 -g -std=c11 -D_GNU_SOURCE -Wall -Wextra -Wshadow -Werror -Iinclude -Isrc -DLW_NO_BPF -o build/test_contract tests/test_contract.c src/contract.c -lm -lrt +python3 tests/check_integration_abi.py +Integration ABI 2 golden check passed (56 values). +build/test_runtime_fs +lerwatt: cannot journal /tmp/lerwatt-runtime-WTCNkb/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq (Is a directory); not writing it +lerwatt: write /tmp/lerwatt-runtime-WTCNkb/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq <- 1500 failed: Is a directory +lerwatt: restore failed: /tmp/lerwatt-runtime-WTCNkb/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq <- 2000 +test_runtime_fs: ok (strict reads, lock lifetime, journal faults, restore validation) +build/test_discovery +test_discovery: topology, frequency, sensor and read-only capability fixtures passed +build/test_notify +test_notify: environment validation, readiness, progress heartbeats and socket failure passed +build/test_checkpoint +test_checkpoint: learned-only roundtrip, identity/schema/age validation and private atomic files passed +build/test_contract +test_contract: ABI2 identity, independent peer versions, bounded freshness and recovery passed +python3 tests/test_daemon_deployment.py build/lerwattd-standalone +daemon deployment: CLI, read-only checks, 16-policy range control, locking, recovery and sensor loss passed +sh tests/test_deploy.sh +test_deploy: all checks passed (fixtures only; no host service or CPU changes) +tests/e2e.sh build +e2e: ok - joint planning requires the learned policy +e2e: ok - unknown point forecaster is rejected before touching a system +e2e: ok - prediction mode and unsupported combinations are rejected before discovery +e2e: ok - no hardware and no simulator -> clear error +e2e: ok - simulator up, policy4 scaling_max_freq = 2400000 +e2e: ok - live root rejects a second simulator, including --force +e2e: ok - auto-detected the simulator +e2e: ok - lerwattd capped big0 down to 1200 MHz while the board ran hot +e2e: ok - clean exit restored every knob and removed the journal +e2e: ok - joint-policy startup falls back before training and restores knobs +e2e: ok - cooperative cold start keeps fallback, valid telemetry and restoration +e2e: ok - kill -9 then --restore recovered scaling_max_freq = 2400000 +e2e: ok - simulator removed its marker on exit +e2e: ok - same root restarts after SIGTERM, duration expiry and SIGINT; data preserved +e2e: ok - unidentified non-empty roots remain protected +e2e: all checks passed +mkdir -p build +bpftool btf dump file /sys/kernel/btf/vmlinux format c > build/vmlinux.h.tmp +mv build/vmlinux.h.tmp build/vmlinux.h +clang-18 -Ivendor -Isrc -Isrc/shared -Ibuild -I/home/ubuntu/lertick-pr/build/deps/install/include -DLERTICK_VERSION=\"source\" -O2 -g -target bpf -mcpu=v3 -Wall -Wno-compare-distinct-pointer-types -D__TARGET_ARCH_arm64 -Ivendor/bpf-compat -I/usr/include/aarch64-linux-gnu -c src/bpf/scx_lertick.bpf.c -o build/scx_lertick.bpf.o +In file included from src/bpf/scx_lertick.bpf.c:23: +In file included from vendor/scx/common.bpf.h:21: +build/vmlinux.h:69147:2: warning: declaration does not declare anything [-Wmissing-declarations] + 69147 | struct aes_enckey; + | ^ +build/vmlinux.h:85401:3: warning: declaration does not declare anything [-Wmissing-declarations] + 85401 | struct ns_tree; + | ^ +build/vmlinux.h:108771:2: warning: declaration does not declare anything [-Wmissing-declarations] + 108771 | struct __filename_head; + | ^ +build/vmlinux.h:152894:2: warning: declaration does not declare anything [-Wmissing-declarations] + 152894 | union pipe_index; + | ^ +build/vmlinux.h:171167:4: warning: declaration does not declare anything [-Wmissing-declarations] + 171167 | struct freelist_counters; + | ^ +5 warnings generated. +bpftool gen skeleton build/scx_lertick.bpf.o name scx_lertick > build/scx_lertick.bpf.skel.h.tmp +mv build/scx_lertick.bpf.skel.h.tmp build/scx_lertick.bpf.skel.h +cc -Ivendor -Isrc -Isrc/shared -Ibuild -I/home/ubuntu/lertick-pr/build/deps/install/include -DLERTICK_VERSION=\"source\" -Isrc/userspace -O2 -g -std=gnu11 -Wall -Wextra src/userspace/scx_lertick.c src/userspace/lerwatt_plugin.c src/userspace/runtime.c -o build/scx_lertick -L/home/ubuntu/lertick-pr/build/deps/install/lib -lbpf -lelf -lzstd -pthread -lz -lelf -lz +In file included from vendor/scx/common.h:74, + from src/userspace/scx_lertick.c:28: +vendor/scx/compat.h: In function ‘__COMPAT_read_enum’: +vendor/scx/compat.h:44:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 44 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +vendor/scx/compat.h:55:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 55 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +vendor/scx/compat.h: In function ‘__COMPAT_struct_has_field’: +vendor/scx/compat.h:99:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 99 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +cc -O2 -g -std=gnu11 -Wall -Wextra benchmarks/burst_workload.c -o build/burst_workload -pthread -lm +cc -O2 -g -std=gnu11 -Wall -Wextra benchmarks/phase2_workload.c -o build/phase2_workload -pthread -lm +cc -O2 -g -std=gnu11 -Wall -Wextra tests/lifecycle_workload.c -o build/lifecycle_workload -pthread -lm +cc -Isrc/userspace -O2 -std=gnu11 -Wall -Wextra -Werror tests/test_loader_runtime.c src/userspace/runtime.c -o build/test_loader_runtime +python3 tests/check_integration_abi.py +Integration ABI 2 golden check passed (56 values). +build/test_loader_runtime +loader runtime: private output, lock ownership, idle-state guard, readiness notify and maintenance lifetime passed +sh tests/test_deploy.sh +test_deploy: plan/check/verify, indefinite/finite defaults, signals, trust paths, maintenance, staging and build fingerprints passed (stubs only) +sh tests/test_service.sh +test_service: notify readiness, long-running intent, immutable bundles, active verification, atomic update/rollback, foreign refusal and default fallback passed (fixtures only) +python3 tests/test_report.py +..... +---------------------------------------------------------------------- +Ran 5 tests in 0.111s + +OK +cc -Isrc/shared -O2 -std=c11 -Wall -Wextra -Werror tests/test_model.c -o build/test_model +build/test_model +{"test":"synthetic_holdout","samples":1000,"model_squared_error":563987,"fixed_squared_error":156938088319} +{"test":"fractional_carry","oracle_trials":100000,"model_bytes":48} +{"test":"model","status":"passed","oracle_trials":200121} +cc -Isrc/shared -O2 -std=c11 -Wall -Wextra -Werror tests/test_accounting.c -o build/test_accounting +build/test_accounting +accounting: 202000 oracle cases and callback-order traces passed +cc -Ibenchmarks -O2 -std=c11 -Wall -Wextra -Werror tests/test_burst_profiles.c -o build/test_burst_profiles +build/test_burst_profiles +burst profiles: phase boundaries, deterministic seeds, groups and u64 bounds passed +cc -Isrc/shared -O2 -std=c11 -Wall -Wextra -Werror tests/test_cpuperf.c -o build/test_cpuperf -lm +build/test_cpuperf +{"test":"cpuperf","status":"passed"} +cc -Ivendor -Isrc/shared -Isrc/userspace -O2 -std=gnu11 -Wall -Wextra -Werror tests/test_lerwatt_plugin.c src/userspace/lerwatt_plugin.c -o build/test_lerwatt_plugin +build/test_lerwatt_plugin +{"test":"lerwatt_plugin","status":"passed"} +python3 tests/check_integration_abi.py +Integration ABI 2 golden check passed (56 values). +Integration ABI 2 golden check passed (56 values); peer compiled ABI matches. diff --git a/results/automatic-discovery/linux-service-fixture-followup.log b/results/automatic-discovery/linux-service-fixture-followup.log new file mode 100644 index 0000000..5ce3978 --- /dev/null +++ b/results/automatic-discovery/linux-service-fixture-followup.log @@ -0,0 +1 @@ +test_service: notify readiness, long-running intent, immutable bundles, active verification, atomic update/rollback, foreign refusal and default fallback passed (fixtures only) diff --git a/results/automatic-discovery/old-argv-fixture-failure.log b/results/automatic-discovery/old-argv-fixture-failure.log new file mode 100644 index 0000000..c3f72f6 --- /dev/null +++ b/results/automatic-discovery/old-argv-fixture-failure.log @@ -0,0 +1,3 @@ +Traceback (most recent call last): + File "", line 132, in +AssertionError diff --git a/results/automatic-discovery/portable-foreground-fixtures.log b/results/automatic-discovery/portable-foreground-fixtures.log new file mode 100644 index 0000000..13c7c6a --- /dev/null +++ b/results/automatic-discovery/portable-foreground-fixtures.log @@ -0,0 +1 @@ +test_deploy: plan/check/verify, indefinite/finite defaults, signals, trust paths, maintenance, staging and build fingerprints passed (stubs only) diff --git a/results/automatic-discovery/portable-lerwatt-fixtures.log b/results/automatic-discovery/portable-lerwatt-fixtures.log new file mode 100644 index 0000000..4de7d6e --- /dev/null +++ b/results/automatic-discovery/portable-lerwatt-fixtures.log @@ -0,0 +1 @@ +test_deploy: all checks passed (fixtures only; no host service or CPU changes) diff --git a/results/automatic-discovery/portable-service-fixtures.log b/results/automatic-discovery/portable-service-fixtures.log new file mode 100644 index 0000000..5ce3978 --- /dev/null +++ b/results/automatic-discovery/portable-service-fixtures.log @@ -0,0 +1 @@ +test_service: notify readiness, long-running intent, immutable bundles, active verification, atomic update/rollback, foreign refusal and default fallback passed (fixtures only) diff --git a/results/automatic-discovery/provenance.json b/results/automatic-discovery/provenance.json new file mode 100644 index 0000000..dcb0e20 --- /dev/null +++ b/results/automatic-discovery/provenance.json @@ -0,0 +1,25 @@ +{ + "baseline": "5ce8a3c", + "recorded_utc": "2026-11-02T17:42:56.174813+00:00", + "evidence_sha256": { + "README.md": "16244409dbb330d16aaff3258208449d10bc166956f50789a82141c9b4cfa372", + "ci-musl-failure.log": "874be5f8d076d922147fa1f077d3a509aa86569f9711f2e3c4573717fbf3fd88", + "control-summary.json": "9e74762e49ce9b221e9eb8abbf5c0e071c6987e778471322dd2e7bb214ea23a5", + "final-live-pair.log": "8f5620e709a63a1f19e1d05dd872c03df0d01a2459c788dc8dd79e60ff0f5569", + "finite-jobs.jsonl": "3c7858b7ed51b69280e1f8c17520de4ab49770ac6c095c3e6607d83c9c818d68", + "first-conflict-failure.log": "4c10ef76306ed10a7a5a5adb6b81544d0393c9a7ff3076b6798135276dfa4952", + "first-service-fixture-failure.log": "7dbf8da6d7f711e7a857a175952aa6db5a5bfb77553d1a26a71887a919551bae", + "initial-live-pair.log": "349de732553cf7ba0e5a646cc4a67d8e89d2b2d767867f48262bd60b3117f43f", + "linux-build-and-tests.log": "e68934912ec73ea884be85a809ffcd8847722a073eea263f276ddebbd9720c6f", + "linux-service-fixture-followup.log": "32cd2b425beeb3a6b31bce24481160da326f08074870792fc495126f20552e87", + "old-argv-fixture-failure.log": "5b322409080f5178a0927b39a6b8bdb8a5a52f3889fad3b963c4e280e0795d22", + "portable-foreground-fixtures.log": "77be90f6d97ebc8c186d51b7a5a2676de4b3a74f87533c6a5b56a7f2e84b0312", + "portable-lerwatt-fixtures.log": "565b6cb0d04952400ec611f7841d379cba9312824c77f59df96655019453c259", + "portable-service-fixtures.log": "32cd2b425beeb3a6b31bce24481160da326f08074870792fc495126f20552e87", + "raw-archive.json": "d9a669aa9e8672ae89b34300ebd5f2a2d2f359be00eb8a9d64230704427d9b4e", + "result.json": "be36cefbd3fe7f1f9aecb89d0476aea9102a4b4385989f3ee045404e2da1782b", + "source-identity.json": "6d18331720dc8c6a1122849a1220f6c3384a582bbc3c52a78f3b93a0b8324697", + "status-fixture-failure.log": "40a51e64775d76029e3fa691ff6b70ebf72b430d5e20df640ad4b5b3aa533d33" + }, + "no_energy_or_model_accuracy_improvement_claim": true +} diff --git a/results/automatic-discovery/raw-archive.json b/results/automatic-discovery/raw-archive.json new file mode 100644 index 0000000..0eb7a17 --- /dev/null +++ b/results/automatic-discovery/raw-archive.json @@ -0,0 +1,6 @@ +{ + "path": "results/local/automatic-discovery-final-pair.tgz", + "bytes": 17179, + "sha256": "c22a84c84f612944659bd6890214df4479d96d263f9cd4110b0262acc46df83e", + "vm_path": "/var/tmp/lertick-power-integration-s07845od" +} diff --git a/results/automatic-discovery/result.json b/results/automatic-discovery/result.json new file mode 100644 index 0000000..4c875de --- /dev/null +++ b/results/automatic-discovery/result.json @@ -0,0 +1,21 @@ +{ + "environment": { + "kernel": "7.0.0-38-generic", + "architecture": "aarch64", + "os_release": "PRETTY_NAME=\"Ubuntu 24.04.5 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.5 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\n", + "systemd": "systemd 255 (255.4-1ubuntu8.18)" + }, + "hardware": "temporary RK3588 simulated CPU-control files; real sched_ext/BPF", + "checks": { + "lerwatt_first_continuous_connection": true, + "lertick_restart_new_session_reconnects": true, + "independent_scheduler_policy_change": true, + "frozen_demand_expires_and_recovers": true, + "lerwatt_restart_restores_expires_reconnects": true, + "independent_power_predictor_change": true, + "lertick_first_connection": true, + "final_control_restore_scheduler_fallback_pin_cleanup": true, + "foreign_pin_preserved_auto_falls_back_without_advice": true + }, + "result": "passed" +} diff --git a/results/automatic-discovery/source-identity.json b/results/automatic-discovery/source-identity.json new file mode 100644 index 0000000..5a57b84 --- /dev/null +++ b/results/automatic-discovery/source-identity.json @@ -0,0 +1,121 @@ +{ + "files": { + "lerwatt-auto-discovery": { + "Makefile": "4c6335c1cfd4df4bcb87ef18aede229bd0096e5b6d8cf500136a8c5ae3a73a2f", + "deploy.sh": "eac0bb15c94e729ed5ce6be2c2da9006ff01c0fe29c7854e0a3f57c03e979009", + "docs/INTEGRATION.md": "3c40ef4796400a2d352fd9ec41e072911dd07c6c6bac035f6acac418492fba5d", + "include/lerwatt/contract.h": "b19b030600cf7b365e0b182fe3655aab2d5dd6cf8aa6b6c589196251a64b6eed", + "include/lerwatt/controller.h": "b415e5e60425aa783c9c90ffa5d532621eba8289e91212b4c74c0ee2d013b5eb", + "include/lerwatt/forecast.h": "0cf89c0c5dfd7b888e99cefaa08fb55802fa96741e5cddd75011716e57bbf905", + "include/lerwatt/hal.h": "4ad85de2f9d9185a07cdf1aed1b98084ba7483c2d53f75926bb830d3fe904d66", + "include/lerwatt/learn.h": "5ffdc676d148948038605b577cb90864e304ce2def61cee027a9fb6d6677127a", + "include/lerwatt/predict.h": "49aafa0f808ae47c86e8efb1400522852d230d7ad7db4b35ce2b7a57722d748b", + "include/lerwatt/temporal.h": "e8f4f47e4c639604672e62e38be616cf6871d2c1406cdbcca9559f4cbe9c4c27", + "sim/abi.c": "5a50ab25a37775a6eada1decf626e96907c3e545fef21f36cf8bf8ccf2017628", + "sim/abi.h": "71e38aae1903acb40ca810d4ab6cc62b670494e54cc7428f2957b6f75f594aaf", + "sim/lerwatt_sim.c": "2db38f27215c3a272481a7745bf2c6a036742daa1280330cf4c7bf25de76d5a2", + "sim/load.c": "4e5f7aef689abd8f195835afb514da99f35f6c3bb9f83e53eb3b31551f5959c9", + "sim/load.h": "3666e213c868a6b6f0f14a23ecf0f1d38c53ae75452f8d623eb390fceb4b5a68", + "sim/model.c": "a96f3c6dd7be9ab3a5abbaaf99fa277d4174bb397604ce9c4d643263ffaed781", + "sim/platform_rk3588.c": "a89646c4f61623381d4348fff0052fb7a2bd47eb5dd94c13e6b1e4f67112bfff", + "sim/sim.h": "dd344c137f690920935f5b140075b7bd5cb9b7afb9d58aa60121201c03150ec8", + "src/checkpoint.c": "f320d349c5853c2ddb3676550273875f38cde8e40cb53be7bb5c3da65d23df6b", + "src/checkpoint.h": "bfda811ca6cbbfee8721de836170687b249345a1913c50b5de0c7e8569ee45e8", + "src/contract.c": "1ef5ea601b922c9788e9cf0a91d411c8ce327d27ea2c36f76007c7ea88122a64", + "src/contract.h": "8a4e105d3691513615220538cc83b92f441a916bc5ac8a8db37d403cc2d0de75", + "src/controller.c": "2fb3116ce7d9d73bdc04b7dc0cdfa213b4ff4cd889500f3724b117a1d8087563", + "src/forecast.c": "21265a764056780555e32f03de4f4d2db0a82ed16557ec5e855b1ef7405c815e", + "src/hal_actuate.c": "c1deefb466ab085a4858241a785edb3e2a415363d241a31a1329e7071ff5db93", + "src/hal_discover.c": "c4ffe3b8e42199c23760aa39a039cb2abbc881e98d09d9199e13dcc8f2cc26f5", + "src/hal_fs.c": "c783cb23cd9e372755bd8175029538d7739f154e042190bd6de3e58b53c78761", + "src/hal_sample.c": "fa97c3330044c3df140b317c7b188800be7ab6796a088573340cfbacff64ffc7", + "src/learn.c": "8a5fbfc6c93f48f3e40a7abf1b2259c3b1070cdf58bc3a14079fce6402162d64", + "src/lerwattd.c": "1502d8f4664f7d4768baecce5ad631a4b9d3e4c282878d06e0f4af539229688c", + "src/notify.c": "0207aa96e1a8d9e7c3e7985eab465bcb76fe5fed7bbec88b7d4f047138fbc319", + "src/notify.h": "d5f83fa2bf09c383d60b95dae5aff9cd7a420633d6fd70056e64185641830b06", + "src/predict.c": "3927893b3a848bb0b7f1f240de52b53632b118a94287f58659782e00a2b5bec7", + "src/runtime.h": "d6abadcfa2b80f107c632fd8708009546045c487b4df4d31a4da65663f7d06f3", + "src/temporal.c": "5a73c46bb8c16857ecaaa1c8725ed54bd3a2033f86ff5bb3d1982e77632d3f64", + "tests/check_integration_abi.py": "eb209f6d5d68972c5fdfa436987455f3273f9a36218e1fe0d8ea4e6f9006f60b", + "tests/e2e.sh": "4d6df818d2115599f9cbb64b36d14969c12277fc47f2b8df674ca697781702ff", + "tests/summarize_cooperative.py": "5ce8546144bc92cbf531cef4a6f4bf39100fc6514eaf535a2e5acb1e2da24cff", + "tests/summarize_runtime_forecast.py": "c6b967a11735a21294df66d837525bdf6b7b19c5ed0a43df37635f9fc0e867a6", + "tests/test_checkpoint.c": "3e73f7b862a9a5c1f03f177bc2435b94a2ab0af729bbea594af7cb71c2f39e41", + "tests/test_closed_loop.c": "c9531b8f4bbf26fbe004f2cd0b4dc5b8d7e3e908dd292601d9b5842d1fe37903", + "tests/test_contract.c": "11fc26d35355837b3d68bdd35a75724de9826c6491f12254fe5bdb07478a253b", + "tests/test_control_forecast.c": "9e6d67bba8d19020c31ede5379c3a1358ba9e592fd45ed5a450e74a36875a1fb", + "tests/test_controller.c": "ae7141c015e40bc80234a0fce610fe9804abbb73abe2c4518e31a51f73736c63", + "tests/test_cooperative_loop.c": "31b36e3cdbf0f120a07a5dab597e0be55134b2bfdcf1dd6b0b97ecebc808a1ab", + "tests/test_cooperative_summary.py": "454cac9d844cde5a6b95fbf48eaf937daa9dcaaacb050b7993625b075e920033", + "tests/test_daemon_deployment.py": "1f702645739f9ce226447b159f774959071f25a769675c7080f89484d5990f48", + "tests/test_deploy.sh": "ca1b99717cfe99042e615a12a5a5a36a6d2872713c03bf6a96fb76bf426d897f", + "tests/test_discovery.c": "69ab7d958ffe385a933d768a9827d9ea5c27f6c6365dd56b333d8e958fa74982", + "tests/test_forecast.c": "b1fc49c84cdd73da2b8736e1395064dead7d2b69f5f162ad9b30fcd0c443066a", + "tests/test_forecast_feedback.c": "79c6b3b455f23e4aecbf872eefe7c648bf87c5fe92e09363ab41c4014fe02e09", + "tests/test_learn.c": "ddd490c1951e4d7531e23f98c46b585ee804c1957b38832da69d32a40abcf794", + "tests/test_model.c": "6095171e0de9d5b47d9ae958e4524854f40ed5f9c6826d11250ca31dfac174d8", + "tests/test_notify.c": "3f46f1f849a6021560b435789a2819d1a34cf851a2b9b96c6796c560cb56b180", + "tests/test_predict.c": "c4cff46982f6d5f0b7e5743c1ddefcb1b0039515aac322758869436726fbd80e", + "tests/test_runtime_forecast.py": "a92fef248162a50ed0766354b096a135c18886de7334dd94ea1da82fedea75ca", + "tests/test_runtime_fs.c": "e571d36b4ba303361ddeda4fa6b4e681fa4b69efda7b7694a8b3afe3093a0591", + "tests/test_runtime_summary.py": "4f3fbfe2d0a0b5812de6e6e08d43656d70f273f00a8661773d66a5180fb4fac6", + "tests/test_service_systemd.py": "c3f966f4c7c477e9391e1e49f20bf20a391071921d353b9760def36e5d3b7155", + "tests/test_temporal.c": "d43751dc32f2aedd044e01688df30979cc533e7ffea399e268c361b58f754742", + "tests/verify_nominal_reference.py": "62e0b651841420709b93c738bc57e319485bb39911042f2a5fe0556aa9b247a9", + "tests/verify_runtime_forecast.py": "55dfb4c9d411ece1b122fdb7ff811e5259d9924235ec6b5f62f8e21a3d7b706e" + }, + "lertick-auto-discovery": { + "Makefile": "402b0057d13999b9c913405842f4afad33bf84bf104377ebdfe1b658adbeded1", + "deploy.sh": "9c6c84a193464c0b970cdfbcf9bde78ee97e59500ea79ba86295fd0d3591a5f7", + "docs/INTEGRATION.md": "3c40ef4796400a2d352fd9ec41e072911dd07c6c6bac035f6acac418492fba5d", + "scripts/build_libbpf.sh": "e1c3df3765aadf0d0c3e0e7c5d59a132e71b326741d72799df358d63cab7fe75", + "scripts/collect_report.py": "77a95132e7588e739d244a25d3c4bd2e21ff67c5f3fe8d51b23b984c618c000a", + "scripts/fetch_reference.sh": "73568483432f84dbfe1d73a0e19256229fb92c4539500518b1558338692c31ad", + "scripts/native_build.sh": "6de422e54ed387ddc2bc9253eab0749adeed55b6a981441cc0740e912c54a8b3", + "scripts/preflight.sh": "e4b80a418b3a033300e7d9dd5654ab9a4cb8ba3b61eec05a99cb4ba8c6caaf46", + "scripts/qemu_vm.py": "37d1413f99071f116f6abcbb9766208b0f999569f9720df483f68fc5a8d540cb", + "scripts/service_manager.sh": "3381491e6ff0983408dff79c2ba1fbe042a93d466685a1b560e200e78acb2b42", + "src/README.md": "c3488beec824932044a9e949ff21515e7b5d249c912233fc8fe2e9ea5295a442", + "src/bpf/scx_lertick.bpf.c": "ebd8dd4f7042374239cd0195bc17201d97b648b1bc5a2abe1ae9d4f494f57cfd", + "src/shared/accounting.h": "9abb0b777743d7fa3aef775a693a35030c59748614235d9c0b2c00e196329033", + "src/shared/cpuperf.h": "b48a4c97c5e93aeddc5a08a2e29b56e5805baab52d2f61cb834b6a16c4e9bf35", + "src/shared/lertick.h": "346f35187c607e9d40cb4689a7cb81f68ff5df360c11eb769d0a25544cf89007", + "src/shared/model.h": "9ce54cb889d29d2532c4ea465c728143e2cb44dfd43dd27c32b24d3641a3c639", + "src/userspace/lerwatt_plugin.c": "4c05727eacc86314b9f211fee02f4aff69ba8415c23e17ecb73a40bb2ba93320", + "src/userspace/lerwatt_plugin.h": "44afb720bd73de0f892c6fb4af33e8b4ddd1e8f29a509a0eac27427b77fc2696", + "src/userspace/runtime.c": "2e199ed93fd1a3b3a5de740514b3ffa54134c44943a05b6d1dec99984ae0d672", + "src/userspace/runtime.h": "8cf5589583e1ebfd50a4baff32a01bc773d11a69ea52947c23a30a10c757e655", + "src/userspace/scx_lertick.c": "e35c014b5b88c254138076517e97839404b3be349568dc6a2376d34cd3705287", + "templates/lertick.service.in": "cf3b7809a40bbc8d7171f26aceceb29eaad1b7a8eff515ac3e46a7f113572498", + "tests/README.md": "231c9a0bb03e10482610c7a68a1c6cfd5afe4fbb99cea1621737b0d265214112", + "tests/check_docs.py": "cb991bf25f025d30393c0ccfa4b3b12b5e2b02f319fa55efe515caac0e1071cd", + "tests/check_integration_abi.py": "eb209f6d5d68972c5fdfa436987455f3273f9a36218e1fe0d8ea4e6f9006f60b", + "tests/lifecycle_workload.c": "a9cb9946dd064b3ec5ff97aa821db73d52e817d2956ec0e9f877c3fcc55923d0", + "tests/test_accounting.c": "6b149b1d3cc3038e65368d9c1d7115221252e6481061a9c82d59e4a2e01338bc", + "tests/test_burst_profiles.c": "5629ccd030fae7b95fc19ea77fe6e1db9c32e044e5d3094eb388ceef7efff0c7", + "tests/test_compact_confirmation.py": "a286e5287ac8fbbe9d04517dfe8313deae1aa99641516643062ce3a378f9bbac", + "tests/test_confirmation.py": "d32ad987399ec6e07fd119d5e59d80daf96a7b3ed14d7fa1d186c94ced77a79c", + "tests/test_cpuperf.c": "c580affc977e2149ab30b7990a8397cf7a2a19e8110b654477798b4f0aa40acd", + "tests/test_deploy.sh": "87e55667cdad6b60df954e14fe760ad4810a5844db7ab9b1b4293ff5ab0e15a1", + "tests/test_lerwatt_plugin.c": "7f8b8f83b43085c41314c245579d40fd2e3db57cd130ef780d1c00e147b65e43", + "tests/test_loader_deployment.py": "b010fa9d40d137676d82a6b3bf555b8e77cd8e8c61d0386fcef986f7addf288b", + "tests/test_loader_runtime.c": "1065d4495e2ebf6c98039a0599a1ac063b30bd138461b2565dea80bd94200076", + "tests/test_model.c": "d7f5acc458083757c03fc3eb8cba2f3d8e7a44623a059a82f1f09af2010ae40d", + "tests/test_online_utility.py": "c9676a2fa618910196b3826820860accbc8026abc4544afb1519bf72dd0a99fd", + "tests/test_power_integration.py": "197d6bfa589b825af08282d5c4aef01c390b36b434ce5fc257890264f6b427f8", + "tests/test_report.py": "4464a43a6723e095d05947c258029a7fa89028939a0e85b68b6dec12cab4f801", + "tests/test_service.sh": "6b836cbc8009b7f5642f5aee6871e4eb75d74b60f4cb152a09604d64fa1acd1c", + "tests/test_service_systemd.py": "6854fd0b358a56f5e24d4698496feac409a331c010274f03699891c92495fd49", + "tests/validate_linux.py": "3a7b9fbf94ad417cedfb57f81218bfa0df3ba47ede61380327da6f7d5d84cffc", + "tests/validate_phase2.py": "db695af5508f66e73dca1aee87c617df47675fc53b02acdc715b659b2936f4e2", + "tests/validate_watchdog_flags.py": "3d874d394eee6ae8273285e96546dbc902a937b8bc1371eea3f2c9fd95737797", + "vendor/lerwatt/contract.h": "b19b030600cf7b365e0b182fe3655aab2d5dd6cf8aa6b6c589196251a64b6eed" + } + }, + "sched_ext": "disabled", + "vcpus": 8, + "archive_retained": true, + "recorded_utc": "2026-11-02T17:29:36.558451+00:00", + "fixture_followup_utc": "2026-11-02T17:42:56.173831+00:00", + "fixture_followup": "Only test transaction budget/timeout diagnostics changed after live tests; the matching revision passed the full Linux service fixture." +} diff --git a/results/automatic-discovery/status-fixture-failure.log b/results/automatic-discovery/status-fixture-failure.log new file mode 100644 index 0000000..a5224cd --- /dev/null +++ b/results/automatic-discovery/status-fixture-failure.log @@ -0,0 +1,38 @@ +cc -Ivendor -Isrc -Isrc/shared -Ibuild -I/home/ubuntu/lertick-pr/build/deps/install/include -DLERTICK_VERSION=\"source\" -Isrc/userspace -O2 -g -std=gnu11 -Wall -Wextra src/userspace/scx_lertick.c src/userspace/lerwatt_plugin.c src/userspace/runtime.c -o build/scx_lertick -L/home/ubuntu/lertick-pr/build/deps/install/lib -lbpf -lelf -lzstd -pthread -lz -lelf -lz +In file included from vendor/scx/common.h:74, + from src/userspace/scx_lertick.c:28: +vendor/scx/compat.h: In function ‘__COMPAT_read_enum’: +vendor/scx/compat.h:44:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 44 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +vendor/scx/compat.h:55:31: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 55 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +vendor/scx/compat.h: In function ‘__COMPAT_struct_has_field’: +vendor/scx/compat.h:99:23: warning: comparison of integer expressions of different signedness: ‘int’ and ‘__u32’ {aka ‘unsigned int’} [-Wsign-compare] + 99 | for (i = 0; i < BTF_INFO_VLEN(t->info); i++) { + | ^ +cc -Ivendor -Isrc/shared -Isrc/userspace -O2 -std=gnu11 -Wall -Wextra -Werror tests/test_lerwatt_plugin.c src/userspace/lerwatt_plugin.c -o build/test_lerwatt_plugin +build/test_lerwatt_plugin +{"test":"lerwatt_plugin","status":"passed"} +python3 tests/check_integration_abi.py +Integration ABI 2 golden check passed (56 values). +systemd: installed helper enabled an unlimited validated worker; absent peer reports waiting +systemd: active off/on preserved scheduling and boot intent, and replaced shared maps +systemd: stop/update/rollback preserved enabled-but-stopped intent and private integration setting +systemd: uninstall disabled/detached/removed the validation service; configuration retained +{"result": "passed", "checks": {"install_does_not_start_or_enable": true, "enabled_unlimited_ready_with_optional_peer_absent": true, "active_integration_toggle_restarts_only_owned_service": true, "stop_update_rollback_preserve_configuration_and_intent": true, "uninstall_disables_detaches_removes_and_retains_config": true}, "environment": {"os_release": "PRETTY_NAME=\"Ubuntu 24.04.5 LTS\"\nNAME=\"Ubuntu\"\nVERSION_ID=\"24.04\"\nVERSION=\"24.04.5 LTS (Noble Numbat)\"\nVERSION_CODENAME=noble\nID=ubuntu\nID_LIKE=debian\nHOME_URL=\"https://www.ubuntu.com/\"\nSUPPORT_URL=\"https://help.ubuntu.com/\"\nBUG_REPORT_URL=\"https://bugs.launchpad.net/ubuntu/\"\nPRIVACY_POLICY_URL=\"https://www.ubuntu.com/legal/terms-and-policies/privacy-policy\"\nUBUNTU_CODENAME=noble\nLOGO=ubuntu-logo\n", "architecture": "aarch64", "kernel": "7.0.0-38-generic", "systemd": "systemd 255 (255.4-1ubuntu8.18)", "elapsed_seconds": 4.76}, "scope": "real sched_ext attachment and PID 1 lifecycle in an opted-in VM; no physical power controls or long hardware run"} +integration: Lerwatt-first startup connected; BPF consumed contracts +integration: online-to-EWMA scheduler change reconnected while Lerwatt stayed running +integration: frozen demand expired and resumed without stale control +integration: temporal-to-adaptive predictor change preserved Lertick PID and session +integration: reverse startup order connected +integration artifacts: /var/tmp/lertick-power-integration-p7i4ko5f +Traceback (most recent call last): + File "/home/ubuntu/lertick-auto-discovery/tests/test_power_integration.py", line 343, in + main() + File "/home/ubuntu/lertick-auto-discovery/tests/test_power_integration.py", line 293, in main + wait_for(lambda: link(unit, "off"), "failed auto transport did not report independent operation") + File "/home/ubuntu/lertick-auto-discovery/tests/test_power_integration.py", line 48, in wait_for + raise AssertionError(message) +AssertionError: failed auto transport did not report independent operation diff --git a/scripts/service_manager.sh b/scripts/service_manager.sh index c15d147..73f4e51 100755 --- a/scripts/service_manager.sh +++ b/scripts/service_manager.sh @@ -131,7 +131,7 @@ $report_hash" } integration_read() { - integration_value=off + integration_value=auto trusted_path "$config_dir" [ -e "$config_dir" ] || return 0 [ "$(stat -c '%u %a' "$config_dir")" = '0 700' ] || fail 'integration directory must be root-owned mode 0700' @@ -142,17 +142,17 @@ integration_read() integration_seen=no while IFS= read -r config_line || [ -n "$config_line" ]; do case $config_line in - lerwatt=on|lerwatt=off) + lerwatt=auto|lerwatt=on|lerwatt=off) [ "$integration_seen" = no ] || fail 'duplicate integration setting' integration_value=${config_line#lerwatt=}; integration_seen=yes ;; - *) fail 'invalid integration configuration; expected lerwatt=on or lerwatt=off' ;; + *) fail 'invalid integration configuration; expected lerwatt=auto, lerwatt=on or lerwatt=off' ;; esac done < "$config" [ "$integration_seen" = yes ] || fail 'empty integration configuration' } integration_write() { - case $1 in on|off) ;; *) fail 'invalid integration value' ;; esac + case $1 in auto|on|off) ;; *) fail 'invalid integration value' ;; esac trusted_path "$config_dir"; trusted_path "$config" mkdir -p "$config_dir"; chmod 700 "$config_dir" integration_tmp=$(mktemp "$config_dir/.integration.XXXXXX") @@ -164,6 +164,8 @@ verify_integration() { if [ "$2" = on ]; then "$1" --verify --mode online --track-all --cpuperf auto --summary-only --lerwatt >/dev/null + elif [ "$2" = auto ]; then + "$1" --verify --mode online --track-all --cpuperf auto --summary-only --lerwatt-auto >/dev/null else "$1" --verify --mode online --track-all --cpuperf auto --summary-only >/dev/null fi @@ -179,6 +181,8 @@ if [ "$command" = service-run ]; then [ -n "$current" ] && validate_release "$current" || fail 'installed release validation failed; no scheduler attached' if [ "$integration_value" = on ]; then exec "$release/scx_lertick" --mode online --duration 0 --track-all --cpuperf auto --summary-only --sample-ms 60000 --notify --lerwatt + elif [ "$integration_value" = auto ]; then + exec "$release/scx_lertick" --mode online --duration 0 --track-all --cpuperf auto --summary-only --sample-ms 60000 --notify --lerwatt-auto fi exec "$release/scx_lertick" --mode online --duration 0 --track-all --cpuperf auto --summary-only --sample-ms 60000 --notify fi @@ -281,7 +285,7 @@ case $command in fail 'internal uninstall dispatch failed' ;; integration) require_service - case ${bundle:-status} in on|off|status) ;; *) fail 'integration accepts on, off or status' ;; esac + case ${bundle:-status} in auto|on|off|status) ;; *) fail 'integration accepts auto, on, off or status' ;; esac integration_read if [ "${bundle:-status}" = status ]; then printf 'Lerwatt integration configured: %s\n' "$integration_value"; exit 0; fi old_integration=$integration_value diff --git a/src/bpf/scx_lertick.bpf.c b/src/bpf/scx_lertick.bpf.c index f590e29..adaed16 100644 --- a/src/bpf/scx_lertick.bpf.c +++ b/src/bpf/scx_lertick.bpf.c @@ -46,6 +46,9 @@ const volatile bool model_update_carry; const volatile u32 cpuperf_mode = LERTICK_CPUPERF_MAX; /* Optional Lerwatt plug-in: read lw_contract, keep demand counters. */ const volatile bool lerwatt_enabled; +/* Loader can disable advice after a best-effort publication failure, before + * attach. Keep this writable: rodata is frozen when BPF is loaded. */ +bool lerwatt_runtime_disabled; const volatile u64 lerwatt_session_id; const volatile u64 cluster_topology_id[LW_CONTRACT_MAX_CLUSTERS]; const volatile u32 nr_cpus = 1; @@ -214,7 +217,7 @@ static __always_inline bool contract_get(s32 cpu, u64 now, struct lertick_contra out->price_milli = 0; out->floor_cap = 0; out->ceiling_cap = 0; - if (!lerwatt_enabled || idx >= LERTICK_MAX_CPUS) + if (!lerwatt_enabled || READ_ONCE(lerwatt_runtime_disabled) || idx >= LERTICK_MAX_CPUS) return false; cluster = cpu_cluster[idx]; if (cluster >= LW_CONTRACT_MAX_CLUSTERS) diff --git a/src/userspace/lerwatt_plugin.c b/src/userspace/lerwatt_plugin.c index 5e02ec5..ee6dbad 100644 --- a/src/userspace/lerwatt_plugin.c +++ b/src/userspace/lerwatt_plugin.c @@ -356,8 +356,8 @@ void ltlw_publish(struct lt_demand_rec *slot, const struct lt_demand_rec *val) __atomic_store_n(&slot->seq, seq + 2, __ATOMIC_RELEASE); } -int ltlw_pin_prepare(const char *dir, const char *const *pins, int npins, - char *err, size_t errlen) +static int pin_prepare(const char *dir, const char *const *pins, int npins, + char *err, size_t errlen, bool remove_stale) { char parent[PATH_MAX]; struct statfs fs; @@ -406,7 +406,7 @@ int ltlw_pin_prepare(const char *dir, const char *const *pins, int npins, close(fd); return -1; } - if (fchmod(fd, 0700)) { + if (remove_stale && fchmod(fd, 0700)) { snprintf(err, errlen, "cannot protect BPF pin directory %s: %s", dir, strerror(errno)); close(fd); return -1; @@ -422,6 +422,10 @@ int ltlw_pin_prepare(const char *dir, const char *const *pins, int npins, snprintf(err, errlen, "refusing unexpected stale pin %s", pins[i]); close(fd); return -1; + } else if (!remove_stale) { + snprintf(err, errlen, "automatic discovery keeps existing pin %s unchanged", pins[i]); + close(fd); + return -1; } else if (!unlinkat(fd, name, 0) || errno == ENOENT) { continue; } @@ -435,3 +439,15 @@ int ltlw_pin_prepare(const char *dir, const char *const *pins, int npins, close(fd); return 0; } + +int ltlw_pin_prepare(const char *dir, const char *const *pins, int npins, + char *err, size_t errlen) +{ + return pin_prepare(dir, pins, npins, err, errlen, true); +} + +int ltlw_pin_prepare_auto(const char *dir, const char *const *pins, int npins, + char *err, size_t errlen) +{ + return pin_prepare(dir, pins, npins, err, errlen, false); +} diff --git a/src/userspace/lerwatt_plugin.h b/src/userspace/lerwatt_plugin.h index 78808ed..4d4126f 100644 --- a/src/userspace/lerwatt_plugin.h +++ b/src/userspace/lerwatt_plugin.h @@ -74,5 +74,8 @@ void ltlw_publish(struct lt_demand_rec *slot, const struct lt_demand_rec *val); */ int ltlw_pin_prepare(const char *dir, const char *const *pins, int npins, char *err, size_t errlen); +/* Best-effort discovery never unlinks or changes permissions on existing pins. */ +int ltlw_pin_prepare_auto(const char *dir, const char *const *pins, int npins, + char *err, size_t errlen); #endif /* LERTICK_LERWATT_PLUGIN_H */ diff --git a/src/userspace/scx_lertick.c b/src/userspace/scx_lertick.c index 720c452..eae26ca 100644 --- a/src/userspace/scx_lertick.c +++ b/src/userspace/scx_lertick.c @@ -459,7 +459,8 @@ static void usage(FILE *out, const char *argv0) " --cpuperf auto|util|max CPU frequency requests to schedutil (default auto:\n" " util when a policy uses schedutil or with --lerwatt;\n" " max keeps the kernel default, every CPU at 1024)\n" - " --lerwatt Attach the optional Lerwatt plug-in: pin contract\n" + " --lerwatt-auto Discover optional power advice; failures keep scheduling\n" + " --lerwatt Strict optional Lerwatt plug-in: pin contract\n" " maps under " LW_CONTRACT_PIN_DIR ", publish demand\n" " --fault-stall --stall-tgid PID --partial --dangerous-vm-test --duration SEC\n" " QEMU-only opted-task watchdog injection\n" @@ -530,7 +531,7 @@ int main(int argc, char **argv) /* CPU frequency requests and the optional Lerwatt plug-in. */ const char *cpuperf_arg = "auto", *cpuperf_reason = "explicit"; unsigned cpuperf = LERTICK_CPUPERF_MAX; - bool lerwatt = false, cpu_report; + bool lerwatt = false, lerwatt_auto = false, cpu_report; unsigned pin_mask = 0; bool model_init_ewma = false; bool model_update_carry = false; @@ -543,7 +544,7 @@ int main(int argc, char **argv) int ncpus; enum { OPT_CHECK = 1000, OPT_SAMPLE, OPT_TRACK, OPT_FIXED, OPT_MIN, OPT_MAX, OPT_PARTIAL, OPT_FAULT, OPT_STALL, OPT_DANGER, OPT_EXPECT, OPT_PROFILE, OPT_ALL, - OPT_CPUPERF, OPT_LERWATT, OPT_MODEL_INIT, OPT_MODEL_UPDATE, + OPT_CPUPERF, OPT_LERWATT, OPT_LERWATT_AUTO, OPT_MODEL_INIT, OPT_MODEL_UPDATE, OPT_VERIFY, OPT_MAINTENANCE, OPT_VERSION, OPT_SUMMARY, OPT_FULL_STATS, OPT_NOTIFY }; static const struct option opts[] = { { "mode", required_argument, NULL, 'm' }, { "duration", required_argument, NULL, 'd' }, @@ -563,6 +564,7 @@ int main(int argc, char **argv) { "fault-stall", no_argument, NULL, OPT_FAULT }, { "stall-tgid", required_argument, NULL, OPT_STALL }, { "dangerous-vm-test", no_argument, NULL, OPT_DANGER }, { "expect-watchdog", no_argument, NULL, OPT_EXPECT }, { "cpuperf", required_argument, NULL, OPT_CPUPERF }, { "lerwatt", no_argument, NULL, OPT_LERWATT }, + { "lerwatt-auto", no_argument, NULL, OPT_LERWATT_AUTO }, { "model-init", required_argument, NULL, OPT_MODEL_INIT }, { "model-update", required_argument, NULL, OPT_MODEL_UPDATE }, { NULL, 0, NULL, 0 }, @@ -610,7 +612,8 @@ int main(int argc, char **argv) return 2; } break; - case OPT_LERWATT: lerwatt = true; break; + case OPT_LERWATT: lerwatt = true; lerwatt_auto = false; break; + case OPT_LERWATT_AUTO: lerwatt = true; lerwatt_auto = true; break; case OPT_MODEL_INIT: if (strcmp(optarg, "bias") && strcmp(optarg, "ewma")) { usage(stderr, argv[0]); @@ -707,7 +710,7 @@ int main(int argc, char **argv) cpuperf = LERTICK_CPUPERF_UTIL; } else if (!strcmp(cpuperf_arg, "max")) { cpuperf = LERTICK_CPUPERF_MAX; - } else if (lerwatt) { + } else if (lerwatt && !lerwatt_auto) { cpuperf = LERTICK_CPUPERF_UTIL; cpuperf_reason = "lerwatt"; } else if (ltlw_schedutil_in_use("")) { @@ -719,13 +722,13 @@ int main(int argc, char **argv) cpu_report = cpuperf == LERTICK_CPUPERF_UTIL || lerwatt; if (lerwatt && ltlw_discover(&topo, ncpus, "", NULL)) { fprintf(stderr, "Lerwatt plug-in: cannot discover CPU clusters.\n"); - status = 1; - goto cleanup; + if (!lerwatt_auto) { status = 1; goto cleanup; } + lerwatt = false; } if (lerwatt && new_power_session(&topo.session_id)) { fprintf(stderr, "Lerwatt plug-in: cannot obtain a fresh attachment identity.\n"); - status = 1; - goto cleanup; + if (!lerwatt_auto) { status = 1; goto cleanup; } + lerwatt = false; } if (lerwatt && topo.npolicies > LW_CONTRACT_MAX_CLUSTERS) fprintf(stderr, "Lerwatt plug-in: %d cpufreq policies; CPUs past the first %d have no contract.\n", @@ -833,7 +836,9 @@ int main(int argc, char **argv) cpu_buf = calloc((size_t)ncpus, sizeof(*cpu_buf)); demand_len = (sizeof(struct lt_demand_rec) * LW_CONTRACT_MAX_CLUSTERS + (size_t)page - 1) / (size_t)page * (size_t)page; - ok = cpu_buf && !ltlw_pin_prepare(LW_CONTRACT_PIN_DIR, pins, 2, err, sizeof(err)); + ok = cpu_buf && !(lerwatt_auto ? + ltlw_pin_prepare_auto(LW_CONTRACT_PIN_DIR, pins, 2, err, sizeof(err)) : + ltlw_pin_prepare(LW_CONTRACT_PIN_DIR, pins, 2, err, sizeof(err))); if (ok) { if (bpf_map__pin(skel->maps.lw_contract, LW_CONTRACT_PIN_LW)) { snprintf(err, sizeof(err), "cannot pin contract maps: %s", strerror(errno)); @@ -858,8 +863,14 @@ int main(int argc, char **argv) } if (!ok) { fprintf(stderr, "Lerwatt plug-in: %s\n", err); - status = 1; - goto cleanup; + if (!lerwatt_auto) { status = 1; goto cleanup; } + /* Disable BPF consumption too: even a briefly exposed partial + * mapping must not affect independent scheduling after failure. */ + skel->bss->lerwatt_runtime_disabled = true; + lerwatt_detach(skel, pin_mask, demand_mem, demand_len); + pin_mask = 0; demand_mem = NULL; demand_len = 0; + lerwatt = false; + fprintf(stderr, "Lerwatt auto discovery unavailable; scheduling independently.\n"); } } if (exit_req) diff --git a/tests/test_deploy.sh b/tests/test_deploy.sh index d197daf..a6c55cf 100644 --- a/tests/test_deploy.sh +++ b/tests/test_deploy.sh @@ -134,7 +134,7 @@ with tempfile.TemporaryDirectory(prefix='lertick-deploy-fixtures-') as directory quoted="telemetry a'b.jsonl" result=invoke('plan','--stats-json',quoted) command_line=result.stdout.splitlines()[1] - assert shlex.split(command_line)==['sudo',str(tree/'build/scx_lertick'),'--mode','online','--duration','0','--track-all','--cpuperf','auto','--summary-only','--sample-ms','60000','--stats-json',quoted] + assert shlex.split(command_line)==['sudo',str(tree/'build/scx_lertick'),'--mode','online','--duration','0','--track-all','--cpuperf','auto','--lerwatt-auto','--summary-only','--sample-ms','60000','--stats-json',quoted] assert calls()==[], 'plan invoked build, sudo or loader' for args in [('run','--fault-stall'),('run','--partial'),('run','--cpuperf','max'),('run','--duration','-1'), ('run','--duration','3601'),('run','--sample-ms','99'),('check','--mode','online'),('plan','--mode','invalid')]: @@ -149,8 +149,8 @@ with tempfile.TemporaryDirectory(prefix='lertick-deploy-fixtures-') as directory clear();result=invoke('run') assert '"event"' not in result.stdout attached=[x for x in calls() if x['tool']=='loader' and '--track-all' in x['args']] - assert attached and attached[-1]['args']==['--mode','online','--duration','0','--track-all','--cpuperf','auto','--summary-only','--sample-ms','60000'] - clear();invoke('trial');assert [x for x in calls() if x['tool']=='loader' and '--track-all' in x['args']][-1]['args']==['--mode','online','--duration','30','--track-all','--cpuperf','auto'] + assert attached and attached[-1]['args']==['--mode','online','--duration','0','--track-all','--cpuperf','auto','--lerwatt-auto','--summary-only','--sample-ms','60000'] + clear();invoke('trial');assert [x for x in calls() if x['tool']=='loader' and '--track-all' in x['args']][-1]['args']==['--mode','online','--duration','30','--track-all','--cpuperf','auto','--lerwatt-auto'] result=invoke('run','--stats-json','-');assert '"event":"registered"' in result.stdout invoke('run',extra={'STUB_LEAVE_ENABLED':'1'},ok=False);state.write_text('disabled') for file in [work/'child-started',work/'child-done']:file.unlink(missing_ok=True) diff --git a/tests/test_power_integration.py b/tests/test_power_integration.py index 378d316..92e0e09 100644 --- a/tests/test_power_integration.py +++ b/tests/test_power_integration.py @@ -112,6 +112,9 @@ def main(): simroot = work / "simulated-board" owned_units, owned_processes, streams = [], [], [] lwunit = ltunit = None + foreign_pin = PINS / "lw_contract" + foreign_owned = False + pin_dir_created = False result = {"environment": {"kernel": platform.release(), "architecture": platform.machine(), "os_release": Path("/etc/os-release").read_text(), "systemd": call("systemd", "--version").stdout.splitlines()[0]}, @@ -143,7 +146,7 @@ def start_lerwatt(forecast="temporal"): def start_lertick(mode="online"): assert STATE.read_text().strip() == "disabled", "refusing another scheduler" path = work / f"lertick-{len(owned_units)}.jsonl" - unit = start_unit("lertick", [loader, "--mode", mode, "--track-all", "--lerwatt", + unit = start_unit("lertick", [loader, "--mode", mode, "--track-all", "--lerwatt-auto", "--cpuperf", "util", "--duration", "0", "--notify", "--sample-ms", "100", "--summary-only", "--stats-json", path]) row = wait_for(lambda: next((r for r in records(path) if r.get("event") == "registered"), None), @@ -271,6 +274,36 @@ def restored(): wait_for(lambda: STATE.read_text().strip() == "disabled" and not any(PINS.glob("*")), "final scheduling state or pins were not restored") result["checks"]["final_control_restore_scheduler_fallback_pin_cleanup"] = True + + # Own one deliberately conflicting pin. Auto discovery must preserve it + # and still attach independently, with advice consumption disabled. + pin_dir_created = not PINS.exists() + PINS.mkdir(mode=0o700, exist_ok=True) + call("bpftool", "map", "create", foreign_pin, "type", "array", "key", "4", + "value", "8", "entries", "1", "name", "ltlw_autotest") + foreign_owned = True + foreign_before = call("bpftool", "-j", "map", "show", "pinned", foreign_pin).stdout + path = work / "conflicting-pin.jsonl" + unit = start_unit("lertick-auto-conflict", [loader, "--mode", "online", "--track-all", + "--lerwatt-auto", "--duration", "0", "--notify", + "--sample-ms", "100", "--summary-only", "--stats-json", path]) + row = wait_for(lambda: next((r for r in records(path) if r.get("event") == "registered"), None), + "auto-conflict registration missing") + assert row["lerwatt"] is False + wait_for(lambda: link(unit, "off"), "failed auto transport did not report independent operation") + wait_for(lambda: any(r.get("phase") == "periodic" for r in records(path)), + "independent scheduler did not emit a runtime snapshot") + assert call("bpftool", "-j", "map", "show", "pinned", foreign_pin).stdout == foreign_before + assert applied(path) == 0 + stop_unit(unit) + wait_for(lambda: STATE.read_text().strip() == "disabled", "auto-conflict scheduler did not detach") + foreign_pin.unlink() + foreign_owned = False + if pin_dir_created and PINS.exists(): + PINS.rmdir() + pin_dir_created = False + result["checks"]["foreign_pin_preserved_auto_falls_back_without_advice"] = True + print("integration: conflicting pin preserved; auto mode scheduled independently", flush=True) result["result"] = "passed" (work / "result.json").write_text(json.dumps(result, indent=2) + "\n") print(json.dumps(result), flush=True) @@ -294,6 +327,10 @@ def restored(): process.wait(timeout=5) except (OSError, subprocess.SubprocessError) as error: cleanup_errors.append(str(error)) + if foreign_owned: + foreign_pin.unlink(missing_ok=True) + if pin_dir_created and PINS.exists(): + PINS.rmdir() for stream in streams: stream.close() if args.keep_results or result.get("result") != "passed" or cleanup_errors: diff --git a/tests/test_service.sh b/tests/test_service.sh index 5d0b486..8e175ab 100755 --- a/tests/test_service.sh +++ b/tests/test_service.sh @@ -98,7 +98,12 @@ with tempfile.TemporaryDirectory(prefix='lertick-service-fixtures-') as td: def calls():return [json.loads(x) for x in log.read_text().splitlines()] def clear():log.write_text('') def run(cmd,ok=True,extra=None,bundle=None): - p=subprocess.run([str(tree/'scripts/service_manager.sh'),str(prefix),cmd,str(bundle or tree)],env=dict(env,**(extra or {})),capture_output=True,text=True,timeout=15) + # Transactions launch many trust/hash stub processes. Slow musl/container + # runners need a fixture budget, not the worker's production watchdog budget. + try: + p=subprocess.run([str(tree/'scripts/service_manager.sh'),str(prefix),cmd,str(bundle or tree)],env=dict(env,**(extra or {})),capture_output=True,text=True,timeout=45) + except subprocess.TimeoutExpired as error: + raise AssertionError(('fixture transaction timed out',cmd,calls()[-12:])) from error assert (p.returncode==0)==ok,(cmd,p.returncode,p.stdout,p.stderr) return p def marker(name):return (prefix/'lib/lertick'/name).read_text().strip() @@ -111,11 +116,16 @@ with tempfile.TemporaryDirectory(prefix='lertick-service-fixtures-') as td: for part in ['Type=notify','NotifyAccess=main','Restart=no',str(prefix)+'/libexec/lertick/service_manager.sh '+str(prefix)+' service-run','NoNewPrivileges=yes','LogRateLimitBurst=100']: assert part in unittext,part for file in (prefix/'lib/lertick/releases'/first).iterdir():assert not file.is_symlink() and not(file.stat().st_mode&0o222) - assert config.read_text()=='lerwatt=off\n' and config.stat().st_mode&0o777==0o600 and configdir.stat().st_mode&0o777==0o700 - assert 'configured: off' in integration('status').stdout + assert config.read_text()=='lerwatt=auto\n' and config.stat().st_mode&0o777==0o600 and configdir.stat().st_mode&0o777==0o700 + assert 'configured: auto' in integration('status').stdout # Public installed helper preserves arguments across its normal sudo path. clear();query=subprocess.run([str(prefix/'bin/lertick'),'integration'],env=dict(env,STUB_UID='1000',PREFIX=str(prefix),DESTDIR=''),capture_output=True,text=True,timeout=15) - assert query.returncode==0 and 'configured: off' in query.stdout and any(c['tool']=='sudo' for c in calls()),(query.returncode,query.stdout,query.stderr) + assert query.returncode==0 and 'configured: auto' in query.stdout and any(c['tool']=='sudo' for c in calls()),(query.returncode,query.stdout,query.stderr) + # First enable uses automatic discovery without a separate integration command. + clear();run('enable') + automatic=[c for c in calls() if c['tool']=='loader' and '--notify' in c['args']][-1] + assert '--lerwatt-auto' in automatic['args'] and '--lerwatt' not in automatic['args'] + run('disable');assert config.read_text()=='lerwatt=auto\n' # A stopped service stays stopped; on/off is exact data and never a sourced script. clear();integration('on');assert config.read_text()=='lerwatt=on\n' and not json.loads(service.read_text())['active'] assert not any(c['tool']=='systemctl' and c['args'][0] in ['start','stop','enable','restart'] for c in calls()) diff --git a/tests/test_service_systemd.py b/tests/test_service_systemd.py index 358607a..9a61523 100644 --- a/tests/test_service_systemd.py +++ b/tests/test_service_systemd.py @@ -148,16 +148,15 @@ def map_ids(): assert property_value("ActiveState") == "inactive" assert call("systemctl", "is-enabled", unit, check=False).stdout.strip() == "disabled" require_default() - assert config.read_text() == "lerwatt=off\n" + assert config.read_text() == "lerwatt=auto\n" result["install_does_not_start_or_enable"] = True - call(installed_helper, "integration", "on", env=environment) - assert config.read_text() == "lerwatt=on\n" and property_value("ActiveState") == "inactive" + assert property_value("ActiveState") == "inactive" require_default() call(installed_helper, "enable", env=environment) first_pid = wait_for(ready, "enabled integration service did not become ready/waiting") command = command_line(first_pid) - assert command[command.index(b"--duration") + 1] == b"0" and b"--lerwatt" in command + assert command[command.index(b"--duration") + 1] == b"0" and b"--lerwatt-auto" in command assert "/lib/lertick/releases/" in os.readlink(f"/proc/{first_pid}/exe") assert STATE.read_text().strip() == "enabled" assert call("systemctl", "is-enabled", unit).stdout.strip() == "enabled"