Skip to content

mem: add vtage value predictor#943

Open
happy-lx wants to merge 1 commit into
xs-devfrom
lvp-vtage
Open

mem: add vtage value predictor#943
happy-lx wants to merge 1 commit into
xs-devfrom
lvp-vtage

Conversation

@happy-lx

@happy-lx happy-lx commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

The idea of ​​using VTAGE (or E-VTAGE) for value prediction was first proposed in the 1st-place Championship Value Prediction (CVP-1) submission.

VTAGE implementation in this PR is adapted from the CVP1 Open-source implementation and modified for our environment. It is not intended to be a bit-exact copy of the original code.

The parameters in the current implementation have not been finely tuned; this task is left to interested parties for further optimization.

The VTAGE algorithm was ported to provide a state-of-the-art baseline for research into value prediction — specifically, the EVES predictor (comprising EStride and EVTAGE) proposed in the CVP1.

For detailed background and reference material:

Change-Id: If6bbd218061b2836690390ca1e3f06788df30100

Summary by CodeRabbit

  • New Features
    • Added VTAGE value predictor support with configurable parameters.
    • Extended value-prediction requests and load-training metadata with optional BTB fetch-target context and richer observed load fields.
  • Bug Fixes
    • Improved load value-prediction training by recording observed latency, cache-hit status, and criticality/validity.
    • Ensured composite value-prediction feedback propagates overall correctness/made signals consistently and refined multi-candidate stats.
  • Chores
    • Updated example value-prediction configuration to use an Ideal-constant ensemble with fixed-priority arbitration.
    • Added safer PGO fallback to non-PGO rebuild when profiling or profile merging fails.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds VTAGE value prediction support across metadata, o3 pipeline wiring, build/config registration, and the VTAGE implementation. It also updates the PGO helper script to rebuild without PGO when profiling or profile merging fails.

Changes

VTAGE value predictor integration

Layer / File(s) Summary
Value prediction metadata contracts
src/cpu/valuepred/vtage_metadata.hh, src/cpu/valuepred/valuepred_metadata.hh
Adds VPHistoryRequestExt and LoadTrainInfoExt extension classes and new VPFeedback fields for overall prediction outcome.
DynInst observed-load recording
src/cpu/o3/dyn_inst.hh
Adds recordVPObservedLoadResult(...) and fields for observed latency, cache-hit, validity, and critical-load status.
Fetch/LSQ/Commit wiring
src/cpu/o3/fetch.cc, src/cpu/o3/lsq.cc, src/cpu/o3/commit.cc
Fetch attaches BTB history data to prediction requests, LSQ records observed load results on response, and Commit forwards load training metadata plus updated VP feedback into valuePred->update().
Composite predictor feedback propagation
src/cpu/valuepred/composite_value_predictor.cc
Propagates the new overall prediction fields to child feedback and changes the multi-candidate counter condition.
VTAGE interface and config declarations
src/cpu/valuepred/vtage.hh, src/cpu/valuepred/ValuePredictor.py, src/cpu/valuepred/SConscript, configs/example/idealkmhv3.py
Declares VTAGE types and stats, registers the predictor in Python/SCons, and adds it to the example predictor list.
VTAGE hashing and training helpers
src/cpu/valuepred/vtage.cc
Implements VTAGE construction, hashing, history folding, indexing, value matching, and training-policy helpers.
VTAGE allocation, aging, predict and update
src/cpu/valuepred/vtage.cc
Implements allocation-bank selection, pointer upgrade, aging/backoff, prediction, update, and no-op squash/specUpdate paths.

PGO fallback script

Layer / File(s) Summary
Fallback rebuild flow
util/pgo/basic_pgo_new.sh
Adds warning and rebuild helpers, then adds guarded profile-run and profile-merge handling that falls back to a non-PGO build path on failure or missing output.

Estimated code review effort: 4 (Complex) | ~75 minutes

Possibly related PRs

  • OpenXiangShan/GEM5#766: Extends the same o3 value-prediction integration points used here, including commit.cc, dyn_inst.hh, fetch.cc, and idealkmhv3.py.
  • OpenXiangShan/GEM5#940: Uses the same newer value-prediction request/update/feedback flow that this PR extends with VTAGE-specific metadata and feedback fields.

Suggested reviewers: tastynoob, jensen-yan

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding the VTAGE value predictor under mem.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lvp-vtage

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@happy-lx happy-lx added the perf label Jul 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/cpu/valuepred/vtage_metadata.hh (1)

41-51: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Document the lifetime contract of fetchTarget.

