CPU sizing advice asks "did the load queue" and "how busy" separately, its thresholds tested at their boundaries (v1.34.10) #113

Merged
mi merged 2 commits from mihoe/capacity-sizing-cpu into main 2026-10-04 19:11:52 +02:00
Owner

The Problem

After PR#112 CapacitySizing.cpu had the highest Mutation-CRAP score of Werkator: 33.17 at a complexity of 12 and a mutation score of 0.47.
Unlike the two before it, it failed mostly on its tests: three tests reached it, and none asked for its boundaries.
Whether the load queued in exactly 5 % of the quarter hours, whether a peak of exactly 40 % lets a thread go, whether a sustained 80 % is tight — a changed comparison passed every test.
The tight verdict had no test at all.

Its complexity of 12 was also two questions in one body, asked one after the other:
did the load queue for the threads, and if not, how busy were they.

Non-Goals

  • No change in the advice: the thresholds, the sizes, and the reasons stay as they are.

The Scenarios

Feature: CPU sizing advice

Scenario#113.01: Without threads or without any CPU history nothing is advised

So that a machine whose CPU was never sampled is not told to shrink.

  • Given a snapshot with no threads, or a history without the load1 and cpuUsed columns
  • When the advice is computed
  • Then the CPU verdict is unknown, with the reason no CPU history
Verified by

Scenario#113.02: A load queuing in exactly 5 % of the quarter hours, or only reaching the threads, buys no thread

So that the waiting share is a limit to exceed, not to reach.

  • Given two threads, and a load above them in exactly 48 of 960 quarter hours, or a load of exactly 2.0 throughout
  • When the advice is computed
  • Then the CPU fits
Verified by

Scenario#113.03: An upgrade is sized to the load the quarter hours sustain

So that the advice names the size that stops the queue, not merely one thread more.

  • Given two threads, and a load of 5.2 in 10 % of the quarter hours
  • When the advice is computed
  • Then the CPU is an upgrade to 6 threads, with the busiest use as its peak
Verified by

Scenario#113.04: Threads go only when the peak stays below 40 % and a smaller size still holds it

So that a downsize is never advised at the boundary, and never to the size already booked.

  • Given four threads with a peak of 1.5, four threads with a peak of 1.6, and two threads with a peak of 0.75
  • When the advice is computed
  • Then the first is a downsize to 2 with its reason, the second fits, the third is a downsize to 1
Verified by

Scenario#113.05: A CPU that sustains 80 % of its threads is tight

So that the watch band starts at 80 %, and its advice holds the sustained use with headroom.

  • Given two threads sustaining 1.6, 1.59, and 4.0
  • When the advice is computed
  • Then 1.6 is tight with 3 threads advised, 1.59 fits, and 4.0 asks for 5
Verified by

Scenario#113.06: One CPU column alone is enough to advise

So that a history that lost one column still gets advice from the other.

  • Given a history with only load1, and one with only cpuUsed
  • When the advice is computed
  • Then the first is judged with a peak of zero, the second without a waiting share
Verified by

The Solution

cpu asks its two questions in two methods:

Method Question
cpuWaited did the load exceed the threads in more than 5 % of the quarter hours? An upgrade, else nothing
cpuBusy with nothing queued, how busy were the threads? A downsize, tight, or fits

CpuUsage carries what both need: the threads, the use per quarter hour, its peak, and the days of the basis.
cpu itself keeps the guard for a missing history.

Measured with PIT as the nightly build runs it:

Method Before After
CapacitySizing.cpu 33.17 6
CapacitySizing.cpuBusy — 5.01
CapacitySizing.cpuWaited — 4.30

cpu itself kills 8 of 8 mutants now, and none of the three is INCONCLUSIVE.

The gate maxMutationCrap falls from 34 to 32: the highest score left is ForgejoWorkflowExporter.settingNotes at 31.63.

Additional Changes

  • Version 1.34.10 with its release note.

Follow-up PRs

  • ForgejoWorkflowExporter.settingNotes (31.63), SystemHealth.assess$diskUtilization (31.28), GitService.authenticated (30.12), SystemMetricsView.from (29.92), and CapacitySizing.ram/column/disk (26.87, 26.83, 21.19).

🤖 Generated with Claude Code

