Branch prediction and speculation
Contract
| Field |
Bound contract |
| Trigger |
Branchy hot code underperforms, a likely or branchless refactor needs judgment, a kernel mitigation such as retpoline or KPTI needs explaining, or code branches on secret data. |
| Authority |
Read-only. The skill runs perf stat on a user-named binary, reads sysfs, and answers in chat. Nothing on disk changes, so there is nothing to roll back. No remote mutation. |
| Side effect |
Chat output only. perf stat writes counters to stdout. |
| Done |
The answer names the branch that mispredicts or the speculation path that leaks, gives a measured branch-misses count where a binary exists, and states the fix with the condition under which it helps. |
Inputs
- Code or hot loop (required): the source or disassembly around the branch in question.
- Binary and workload (optional): needed for a measured verdict. Without them the answer is a hypothesis.
- Threat model (optional): whether the question is performance only or also side-channel safety.
Procedure
- Explain the mechanism in one pass. The front end predicts a direction for each conditional branch, executes the predicted path, and on resolve either commits or squashes the wrong-path work and refetches from the correct address. The squash cost grows with the distance from fetch to resolve, so a deeper pipeline pays more per mispredict. Backward branches are usually loop closers and predict taken; a data-dependent forward branch with no pattern is the hard case. Done when: the user can say why a given branch is predictable or not.
- Measure before changing code. Done when: a
branch-misses count and its ratio to branches for the real workload is recorded, or no binary exists and the answer is marked as unmeasured.
perf stat -e branches,branch-misses ./app
Read the ratio against the workload, not against a fixed number: a tight loop over sorted data should show a ratio near zero, while a parser over random input can sit far higher and still be at its floor. Only a ratio that drops after a change proves the change.
- Pick the remedy for a mispredicting branch. Done when: one remedy is chosen and the condition under which it wins is stated.
- Sort or partition the data so the branch becomes a run of one direction.
- Replace the branch with a select.
int m = a < b ? a : b; may lower to cmov. The select executes both operands every time, so it wins only when the branch mispredicts often; on a predictable branch it loses.
- Split hot and cold paths so the rare path leaves the hot cache line.
- Peel the loop exit or handle the tail without a branch when the exit mispredicts.
- Apply compiler hints last.
__builtin_expect(!!(x), 1) and __builtin_expect(!!(x), 0) steer code layout, not the dynamic predictor. On a current out-of-order core the predictor already learns most static patterns, so the hint helps layout of the cold path and little else. Measure after adding one. Done when: the hint is kept only with a measured win.
- Cover the security side when the branch touches secrets. Speculation past a bounds check can load secret-dependent memory and leave its address in cache state (Spectre variant 1). Meltdown let a user load read a kernel mapping before the fault retired; KPTI separates the page tables. Done when: the applicable mitigation layer is named.
- Kernel: read the state from
/sys/devices/system/cpu/vulnerabilities/ (one file per issue, such as spectre_v1, spectre_v2, meltdown, l1tf). Retpoline, IBRS, IBPB, and STIBP appear in the spectre_v2 text. A host booted with mitigations=off reports Vulnerable here.
- Compiler: Clang's
-mspeculative-load-hardening masks pointers on the speculative path.
- Code: constant-time algorithms with no secret-dependent branch or index. This is the only layer that protects a secret from a same-process timing channel.
For the pipeline model behind the penalty, use cpu-pipelines-and-hazards. For cache timing channels, use cpu-cache-opt. For the kernel mitigation set (KPTI, CET), use kernel-security.
Failure and recovery
| Failure class |
Behavior |
| No binary or workload |
Deliver the mechanism and the candidate fixes as hypotheses. Mark the answer unmeasured. |
perf stat denied |
Report the perf_event_paranoid value the tool prints and the capability it needs. Do not change the sysctl. |
| Hint shows no gain |
The predictor already handled the branch. Remove the hint and profile for the real bottleneck. |
| Branchless version slower |
The branch was predictable and the select now executes both operands. Revert and benchmark on the target CPU. |
| Mitigation regresses throughput |
Name the mitigation and its cost. Isolating the secret-handling code is the alternative; do not recommend disabling mitigations. |
Output
A chat answer that names the mechanism, the measured branch-misses figure when a binary exists, one chosen remedy with its winning condition, and the mitigation layer that applies when secrets are involved.
1---2name: branch-prediction-and-speculation3description: Use when explaining branch predictors, mispredict penalties, speculative execution, Spectre or Meltdown mitigations, or branchless code. Not for pipeline stage theory: use cpu-pipelines-and-hazards.4---56# Branch prediction and speculation78## Contract910| Field | Bound contract |11|---|---|12| Trigger | Branchy hot code underperforms, a `likely` or branchless refactor needs judgment, a kernel mitigation such as retpoline or KPTI needs explaining, or code branches on secret data. |13| Authority | Read-only. The skill runs `perf stat` on a user-named binary, reads sysfs, and answers in chat. Nothing on disk changes, so there is nothing to roll back. No remote mutation. |14| Side effect | Chat output only. `perf stat` writes counters to stdout. |15| Done | The answer names the branch that mispredicts or the speculation path that leaks, gives a measured `branch-misses` count where a binary exists, and states the fix with the condition under which it helps. |1617## Inputs1819- Code or hot loop (required): the source or disassembly around the branch in question.20- Binary and workload (optional): needed for a measured verdict. Without them the answer is a hypothesis.21- Threat model (optional): whether the question is performance only or also side-channel safety.2223## Procedure24251. Explain the mechanism in one pass. The front end predicts a direction for each conditional branch, executes the predicted path, and on resolve either commits or squashes the wrong-path work and refetches from the correct address. The squash cost grows with the distance from fetch to resolve, so a deeper pipeline pays more per mispredict. Backward branches are usually loop closers and predict taken; a data-dependent forward branch with no pattern is the hard case. Done when: the user can say why a given branch is predictable or not.262. Measure before changing code. Done when: a `branch-misses` count and its ratio to `branches` for the real workload is recorded, or no binary exists and the answer is marked as unmeasured.2728```bash29perf stat -e branches,branch-misses ./app30```3132Read the ratio against the workload, not against a fixed number: a tight loop over sorted data should show a ratio near zero, while a parser over random input can sit far higher and still be at its floor. Only a ratio that drops after a change proves the change.33343. Pick the remedy for a mispredicting branch. Done when: one remedy is chosen and the condition under which it wins is stated.35 - Sort or partition the data so the branch becomes a run of one direction.36 - Replace the branch with a select. `int m = a < b ? a : b;` may lower to `cmov`. The select executes both operands every time, so it wins only when the branch mispredicts often; on a predictable branch it loses.37 - Split hot and cold paths so the rare path leaves the hot cache line.38 - Peel the loop exit or handle the tail without a branch when the exit mispredicts.394. Apply compiler hints last. `__builtin_expect(!!(x), 1)` and `__builtin_expect(!!(x), 0)` steer code layout, not the dynamic predictor. On a current out-of-order core the predictor already learns most static patterns, so the hint helps layout of the cold path and little else. Measure after adding one. Done when: the hint is kept only with a measured win.405. Cover the security side when the branch touches secrets. Speculation past a bounds check can load secret-dependent memory and leave its address in cache state (Spectre variant 1). Meltdown let a user load read a kernel mapping before the fault retired; KPTI separates the page tables. Done when: the applicable mitigation layer is named.41 - Kernel: read the state from `/sys/devices/system/cpu/vulnerabilities/` (one file per issue, such as `spectre_v1`, `spectre_v2`, `meltdown`, `l1tf`). Retpoline, IBRS, IBPB, and STIBP appear in the `spectre_v2` text. A host booted with `mitigations=off` reports `Vulnerable` here.42 - Compiler: Clang's `-mspeculative-load-hardening` masks pointers on the speculative path.43 - Code: constant-time algorithms with no secret-dependent branch or index. This is the only layer that protects a secret from a same-process timing channel.4445For the pipeline model behind the penalty, use `cpu-pipelines-and-hazards`. For cache timing channels, use `cpu-cache-opt`. For the kernel mitigation set (KPTI, CET), use `kernel-security`.4647## Failure and recovery4849| Failure class | Behavior |50|---|---|51| No binary or workload | Deliver the mechanism and the candidate fixes as hypotheses. Mark the answer unmeasured. |52| `perf stat` denied | Report the `perf_event_paranoid` value the tool prints and the capability it needs. Do not change the sysctl. |53| Hint shows no gain | The predictor already handled the branch. Remove the hint and profile for the real bottleneck. |54| Branchless version slower | The branch was predictable and the select now executes both operands. Revert and benchmark on the target CPU. |55| Mitigation regresses throughput | Name the mitigation and its cost. Isolating the secret-handling code is the alternative; do not recommend disabling mitigations. |5657## Output5859A chat answer that names the mechanism, the measured `branch-misses` figure when a binary exists, one chosen remedy with its winning condition, and the mitigation layer that applies when secrets are involved.