VPHistoryRequestExt holds a raw, non-owning fetchTarget pointer into an FTQ entry (populated in Fetch::processSingleInstruction via &dbpbtb->ftqFetchingTarget(tid)). Current usage is safe because it's dereferenced synchronously inside the same valuePredict() call, but nothing in the header states this constraint. A future caller that stashes the extension/record for later (e.g. across cycles) could dereference a stale/reused FTQ slot.

Consider adding a short comment documenting that fetchTarget is only valid for the duration of the valuePredict() call that receives this extension.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage_metadata.hh` around lines 41 - 51,
`VPHistoryRequestExt` stores a raw non-owning `fetchTarget` pointer whose
validity is only synchronous, but that constraint is not documented. Add a brief
lifetime comment on `fetchTarget` in `VPHistoryRequestExt` (and, if needed, near
the constructor) stating that it points to an FTQ entry and is only valid for
the duration of the `valuePredict()` call that consumes this extension. Use the
`VPHistoryRequestExt` and `fetchTarget` symbols so future callers know not to
retain it across cycles or stash it beyond the immediate call.
src/cpu/valuepred/vtage.hh (2)

52-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Naming convention: constant and method names don't follow the repo's lower_snake_case/ALL_CAPS rules.

ValueWays (Line 53) is UpperCamelCase rather than ALL_CAPS, and the private helper methods declared here (bitMask, maxConf, mix64, foldHistory, fillIndicesAndTags, etc.) are camelCase rather than lower_snake_case. Note several public overrides (predict, update, specUpdate, squash, getValuePredictorType) are constrained by the base VPUnit interface and can't be renamed independently, so full compliance would require broader base-class changes; treat this as advisory only for the new private helpers.

As per coding guidelines, "Types and classes should use UpperCamelCase naming convention. Functions and methods should use lower_snake_case naming convention. Constants should use ALL_CAPS naming convention."

Also applies to: 184-213

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage.hh` around lines 52 - 53, The new constant and helper
names in VTAGE violate the repo naming rules: ValueWays should be ALL_CAPS, and
the private helper methods in VTAGE should use lower_snake_case. Update the
identifiers in VTAGE to match the convention (for example, the constant
definition and helpers like bitMask, maxConf, mix64, foldHistory, and
fillIndicesAndTags), while leaving the VPUnit override methods alone since they
follow the inherited interface and should not be renamed independently.

Source: Coding guidelines


93-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider deriving numBanks from histLengths.size() instead of a separately configurable param.

