> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kguardian.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Compute

> Every compute.* Helm value, the env vars it renders, the broker endpoints, and the finding JSON

Reference for the [compute contention](/concepts/compute-contention)
feature. Operational steps are in the [guide](/guides/compute-gauges).

## Helm values

| Key                                     | Type  | Default | Description                                                                                                                                                                                                       |
| --------------------------------------- | ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `compute.enabled`                       | bool  | `true`  | Master switch. Mounts `/sys/fs/cgroup` read-only into the controller and starts the sampler. `false` removes the mount, the sampler and every controller-side `COMPUTE_*` env.                                    |
| `compute.sampleInterval`                | int   | `5`     | Seconds between cgroup samples. Drives the live gauges; history is always folded per minute.                                                                                                                      |
| `compute.contention.enabled`            | bool  | `false` | Load the `sched_contention` eBPF probe. Requires `compute.enabled`. Without it there is no run-queue histogram, no blame list and no `noisy-neighbor` finding.                                                    |
| `compute.contention.minRunqLatencyUs`   | int   | `100`   | In-kernel filter: run-queue waits shorter than this many microseconds are dropped before any map write.                                                                                                           |
| `compute.thresholds.stallSome`          | int   | `20`    | `cpu.pressure some avg10` (percent) at or above which a victim counts as stalled, for two consecutive minutes.                                                                                                    |
| `compute.thresholds.runqP99Ms`          | int   | `20`    | Run-queue p99 (ms) at or above which a victim counts as stalled. Only meaningful with the probe.                                                                                                                  |
| `compute.thresholds.throttledRatio`     | float | `0.25`  | Throttled time ÷ quota time over the window at or above which `cpu-throttled` fires.                                                                                                                              |
| `compute.thresholds.throttledRatioMax`  | float | `0.10`  | Hard gate: above this ratio a container is never a `noisy-neighbor` victim.                                                                                                                                       |
| `compute.thresholds.blameShare`         | float | `0.40`  | Share of the victim's wait time one cgroup must hold to be named the culprit.                                                                                                                                     |
| `compute.thresholds.memStallSome`       | int   | `10`    | `memory.pressure some avg10` (percent) at or above which `memory-pressure` can fire (while the node is also under pressure).                                                                                      |
| `compute.thresholds.refaultPerMin`      | int   | `1000`  | Workingset refaults per minute at or above which a container counts as thrashing for `memory-pressure` (the alternative to `memStallSome`; the node must also be under pressure).                                 |
| `compute.thresholds.minRunqEvents`      | int   | `50`    | Run-queue events per minute a history row must carry before its p99 counts as a CPU stall. Filters p99-only findings on near-idle sidecars; the histogram overflow bucket (multi-second waits) is never filtered. |
| `compute.history.retentionDays`         | int   | `7`     | Days of history kept. `0` disables history inserts and pruning **and every compute finding** (they are computed from history); only the live gauges remain.                                                       |
| `compute.history.minuteResolutionHours` | int   | `24`    | Hours kept at one-minute resolution before rows are folded into 5-minute rows.                                                                                                                                    |

Thresholds are evaluated by the broker, so a change takes effect on the next
findings poll without a controller restart.

## Environment variables

Rendered by the chart; listed here for operators who run the binaries
another way.

**Controller** (`kguardian-controller` DaemonSet)

| Env                            | From                                  | Default          |
| ------------------------------ | ------------------------------------- | ---------------- |
| `COMPUTE_ENABLED`              | `compute.enabled`                     | `true`           |
| `COMPUTE_SAMPLE_INTERVAL_SECS` | `compute.sampleInterval`              | `5`              |
| `COMPUTE_CONTENTION_ENABLED`   | `compute.contention.enabled`          | `false`          |
| `COMPUTE_MIN_RUNQ_LATENCY_US`  | `compute.contention.minRunqLatencyUs` | `100`            |
| `COMPUTE_CGROUP_ROOT`          | fixed                                 | `/sys/fs/cgroup` |
| `COMPUTE_HOST_PROC`            | fixed                                 | `/proc`          |