## The Problem After PR#112 `CapacitySizing.cpu` had the highest Mutation-CRAP score of Werkator: 33.17 at a complexity of 12 and a mutation score of 0.47. Unlike the two before it, it failed mostly on its tests: three tests reached it, and none asked for its boundaries. Whether the load queued in exactly 5 % of the quarter hours, whether a peak of exactly 40 % lets a thread go, whether a sustained 80 % is tight — a changed comparison passed every test. The tight verdict had no test at all. Its complexity of 12 was also two questions in one body, asked one after the other: did the load queue for the threads, and if not, how busy were they. ## Non-Goals - No change in the advice: the thresholds, the sizes, and the reasons stay as they are. ## The Scenarios ### Feature: CPU sizing advice #### Scenario#113.01: Without threads or without any CPU history nothing is advised So that a machine whose CPU was never sampled is not told to shrink. - **Given** a snapshot with no threads, or a history without the `load1` and `cpuUsed` columns - **When** the advice is computed - **Then** the CPU verdict is `unknown`, with the reason `no CPU history` ##### Verified by - [CapacitySizingUnitTest](../../src/test/kotlin/de/hoennig/werkator/metrics/CapacitySizingUnitTest.kt) — Scenario#113.01 #### Scenario#113.02: A load queuing in exactly 5 % of the quarter hours, or only reaching the threads, buys no thread So that the waiting share is a limit to exceed, not to reach. - **Given** two threads, and a load above them in exactly 48 of 960 quarter hours, or a load of exactly 2.0 throughout - **When** the advice is computed - **Then** the CPU fits ##### Verified by - [CapacitySizingUnitTest](../../src/test/kotlin/de/hoennig/werkator/metrics/CapacitySizingUnitTest.kt) — Scenario#113.02 #### Scenario#113.03: An upgrade is sized to the load the quarter hours sustain So that the advice names the size that stops the queue, not merely one thread more. - **Given** two threads, and a load of 5.2 in 10 % of the quarter hours - **When** the advice is computed - **Then** the CPU is an upgrade to 6 threads, with the busiest use as its peak ##### Verified by - [CapacitySizingUnitTest](../../src/test/kotlin/de/hoennig/werkator/metrics/CapacitySizingUnitTest.kt) — Scenario#113.03 #### Scenario#113.04: Threads go only when the peak stays below 40 % and a smaller size still holds it So that a downsize is never advised at the boundary, and never to the size already booked. - **Given** four threads with a peak of 1.5, four threads with a peak of 1.6, and two threads with a peak of 0.75 - **When** the advice is computed - **Then** the first is a downsize to 2 with its reason, the second fits, the third is a downsize to 1 ##### Verified by - [CapacitySizingUnitTest](../../src/test/kotlin/de/hoennig/werkator/metrics/CapacitySizingUnitTest.kt) — Scenario#113.04 #### Scenario#113.05: A CPU that sustains 80 % of its threads is tight So that the watch band starts at 80 %, and its advice holds the sustained use with headroom. - **Given** two threads sustaining 1.6, 1.59, and 4.0 - **When** the advice is computed - **Then** 1.6 is tight with 3 threads advised, 1.59 fits, and 4.0 asks for 5 ##### Verified by - [CapacitySizingUnitTest](../../src/test/kotlin/de/hoennig/werkator/metrics/CapacitySizingUnitTest.kt) — Scenario#113.05 #### Scenario#113.06: One CPU column alone is enough to advise So that a history that lost one column still gets advice from the other. - **Given** a history with only `load1`, and one with only `cpuUsed` - **When** the advice is computed - **Then** the first is judged with a peak of zero, the second without a waiting share ##### Verified by - [CapacitySizingUnitTest](../../src/test/kotlin/de/hoennig/werkator/metrics/CapacitySizingUnitTest.kt) — Scenario#113.06 ## The Solution `cpu` asks its two questions in two methods: | Method | Question | | ----------- | ----------------------------------------------------------------------------------------------- | | `cpuWaited` | did the load exceed the threads in more than 5 % of the quarter hours? An upgrade, else nothing | | `cpuBusy` | with nothing queued, how busy were the threads? A downsize, tight, or fits | `CpuUsage` carries what both need: the threads, the use per quarter hour, its peak, and the days of the basis. `cpu` itself keeps the guard for a missing history. Measured with PIT as the nightly build runs it: | Method | Before | After | | -------------------------- | ------ | ----- | | `CapacitySizing.cpu` | 33.17 | 6 | | `CapacitySizing.cpuBusy` | — | 5.01 | | `CapacitySizing.cpuWaited` | — | 4.30 | `cpu` itself kills 8 of 8 mutants now, and none of the three is `INCONCLUSIVE`. The gate `maxMutationCrap` falls from 34 to 32: the highest score left is `ForgejoWorkflowExporter.settingNotes` at 31.63. ## Additional Changes - Version 1.34.10 with its release note. ## Follow-up PRs - `ForgejoWorkflowExporter.settingNotes` (31.63), `SystemHealth.assess$diskUtilization` (31.28), `GitService.authenticated` (30.12), `SystemMetricsView.from` (29.92), and `CapacitySizing.ram`/`column`/`disk` (26.87, 26.83, 21.19). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mi added 1 commit 2026-10-04 18:51:57 +02:00
WIP: CPU sizing advice (PR-doc skeleton)
werkator build succeeded after 01:59
9c37824f5f
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mi added 1 commit 2026-10-04 19:06:14 +02:00
CapacitySizing.cpu had Mutation-CRAP 33.17 (complexity 12, mutation score
0.47): its boundaries and the tight verdict were untested.

- cpuWaited: an upgrade when the load exceeded the threads in more than
  5 % of the quarter hours; cpuBusy: downsize, tight or fits otherwise.
- CpuUsage carries threads, use, peak and days for both.
- Scenario#113.01-06 test the boundaries; cpu 6, cpuBusy 5.01,
  cpuWaited 4.30. Gate 34 -> 32.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mi changed title from WIP: CPU sizing advice tested and split (v1.34.10) to CPU sizing advice asks "did the load queue" and "how busy" separately, its thresholds tested at their boundaries (v1.34.10) 2026-10-04 19:06:14 +02:00
mi merged commit f2f23780a2 into main 2026-10-04 19:11:52 +02:00
mi deleted branch mihoe/capacity-sizing-cpu 2026-10-04 19:11:52 +02:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mi/werkator#113