numHistories/numBanks/histLengths are three independent Params that must satisfy numBanks == numHistories + 1 and histLengths.size() == numBanks (enforced only via runtime gem5_assert in the constructor). A user could easily set inconsistent values and only discover it via a fatal assertion at simulation start. Deriving numBanks (and even numHistories) directly from histLengths.size() would remove this footgun.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage.hh` around lines 93 - 95, The VTAGE params currently
expose independent numHistories, numBanks, and histLengths values, but numBanks
should be derived from histLengths.size() so callers cannot configure
inconsistent state. Update the VTAGE parameter handling in vtage.hh and the
VTAGE constructor/initialization path to stop treating numBanks as a separate
user-configurable source of truth, and instead compute it from histLengths (and,
if possible, derive numHistories from that relationship as well). Make sure all
uses of numBanks and numHistories in the VTAGE class refer to the derived values
so the existing runtime gem5_assert checks are no longer needed as the primary
validation.
src/cpu/valuepred/vtage.cc (1)

184-201: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

foldHistory is O(length) per call regardless of set-bit density; called 4× per bank in fillIndicesAndTags.

For every predict() call, fillIndicesAndTags invokes foldHistory 4 times per bank (history/path history × index/tag), each iterating every bit up to length via history.test(bit). With numBanks=9 and history lengths up to 127, this is a meaningful hot-path cost on every fetch-time value prediction. boost::dynamic_bitset supports find_first()/find_next() to skip directly to set bits, which would make the loop cost proportional to the population count rather than the full length.

♻️ Sketch using find_next for sparse history
-    for (size_t bit = 0; bit < limit; ++bit) {
-        if (!history.test(bit)) {
-            continue;
-        }
-        accum ^= mix64((static_cast<uint64_t>(bit) + 1) *
-                0x9e3779b97f4a7c15ULL ^ salt);
-        accum = (accum << 7) | (accum >> (64 - 7));
-    }
+    for (auto bit = history.find_first();
+            bit != boost::dynamic_bitset<>::npos && bit < limit;
+            bit = history.find_next(bit)) {
+        accum ^= mix64((static_cast<uint64_t>(bit) + 1) *
+                0x9e3779b97f4a7c15ULL ^ salt);
+        accum = (accum << 7) | (accum >> (64 - 7));
+    }

Also applies to: 204-238

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage.cc` around lines 184 - 201, The VTAGE::foldHistory
helper currently scans every bit up to the requested length on each call, which
makes the predict-time hot path in fillIndicesAndTags unnecessarily expensive.
Update foldHistory to iterate only over set bits in the boost::dynamic_bitset
history using find_first/find_next (while preserving the current mixing, salt,
and bitMask(out_bits) behavior), so the cost scales with the number of set bits
rather than the full history length. Make sure the change still works for both
history and path-history inputs used by fillIndicesAndTags across all banks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cpu/valuepred/vtage.cc`:
- Around line 350-372: The allocation logic in VTAGE::chooseAllocationStartBank
leaves bank 0 permanently unused, so update() and predict() never exercise the
base-bank path and the hit_bank == 0 branch is dead. Fix this by either making
bank 0 the explicit always-valid base predictor and updating the
allocation/prediction paths accordingly, or by removing the extra reserved bank
from the VTAGE bank layout and deleting the unreachable special-case in
chooseAllocationStartBank().

---

Nitpick comments:
In `@src/cpu/valuepred/vtage_metadata.hh`:
- Around line 41-51: `VPHistoryRequestExt` stores a raw non-owning `fetchTarget`
pointer whose validity is only synchronous, but that constraint is not
documented. Add a brief lifetime comment on `fetchTarget` in
`VPHistoryRequestExt` (and, if needed, near the constructor) stating that it
points to an FTQ entry and is only valid for the duration of the
`valuePredict()` call that consumes this extension. Use the
`VPHistoryRequestExt` and `fetchTarget` symbols so future callers know not to
retain it across cycles or stash it beyond the immediate call.

In `@src/cpu/valuepred/vtage.cc`:
- Around line 184-201: The VTAGE::foldHistory helper currently scans every bit
up to the requested length on each call, which makes the predict-time hot path
in fillIndicesAndTags unnecessarily expensive. Update foldHistory to iterate
only over set bits in the boost::dynamic_bitset history using
find_first/find_next (while preserving the current mixing, salt, and
bitMask(out_bits) behavior), so the cost scales with the number of set bits
rather than the full history length. Make sure the change still works for both
history and path-history inputs used by fillIndicesAndTags across all banks.

In `@src/cpu/valuepred/vtage.hh`:
- Around line 52-53: The new constant and helper names in VTAGE violate the repo
naming rules: ValueWays should be ALL_CAPS, and the private helper methods in
VTAGE should use lower_snake_case. Update the identifiers in VTAGE to match the
convention (for example, the constant definition and helpers like bitMask,
maxConf, mix64, foldHistory, and fillIndicesAndTags), while leaving the VPUnit
override methods alone since they follow the inherited interface and should not
be renamed independently.
- Around line 93-95: The VTAGE params currently expose independent numHistories,
numBanks, and histLengths values, but numBanks should be derived from
histLengths.size() so callers cannot configure inconsistent state. Update the
VTAGE parameter handling in vtage.hh and the VTAGE constructor/initialization
path to stop treating numBanks as a separate user-configurable source of truth,
and instead compute it from histLengths (and, if possible, derive numHistories
from that relationship as well). Make sure all uses of numBanks and numHistories
in the VTAGE class refer to the derived values so the existing runtime
gem5_assert checks are no longer needed as the primary validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c90987cb-2a53-4d5a-9f73-d79f6a4328e3

📥 Commits

Reviewing files that changed from the base of the PR and between f0745cc and 5569535.

📒 Files selected for processing (12)
  • configs/example/idealkmhv3.py
  • src/cpu/o3/commit.cc
  • src/cpu/o3/dyn_inst.hh
  • src/cpu/o3/fetch.cc
  • src/cpu/o3/lsq.cc
  • src/cpu/valuepred/SConscript
  • src/cpu/valuepred/ValuePredictor.py
  • src/cpu/valuepred/composite_value_predictor.cc
  • src/cpu/valuepred/valuepred_metadata.hh
  • src/cpu/valuepred/vtage.cc
  • src/cpu/valuepred/vtage.hh
  • src/cpu/valuepred/vtage_metadata.hh

Comment on lines +350 to +372
unsigned
VTAGE::chooseAllocationStartBank(int hit_bank)
{
unsigned start_bank = 1;
if (hit_bank >= 0) {
start_bank = std::min<unsigned>(static_cast<unsigned>(hit_bank + 1),
numBanks - 1);
if (hit_bank == 0 && start_bank + 1 < numBanks) {
++start_bank;
}
}

if (enableStochasticTraining && start_bank > 1 &&
chance(shortHistoryAllocBias)) {
start_bank = 1;
}
if (enableStochasticTraining && start_bank + 1 < numBanks &&
chance(deepAllocExtraHopProb)) {
++start_bank;
}

return std::min(start_bank, numBanks - 1);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="src/cpu/valuepred/vtage.cc"

echo "== file info =="
wc -l "$file"
echo

echo "== outline =="
ast-grep outline "$file" --view expanded || true
echo

echo "== relevant ranges =="
sed -n '90,130p;330,390p;470,520p;590,630p' "$file" | cat -n

Repository: OpenXiangShan/GEM5

Length of output: 8151


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="src/cpu/valuepred/vtage.cc"

echo "== constructor/init section =="
sed -n '1,120p' "$file" | cat -n
echo

echo "== predict hit-scan and allocation sections =="
sed -n '450,520p;590,625p' "$file" | cat -n
echo

echo "== search for bank 0 specific logic =="
rg -n "bank 0|bank0|hitBank == 0|numBanks ==|numHistories|tables\\[.*\\]\\[0\\]|\\[0\\].*valid|start_bank" "$file"

Repository: OpenXiangShan/GEM5

Length of output: 11336


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=$(git ls-files 'src/cpu/valuepred/vtage.*' 'src/cpu/valuepred/*' 'src/**/valuepred/*' | tr '\n' ' ')
echo "== candidate files =="
printf '%s\n' "$files"
echo

echo "== bank 0 / valid / allocation writes =="
rg -n "valid\\s*=\\s*true|valid\\s*=\\s*false|chooseAllocationStartBank|tables\\[.*\\]\\[0\\]|bank == 0|hitBank == 0|base bank|untyped|untagged|always-valid|predict\\(|update\\(" src/cpu/valuepred src -g '!**/*.o'
echo

echo "== VTAGEEntry definition and defaults =="
fd -a 'vtage*.hh' src || true
fd -a 'vtage*.cc' src || true

Repository: OpenXiangShan/GEM5

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== all vtage.cc validity writes =="
rg -n "valid\s*=" src/cpu/valuepred/vtage.cc
echo

echo "== bank-0 and base-bank references in VTAGE headers/metadata =="
rg -n "bank 0|base bank|bank0|hit_bank == 0|numBanks == numHistories \+ 1|histLengths\[0\]|tables\[.*\]\[0\]|valid = false|valid = true" \
  src/cpu/valuepred/vtage.hh src/cpu/valuepred/vtage_metadata.hh src/cpu/valuepred/ValuePredictor.py src/cpu/valuepred/vtage.cc
echo

echo "== vtage.hh relevant structs/enums =="
sed -n '1,140p;180,250p' src/cpu/valuepred/vtage.hh | cat -n

Repository: OpenXiangShan/GEM5

Length of output: 8792


Bank 0 is reserved but never populated
chooseAllocationStartBank() never returns 0, so update() never writes tables[tid][0], and predict() can never hit bank 0. That makes the hit_bank == 0 branch unreachable while still reserving a full base-bank slice via numBanks == numHistories + 1. If bank 0 is meant to be the always-valid base predictor, it needs explicit handling; otherwise remove the extra bank and the dead branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage.cc` around lines 350 - 372, The allocation logic in
VTAGE::chooseAllocationStartBank leaves bank 0 permanently unused, so update()
and predict() never exercise the base-bank path and the hit_bank == 0 branch is
dead. Fix this by either making bank 0 the explicit always-valid base predictor
and updating the allocation/prediction paths accordingly, or by removing the
extra reserved bank from the VTAGE bank layout and deleting the unreachable
special-case in chooseAllocationStartBank().

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@happy-lx happy-lx force-pushed the lvp-vtage branch 2 times, most recently from 1d5c39c to 1eea5de Compare July 7, 2026 08:49
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
configs/example/idealkmhv3.py (1)