When `compute.enabled` is false the chart renders only `COMPUTE_ENABLED=false`
and no `/sys/fs/cgroup` mount.

**Broker** (`kguardian-broker` Deployment) — rendered regardless of
`compute.enabled`, so a cluster that turns the feature off still prunes what
it collected.

| Env                                     | From                                    | Default |
| --------------------------------------- | --------------------------------------- | ------- |
| `COMPUTE_HISTORY_RETENTION_DAYS`        | `compute.history.retentionDays`         | `7`     |
| `COMPUTE_HISTORY_MINUTE_HOURS`          | `compute.history.minuteResolutionHours` | `24`    |
| `COMPUTE_RETENTION_INTERVAL_SECS`       | fixed                                   | `600`   |
| `COMPUTE_THRESHOLD_STALL_SOME`          | `compute.thresholds.stallSome`          | `20`    |
| `COMPUTE_THRESHOLD_RUNQ_P99_MS`         | `compute.thresholds.runqP99Ms`          | `20`    |
| `COMPUTE_THRESHOLD_THROTTLED_RATIO`     | `compute.thresholds.throttledRatio`     | `0.25`  |
| `COMPUTE_THRESHOLD_THROTTLED_RATIO_MAX` | `compute.thresholds.throttledRatioMax`  | `0.10`  |
| `COMPUTE_THRESHOLD_BLAME_SHARE`         | `compute.thresholds.blameShare`         | `0.40`  |
| `COMPUTE_THRESHOLD_MEM_STALL_SOME`      | `compute.thresholds.memStallSome`       | `10`    |
| `COMPUTE_THRESHOLD_REFAULT_PER_MIN`     | `compute.thresholds.refaultPerMin`      | `1000`  |
| `COMPUTE_THRESHOLD_MIN_RUNQ_EVENTS`     | `compute.thresholds.minRunqEvents`      | `50`    |

## Pod annotation

| Annotation                     | Effect                                                                                                                                |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `kguardian.dev/compute: "off"` | The pod is not sampled and is not registered with the scheduler probe as a victim. It can still be named as a culprit for other pods. |

## Broker endpoints

All read endpoints return JSON and are metered by the broker's read budget.
The two `POST`s are for the controller. When `broker.auth.enabled` is set,
every broker endpoint — these included — requires the bearer token; the
auth middleware is global, not per route.