79-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant explicit arb assignment.

arb=CVPFixedPriorityArb() matches the class default already defined for CompositeValuePredictor in ValuePredictor.py. Harmless, but adds no behavioral change over omitting it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@configs/example/idealkmhv3.py` at line 79, The explicit arb assignment is
redundant because CompositeValuePredictor already defaults to
CVPFixedPriorityArb; remove the unnecessary arb=CVPFixedPriorityArb() argument
from the CompositeValuePredictor configuration in the example setup so it relies
on the class default.
src/cpu/valuepred/ValuePredictor.py (1)

100-115: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate probability knobs stay in [0, 1].

These Param.Float values feed VTAGE::chance(), where values <= 0 become never and >= 1 become always. Add VTAGE constructor checks so config typos fail fast instead of silently changing training policy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/ValuePredictor.py` around lines 100 - 115, The probability
parameters in ValuePredictor are currently unconstrained, so invalid config
values can silently change VTAGE::chance() behavior. Add validation in the VTAGE
constructor or initialization path that checks each probability knob from
ValuePredictor (such as allocProbLoadL1Hit, allocProbLoadMiss,
confIncProbLowValue, confIncProbFastLoad, uIncProbFastLoad,
valueArrayUpgradeProb, shortHistoryAllocBias, and deepAllocExtraHopProb) is
within [0, 1], and fail fast with a clear error if not.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cpu/valuepred/vtage.cc`:
- Around line 38-45: The constructor initialization in vtage.cc computes
bankSize, valueEntriesPerWay, and totalValueEntries with unchecked shifts before
the VTAGE assertions can run, so invalid params can cause undefined behavior
first. Move the bounds validation ahead of these member initializers or replace
the raw shifts with a checked/guarded helper in the VTAGE constructor so
logBankSize and logValueArrayEntries are verified before any array sizing
occurs.

---

Nitpick comments:
In `@configs/example/idealkmhv3.py`:
- Line 79: The explicit arb assignment is redundant because
CompositeValuePredictor already defaults to CVPFixedPriorityArb; remove the
unnecessary arb=CVPFixedPriorityArb() argument from the CompositeValuePredictor
configuration in the example setup so it relies on the class default.

In `@src/cpu/valuepred/ValuePredictor.py`:
- Around line 100-115: The probability parameters in ValuePredictor are
currently unconstrained, so invalid config values can silently change
VTAGE::chance() behavior. Add validation in the VTAGE constructor or
initialization path that checks each probability knob from ValuePredictor (such
as allocProbLoadL1Hit, allocProbLoadMiss, confIncProbLowValue,
confIncProbFastLoad, uIncProbFastLoad, valueArrayUpgradeProb,
shortHistoryAllocBias, and deepAllocExtraHopProb) is within [0, 1], and fail
fast with a clear error if not.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3574ad79-a819-4427-994a-4c6ed42e4e1f

📥 Commits

Reviewing files that changed from the base of the PR and between 1d5c39c and 1eea5de.

📒 Files selected for processing (12)
  • configs/example/idealkmhv3.py
  • src/cpu/o3/commit.cc
  • src/cpu/o3/dyn_inst.hh
  • src/cpu/o3/fetch.cc
  • src/cpu/o3/lsq.cc
  • src/cpu/valuepred/SConscript
  • src/cpu/valuepred/ValuePredictor.py
  • src/cpu/valuepred/composite_value_predictor.cc
  • src/cpu/valuepred/valuepred_metadata.hh
  • src/cpu/valuepred/vtage.cc
  • src/cpu/valuepred/vtage.hh
  • src/cpu/valuepred/vtage_metadata.hh
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/cpu/valuepred/composite_value_predictor.cc
  • src/cpu/valuepred/valuepred_metadata.hh
  • src/cpu/valuepred/SConscript
  • src/cpu/o3/lsq.cc
  • src/cpu/o3/commit.cc
  • src/cpu/valuepred/vtage_metadata.hh
  • src/cpu/o3/fetch.cc
  • src/cpu/o3/dyn_inst.hh
  • src/cpu/valuepred/vtage.hh

Comment on lines +38 to +45
logBankSize(params.logBankSize),
bankSize(1u << params.logBankSize),
tagBits(params.tagBits),
confBits(params.confBits),
usefulBits(params.usefulBits),
logValueArrayEntries(params.logValueArrayEntries),
valueEntriesPerWay(1u << params.logValueArrayEntries),
totalValueEntries(ValueWays * (1u << params.logValueArrayEntries)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all VTAGE size shifts and the declared storage widths before patching.
set -euo pipefail
rg -n -C3 '1u\s*<<|logBankSize|logValueArrayEntries|bankSize|valueEntriesPerWay|totalValueEntries' src/cpu/valuepred/vtage.cc src/cpu/valuepred/vtage.hh

Repository: OpenXiangShan/GEM5

Length of output: 8312


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect VTAGE parameter definitions and any config-side bounds on the shift inputs.
rg -n -C3 'logBankSize|logValueArrayEntries|bankSize|valueEntriesPerWay|totalValueEntries|VTAGE' src include configs . \
  -g '!**/build/**' -g '!**/dist/**' -g '!**/node_modules/**'

Repository: OpenXiangShan/GEM5

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the constructor body to see whether any validation happens before/after sizing.
sed -n '1,140p' src/cpu/valuepred/vtage.cc

Repository: OpenXiangShan/GEM5

Length of output: 5185


Guard the size shifts before constructing the arrays. 1u << params.logBankSize and 1u << params.logValueArrayEntries are evaluated in the initializer list, before the constructor assertions run, so a large config value can trigger undefined behavior before gem5 reports the bad parameter. Use a checked shift or validate the bounds first.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage.cc` around lines 38 - 45, The constructor
initialization in vtage.cc computes bankSize, valueEntriesPerWay, and
totalValueEntries with unchecked shifts before the VTAGE assertions can run, so
invalid params can cause undefined behavior first. Move the bounds validation
ahead of these member initializers or replace the raw shifts with a
checked/guarded helper in the VTAGE constructor so logBankSize and
logValueArrayEntries are verified before any array sizing occurs.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
configs/example/idealkmhv3.py (1)

79-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant explicit arb assignment.

CVPFixedPriorityArb() is already the default value for CompositeValuePredictor.arb per ValuePredictor.py. Explicitly passing it here is harmless but unnecessary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@configs/example/idealkmhv3.py` at line 79, Remove the redundant explicit arb
assignment where CompositeValuePredictor is configured in the example setup,
since CVPFixedPriorityArb() is already the default for the arb parameter. Update
the call site that passes arb=CVPFixedPriorityArb() so it relies on the default
value instead, keeping the configuration cleaner without changing behavior.
util/pgo/basic_pgo_new.sh (3)

35-35: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fallback exits 0 despite the original PGO build failing.

rebuild_without_pgo always exit 0s, even when invoked because profiling or profdata merge failed. Callers (e.g., CI) will see a successful exit even though PGO instrumentation never completed, potentially masking a real problem in the PGO toolchain.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@util/pgo/basic_pgo_new.sh` at line 35, The fallback path in
rebuild_without_pgo currently always returns success, which can hide a failed
PGO build or profiling step. Update rebuild_without_pgo in basic_pgo_new.sh so
it preserves and propagates the original failure status instead of
unconditionally exiting 0; make the function return or exit with the caller’s
non-zero code when it is invoked due to profiling or profdata merge errors.

84-84: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer a subshell over cd .. to avoid needing to cd back.