| Endpoint                                                       | Returns                                                                                                                                                                                                   |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /compute/latest?namespace=<ns>`                           | `{ "containers": [...], "nodes": [...] }` — one row per live container in the namespace (blame inline) and the node rows for the nodes hosting them. `namespace` is required.                             |
| `GET /compute/history/{pod_uid}?minutes=60`                    | `{ "rows": [...] }` — history rows for the pod, oldest first, at whatever resolution the window has. `minutes` is capped at 10080.                                                                        |
| `GET /compute/contention?namespace=<ns>&node=<node>&minutes=5` | `{ "pairs": [...] }` — victim→culprit pairs. One of `namespace` / `node` is required. Up to 50 pairs per victim.                                                                                          |
| `GET /compute/findings?namespace=<ns>&node=<node>`             | `{ "findings": [Finding], "truncated": bool, "victims_evaluated": int, "history_disabled": bool }` — see [findings response](#findings-response). Both filters optional; neither means the whole cluster. |
| `GET /compute/nodes`                                           | `{ "nodes": [...] }` — every node's latest sample: pressure, context-switch rate, capacity, BPF map occupancy, and the `compute_enabled` / `compute_supported` / `contention_loaded` flags.               |
| `POST /pod/compute/batch`                                      | Controller → broker, every sample interval.                                                                                                                                                               |
| `POST /pod/compute/history/batch`                              | Controller → broker, every 60 s.                                                                                                                                                                          |

## Finding

```json theme={null}
{
  "kind": "noisy-neighbor",
  "severity": "high",
  "victim": {
    "pod_uid": "3f1c…",
    "namespace": "payments",
    "pod_name": "api-7c9d8f6b5-x2k4q",
    "container": "api",
    "container_uid": "3f1c…/api",
    "node": "worker-3"
  },
  "culprit": {
    "kind": "pod",
    "ref": "batch/etl-1-x/worker",
    "pod_uid": "9a02…",
    "namespace": "batch",
    "pod_name": "etl-1-x",
    "container_uid": "9a02…/worker",
    "blame_share": 0.71,
    "cpu_usage_millis": 1900.0,
    "cpu_request_millis": 500
  },
  "evidence": {
    "window_minutes": 5,
    "cpu_psi_some10_max": 31.0,
    "cpu_psi_full10_max": 4.2,
    "runq_p99_us_max": 48000,
    "throttled_ratio": 0.02,
    "mem_psi_some10_max": 0.0,
    "node_mem_some10_max": 0.0,
    "refault_delta": 0,
    "mem_events_high_delta": 0
  },
  "first_seen": "2026-09-10T02:36:00Z",
  "last_seen": "2026-09-10T02:41:00Z",
  "message": "payments/api is starved for CPU by batch/etl-1-x (71% of its wait); etl-1-x is using 1.9 cores against a 0.5-core request."
}
```

| Field                      | Notes                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `kind`                     | `noisy-neighbor`, `cpu-throttled`, `cpu-contended`, `memory-pressure`, `memory-limit-thrash`. What each means and its remediation: [finding kinds](/concepts/compute-contention#finding-kinds).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `severity`                 | `critical`, `high`, `medium`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `victim`                   | The stalled container. `container_uid` is `<pod_uid>/<container>`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `culprit`                  | `null` for `cpu-throttled`, `cpu-contended` and `memory-limit-thrash`. `kind` is `pod`, `system` or `kernel`; the `pod_*` fields are `null` unless `kind` is `pod`. `blame_share` is the culprit's share of the victim's scheduler wait time over the window for `noisy-neighbor`; for `memory-pressure` it is the culprit's share of the **node's memory overage** (usage beyond requests), not a wait share. `cpu_usage_millis` and `cpu_request_millis` are the numbers behind "running beyond its request"; `cpu_request_millis` is `null` when the culprit has none, and `cpu_usage_millis` is `null` when the culprit is opted out (`kguardian.dev/compute: "off"`) and therefore not sampled. |
| `evidence`                 | The values that fired the rule, as maxima over the window. `runq_p99_us_max` is `null` when the probe is not loaded.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `first_seen` / `last_seen` | RFC 3339 UTC.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `message`                  | One sentence, safe to show verbatim.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |

## Findings response

```json theme={null}
{ "findings": [ … ], "truncated": false, "victims_evaluated": 412, "history_disabled": false }
```

| Field               | Notes                                                                                                                                                           |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `findings`          | Array of [Finding](#finding).                                                                                                                                   |
| `truncated`         | `true` when the request hit the per-call victim cap and some containers in scope were not evaluated. Narrow the scope with `namespace` or `node`.               |
| `victims_evaluated` | Number of containers the rule engine actually evaluated for this call.                                                                                          |
| `history_disabled`  | `true` when `compute.history.retentionDays` is `0`. Findings are computed from history, so this response can never contain any; the live gauges are unaffected. |

## History row

`GET /compute/history/{pod_uid}` rows carry `resolution_secs` (60 or 300);
gauges are stored as `_avg` / `_max` / `_last` columns (`cpu_usage_millis`,
`mem_current`, `mem_working_set`, `cpu_psi_some10`, `cpu_psi_full10`,
`mem_psi_some10`, `mem_psi_full10`), counters (`cpu_nr_periods`,
`cpu_nr_throttled`, `cpu_throttled_usec`, `mem_events_high`,
`mem_events_max`, `mem_oom_kill`, `mem_refault`, `mem_pgmajfault`,
`runq_count`) are sums over the row's interval, and `runq_hist` is the
24-bucket log2 latency histogram (bucket *b* is `[2^b, 2^(b+1))` µs; bucket
23 is overflow and is never reported as a finite maximum).