Minor robustness nit flagged by shellcheck.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@util/pgo/basic_pgo_new.sh` at line 84, The script uses a plain cd .. in the
PGO setup flow, which requires later restoring the directory and is less robust.
Update the basic_pgo_new.sh logic to run that parent-directory command in a
subshell instead of changing the caller’s working directory, keeping the
surrounding behavior in place while avoiding the need to cd back.

Source: Linters/SAST tools


62-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Quote path/variable expansions per shellcheck.

$gem5_home in the gem5.fast invocation is unquoted (lines 64-65), risking word-splitting/globbing if the path contains spaces or special characters.

🔧 Proposed fix
-$gem5_home/build/RISCV/gem5.fast \
-     $gem5_home/configs/example/idealkmhv3.py \
+"$gem5_home"/build/RISCV/gem5.fast \
+     "$gem5_home"/configs/example/idealkmhv3.py \
      --raw-cpt \
      --generic-rv-cpt=$GEM5_PGO_CPT
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@util/pgo/basic_pgo_new.sh` around lines 62 - 71, The gem5.fast invocation in
basic_pgo_new.sh uses unquoted variable expansions, so update the command in the
profiling block to quote the path variables referenced by the gem5_home and
GEM5_PGO_CPT values. Fix the shellcheck issue by adjusting the command near the
gem5.fast call so the path arguments are treated as single values even if they
contain spaces or special characters.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/cpu/valuepred/vtage.cc`:
- Around line 59-66: The VTAGE probability parameters are currently accepted
without validation, which can let invalid values silently behave as always/never
in chance(). Add constructor assertions in the VTAGE parameter initialization
path to verify every stochastic Param.Float stays within [0, 1], covering the
probabilities initialized in the constructor (including allocProbLoadL1Hit,
allocProbLoadMiss, confIncProbLowValue, confIncProbFastLoad, uIncProbFastLoad,
valueArrayUpgradeProb, shortHistoryAllocBias, and deepAllocExtraHopProb) as well
as the related probability fields in the later constructor block. Use the VTAGE
class/constructor and any helper that consumes these params as the main place to
enforce validation.

In `@util/pgo/basic_pgo_new.sh`:
- Around line 26-36: The rebuild_without_pgo function currently continues even
if cd "$gem5_home" fails, which can make the subsequent rm -rf llvm-pgo run in
the wrong directory. Update rebuild_without_pgo to hard-fail immediately when
the cd step does not succeed, before any destructive cleanup, and keep the
existing flow intact for the successful path.

---

Nitpick comments:
In `@configs/example/idealkmhv3.py`:
- Line 79: Remove the redundant explicit arb assignment where
CompositeValuePredictor is configured in the example setup, since
CVPFixedPriorityArb() is already the default for the arb parameter. Update the
call site that passes arb=CVPFixedPriorityArb() so it relies on the default
value instead, keeping the configuration cleaner without changing behavior.

In `@util/pgo/basic_pgo_new.sh`:
- Line 35: The fallback path in rebuild_without_pgo currently always returns
success, which can hide a failed PGO build or profiling step. Update
rebuild_without_pgo in basic_pgo_new.sh so it preserves and propagates the
original failure status instead of unconditionally exiting 0; make the function
return or exit with the caller’s non-zero code when it is invoked due to
profiling or profdata merge errors.
- Line 84: The script uses a plain cd .. in the PGO setup flow, which requires
later restoring the directory and is less robust. Update the basic_pgo_new.sh
logic to run that parent-directory command in a subshell instead of changing the
caller’s working directory, keeping the surrounding behavior in place while
avoiding the need to cd back.
- Around line 62-71: The gem5.fast invocation in basic_pgo_new.sh uses unquoted
variable expansions, so update the command in the profiling block to quote the
path variables referenced by the gem5_home and GEM5_PGO_CPT values. Fix the
shellcheck issue by adjusting the command near the gem5.fast call so the path
arguments are treated as single values even if they contain spaces or special
characters.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e76f790-864c-4154-9dea-76f235797f28

📥 Commits

Reviewing files that changed from the base of the PR and between 1eea5de and b5bcf34.

📒 Files selected for processing (13)
  • configs/example/idealkmhv3.py
  • src/cpu/o3/commit.cc
  • src/cpu/o3/dyn_inst.hh
  • src/cpu/o3/fetch.cc
  • src/cpu/o3/lsq.cc
  • src/cpu/valuepred/SConscript
  • src/cpu/valuepred/ValuePredictor.py
  • src/cpu/valuepred/composite_value_predictor.cc
  • src/cpu/valuepred/valuepred_metadata.hh
  • src/cpu/valuepred/vtage.cc
  • src/cpu/valuepred/vtage.hh
  • src/cpu/valuepred/vtage_metadata.hh
  • util/pgo/basic_pgo_new.sh
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/cpu/valuepred/valuepred_metadata.hh
  • src/cpu/valuepred/vtage_metadata.hh
  • src/cpu/o3/lsq.cc
  • src/cpu/o3/dyn_inst.hh
  • src/cpu/o3/fetch.cc
  • src/cpu/valuepred/SConscript
  • src/cpu/valuepred/vtage.hh
  • src/cpu/o3/commit.cc
  • src/cpu/valuepred/composite_value_predictor.cc

Comment on lines +59 to +66
allocProbLoadL1Hit(params.allocProbLoadL1Hit),
allocProbLoadMiss(params.allocProbLoadMiss),
confIncProbLowValue(params.confIncProbLowValue),
confIncProbFastLoad(params.confIncProbFastLoad),
uIncProbFastLoad(params.uIncProbFastLoad),
valueArrayUpgradeProb(params.valueArrayUpgradeProb),
shortHistoryAllocBias(params.shortHistoryAllocBias),
deepAllocExtraHopProb(params.deepAllocExtraHopProb),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate stochastic probabilities instead of silently clamping configs.

Param.Float values outside [0, 1] currently become “never” or “always” in chance(), which can hide misconfigured VTAGE training policy. Add constructor assertions for every probability param.

Suggested fix
+#include <cmath>
+
 VTAGE::VTAGE(const Params &params)
@@
     gem5_assert(l2HitMaxCycles <= llcHitMaxCycles,
             "VTAGE l2HitMaxCycles must not exceed llcHitMaxCycles");
+
+    const auto valid_probability = [](double probability) {
+        return std::isfinite(probability) &&
+            probability >= 0.0 && probability <= 1.0;
+    };
+    gem5_assert(valid_probability(allocProbLoadL1Hit),
+            "VTAGE allocProbLoadL1Hit must be in [0, 1]");
+    gem5_assert(valid_probability(allocProbLoadMiss),
+            "VTAGE allocProbLoadMiss must be in [0, 1]");
+    gem5_assert(valid_probability(confIncProbLowValue),
+            "VTAGE confIncProbLowValue must be in [0, 1]");
+    gem5_assert(valid_probability(confIncProbFastLoad),
+            "VTAGE confIncProbFastLoad must be in [0, 1]");
+    gem5_assert(valid_probability(uIncProbFastLoad),
+            "VTAGE uIncProbFastLoad must be in [0, 1]");
+    gem5_assert(valid_probability(valueArrayUpgradeProb),
+            "VTAGE valueArrayUpgradeProb must be in [0, 1]");
+    gem5_assert(valid_probability(shortHistoryAllocBias),
+            "VTAGE shortHistoryAllocBias must be in [0, 1]");
+    gem5_assert(valid_probability(deepAllocExtraHopProb),
+            "VTAGE deepAllocExtraHopProb must be in [0, 1]");

Also applies to: 147-160

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cpu/valuepred/vtage.cc` around lines 59 - 66, The VTAGE probability
parameters are currently accepted without validation, which can let invalid
values silently behave as always/never in chance(). Add constructor assertions
in the VTAGE parameter initialization path to verify every stochastic
Param.Float stays within [0, 1], covering the probabilities initialized in the
constructor (including allocProbLoadL1Hit, allocProbLoadMiss,
confIncProbLowValue, confIncProbFastLoad, uIncProbFastLoad,
valueArrayUpgradeProb, shortHistoryAllocBias, and deepAllocExtraHopProb) as well
as the related probability fields in the later constructor block. Use the VTAGE
class/constructor and any helper that consumes these params as the main place to
enforce validation.

Comment thread util/pgo/basic_pgo_new.sh
Comment on lines +26 to +36
function rebuild_without_pgo() {
warn "$1"
cd "$gem5_home"
rm -rf llvm-pgo
CC=clang CXX=clang++ scons -c build/RISCV/gem5.fast --gold-linker
check $?
CC=clang CXX=clang++ scons build/RISCV/gem5.fast -j $build_threads --gold-linker
check $?
printf "Non-PGO build is done after PGO fallback.\n"
exit 0
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard cd before destructive rm -rf.

If cd "$gem5_home" fails (unset/invalid path), execution continues and rm -rf llvm-pgo runs against the current (unintended) directory. Given the destructive nature of rm -rf, this should hard-fail instead of silently proceeding.

🛡️ Proposed fix
 function rebuild_without_pgo() {
     warn "$1"
-    cd "$gem5_home"
+    cd "$gem5_home" || { echo "FAIL: cannot cd to $gem5_home"; exit 1; }
     rm -rf llvm-pgo
-    CC=clang CXX=clang++ scons -c build/RISCV/gem5.fast --gold-linker
+    CC=clang CXX=clang++ scons -c build/RISCV/gem5.fast --gold-linker
     check $?
-    CC=clang CXX=clang++ scons build/RISCV/gem5.fast -j $build_threads --gold-linker
+    CC=clang CXX=clang++ scons build/RISCV/gem5.fast -j "$build_threads" --gold-linker
     check $?
     printf "Non-PGO build is done after PGO fallback.\n"
     exit 0
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function rebuild_without_pgo() {
warn "$1"
cd "$gem5_home"
rm -rf llvm-pgo
CC=clang CXX=clang++ scons -c build/RISCV/gem5.fast --gold-linker
check $?
CC=clang CXX=clang++ scons build/RISCV/gem5.fast -j $build_threads --gold-linker
check $?
printf "Non-PGO build is done after PGO fallback.\n"
exit 0
}
function rebuild_without_pgo() {
warn "$1"
cd "$gem5_home" || { echo "FAIL: cannot cd to $gem5_home"; exit 1; }
rm -rf llvm-pgo
CC=clang CXX=clang++ scons -c build/RISCV/gem5.fast --gold-linker
check $?
CC=clang CXX=clang++ scons build/RISCV/gem5.fast -j "$build_threads" --gold-linker
check $?
printf "Non-PGO build is done after PGO fallback.\n"
exit 0
}
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 28-28: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)


[info] 32-32: Double quote to prevent globbing and word splitting.

(SC2086)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@util/pgo/basic_pgo_new.sh` around lines 26 - 36, The rebuild_without_pgo
function currently continues even if cd "$gem5_home" fails, which can make the
subsequent rm -rf llvm-pgo run in the wrong directory. Update
rebuild_without_pgo to hard-fail immediately when the cd step does not succeed,
before any destructive cleanup, and keep the existing flow intact for the
successful path.

Source: Linters/SAST tools

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

🚀 Coremark Smoke Test Results

Branch IPC Change
Base (xs-dev) 2.3162 -
This PR 2.3162 ➡️ 0.0000 (0.00%)

✅ Difftest smoke test passed!

VTAGE is largely based on the open-source implementation of the 1st-place Championship Value Prediction (CVP-1) submission.

The version in this codebase is adapted and modified for our environment. It is not intended to be a bit-exact copy of the original code.

For detailed background and reference material:
+ Paper: https://microarch.org/cvp1/papers/Seznec.pdf
+ Open-source implementation: https://www.microarch.org/cvp1/code/Seznec.tar.gz
+ Official website: https://www.microarch.org/cvp1/

Change-Id: If6bbd218061b2836690390ca1e3f06788df30100
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant