Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/cpu/o3/fetch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1535,8 +1535,13 @@ Fetch::handleIEWSignals()
for (const auto resolvedInstPC : entry.resolvedInstPC) {
dbpbtb->markCFIResolved(stream_id, resolvedInstPC);
}
dbpbtb->resolveUpdate(stream_id);
resolveQueue.pop_front();
bool success = dbpbtb->resolveUpdate(stream_id);
if (success) {
dbpbtb->notifyResolveSuccess();
resolveQueue.pop_front();
} else {
dbpbtb->notifyResolveFailure();
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/cpu/pred/BranchPredictor.py
Original file line number Diff line number Diff line change
Expand Up @@ -1171,3 +1171,4 @@ class DecoupledBPUWithBTB(BranchPredictor):
enableLoopBuffer = Param.Bool(False, "Enable loop buffer to supply inst for loops")
enableLoopPredictor = Param.Bool(False, "Use loop predictor to predict loop exit")
enableJumpAheadPredictor = Param.Bool(False, "Use jump ahead predictor to skip no-need-to-predict blocks")
resolveBlockThreshold = Param.Unsigned(8, "Consecutive resolve dequeue failures before blocking prediction once")
77 changes: 39 additions & 38 deletions src/cpu/pred/btb/btb_tage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ tageStats(this, p.numPredictors, p.numBanks)

// initialize use_alt_on_na table
useAlt.resize(useAltOnNaSize, 0);

#ifndef UNIT_TEST
hasDB = true;
switch (getDelay()) {
Expand Down Expand Up @@ -640,56 +639,58 @@ BTBTAGE::handleNewEntryAllocation(const Addr &startPC,
}

/**
* @brief Updates the TAGE predictor state based on actual branch execution results
*
* @param stream The fetch stream containing branch execution information
* @brief Probe resolved update for bank conflicts without mutating state.
* Returns false if the update cannot proceed due to a bank conflict.
*/
void
BTBTAGE::update(const FetchStream &stream) {
bool
BTBTAGE::canResolveUpdate(const FetchStream &stream) {
Addr startAddr = stream.getRealStartPC();
unsigned updateBank = getBankId(startAddr);

DPRINTF(TAGE, "update startAddr: %#lx, bank: %u\n", startAddr, updateBank);

#ifndef UNIT_TEST
// Record update access per bank
// Record attempted update access per bank (even if it conflicts)
tageStats.updateAccessPerBank[updateBank]++;
#endif

// ========== Bank Conflict Detection ==========
// Check if this update conflicts with the last prediction
// Only perform conflict detection if enableBankConflict is true
if (enableBankConflict) {
// Conflict happens when:
// 1. There was a valid prediction in this or previous tick (predBankValid)
// 2. Update and prediction target the same bank (updateBank == lastPredBankId)
//
// Note: This assumes one update() call per tick (guaranteed by fetch stage)
if (predBankValid && updateBank == lastPredBankId) {
tageStats.updateBankConflict++;
tageStats.updateDroppedDueToConflict++;

if (enableBankConflict && predBankValid && updateBank == lastPredBankId) {
tageStats.updateBankConflict++;
tageStats.updateDeferredDueToConflict++;
#ifndef UNIT_TEST
// Record conflict for this specific bank
tageStats.updateBankConflictPerBank[updateBank]++;
tageStats.updateBankConflictPerBank[updateBank]++;
#endif
DPRINTF(TAGE, "Bank conflict detected: update bank %u conflicts with prediction bank %u, "
"deferring this update (will retry after blocking prediction)\n",
updateBank, lastPredBankId);
predBankValid = false;
return false;
}

DPRINTF(TAGE, "Bank conflict detected: update bank %u conflicts with "
"prediction bank %u, dropping this update\n",
updateBank, lastPredBankId);

// Clear prediction state after consuming it
predBankValid = false;
return; // Drop this update entirely
}
return true;
}

// If no conflict, clear prediction state (prediction has been consumed)
if (predBankValid) {
DPRINTF(TAGE, "No bank conflict: update bank %u != prediction bank %u\n",
updateBank, lastPredBankId);
}
/**
* @brief Perform resolved update after probe success.
*/
void
BTBTAGE::doResolveUpdate(const FetchStream &stream) {
if (enableBankConflict && predBankValid) {
// Prediction consumed; clear bank tag for next cycle
predBankValid = false;
}
update(stream);
}

/**
* @brief Updates the TAGE predictor state based on actual branch execution results
*
* @param stream The fetch stream containing branch execution information
*/
void
BTBTAGE::update(const FetchStream &stream) {
Addr startAddr = stream.getRealStartPC();
unsigned updateBank = getBankId(startAddr);

DPRINTF(TAGE, "update startAddr: %#lx, bank: %u\n", startAddr, updateBank);

// ========== Normal Update Logic ==========
// Prepare BTB entries to update
Expand Down Expand Up @@ -1023,7 +1024,7 @@ BTBTAGE::TageStats::TageStats(statistics::Group* parent, int numPredictors, int
ADD_STAT(updateMispred, statistics::units::Count::get(), "mispred when update"),
ADD_STAT(updateResetU, statistics::units::Count::get(), "reset u when update"),
ADD_STAT(updateBankConflict, statistics::units::Count::get(), "number of bank conflicts detected"),
ADD_STAT(updateDroppedDueToConflict, statistics::units::Count::get(), "number of updates dropped due to bank conflict"),
ADD_STAT(updateDeferredDueToConflict, statistics::units::Count::get(), "number of updates deferred due to bank conflict (retried later)"),
ADD_STAT(updateBankConflictPerBank, statistics::units::Count::get(), "bank conflicts per bank"),
ADD_STAT(updateAccessPerBank, statistics::units::Count::get(), "update accesses per bank"),
ADD_STAT(predAccessPerBank, statistics::units::Count::get(), "prediction accesses per bank"),
Expand Down
4 changes: 3 additions & 1 deletion src/cpu/pred/btb/btb_tage.hh
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class BTBTAGE : public TimedBaseBTBPredictor

// Update predictor state based on actual branch outcomes
void update(const FetchStream &entry) override;
bool canResolveUpdate(const FetchStream &entry) override;
void doResolveUpdate(const FetchStream &entry) override;

#ifndef UNIT_TEST
void commitBranch(const FetchStream &stream, const DynInstPtr &inst) override;
Expand Down Expand Up @@ -349,7 +351,7 @@ class BTBTAGE : public TimedBaseBTBPredictor

// Bank conflict statistics
Scalar updateBankConflict; // Number of bank conflicts detected
Scalar updateDroppedDueToConflict; // Number of updates dropped due to bank conflict
Scalar updateDeferredDueToConflict; // Number of updates deferred due to bank conflict (retried later)

#ifndef UNIT_TEST
// Fine-grained per-bank statistics
Expand Down
60 changes: 51 additions & 9 deletions src/cpu/pred/btb/decoupled_bpred.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ DecoupledBPUWithBTB::DecoupledBPUWithBTB(const DecoupledBPUWithBTBParams &p)
bpDBSwitches(p.bpDBSwitches),
numStages(p.numStages),
historyManager(16), // TODO: fix this
resolveBlockThreshold(p.resolveBlockThreshold),
dbpBtbStats(this, p.numStages, p.fsq_size, maxInstsNum)
{
if (bpDBSwitches.size() > 0) {
Expand Down Expand Up @@ -139,8 +140,14 @@ DecoupledBPUWithBTB::tick()

// 1. Request new prediction if FSQ not full and we are idle
if (bpuState == BpuState::IDLE && !streamQueueFull()) {
requestNewPrediction();
bpuState = BpuState::PREDICTOR_DONE;
if (blockPredictionPending) {
DPRINTF(Override, "Prediction blocked to prioritize resolve update\n");
dbpBtbStats.predictionBlockedForUpdate++;
blockPredictionPending = false;
} else {
requestNewPrediction();
bpuState = BpuState::PREDICTOR_DONE;
}
}

// 2. Handle pending prediction if available
Expand Down Expand Up @@ -620,26 +627,61 @@ DecoupledBPUWithBTB::update(unsigned stream_id, ThreadID tid)
historyManager.commit(stream_id);
}

void
bool
DecoupledBPUWithBTB::resolveUpdate(unsigned &stream_id)
{
auto stream_it = fetchStreamQueue.find(stream_id);
if (stream_it == fetchStreamQueue.end()) {
DPRINTF(DecoupleBP, "Stream id %u not found in fetchStreamQueue, cannot update predictors\n", stream_id);
return;
return true;
}

auto &stream = stream_it->second;

// Update predictor components only if the stream is hit or taken
if (stream.isHit || stream.exeTaken) {
// Update predictor components
for (int i = 0; i < numComponents; ++i) {
if (components[i]->getResolvedUpdate()) {
components[i]->update(stream);
if (!(stream.isHit || stream.exeTaken)) {
return true;
}

// Phase 1: probe all resolved-update components to ensure no blocker
for (int i = 0; i < numComponents; ++i) {
if (components[i]->getResolvedUpdate()) {
if (!components[i]->canResolveUpdate(stream)) {
return false;
}
}
}

// Phase 2: all clear, perform updates once
for (int i = 0; i < numComponents; ++i) {
if (components[i]->getResolvedUpdate()) {
components[i]->doResolveUpdate(stream);
}
}

return true;
}

void
DecoupledBPUWithBTB::notifyResolveSuccess()
{
resolveDequeueFailCounter = 0;
}

void
DecoupledBPUWithBTB::notifyResolveFailure()
{
resolveDequeueFailCounter++;
if (resolveDequeueFailCounter >= resolveBlockThreshold) {
blockPredictionOnce();
resolveDequeueFailCounter = 0;
}
}

void
DecoupledBPUWithBTB::blockPredictionOnce()
{
blockPredictionPending = true;
}

void
Expand Down
11 changes: 10 additions & 1 deletion src/cpu/pred/btb/decoupled_bpred.hh
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ class DecoupledBPUWithBTB : public BPredUnit
bool squashing{false};

HistoryManager historyManager;
bool blockPredictionPending{false};
unsigned resolveDequeueFailCounter{0};
const unsigned resolveBlockThreshold;

unsigned numOverrideBubbles{0};

Expand Down Expand Up @@ -362,6 +365,9 @@ class DecoupledBPUWithBTB : public BPredUnit
statistics::Scalar predFalseHit;
statistics::Scalar commitFalseHit;

// Window blocking statistics
statistics::Scalar predictionBlockedForUpdate; // Times prediction was blocked for update priority

DBPBTBStats(statistics::Group* parent, unsigned numStages, unsigned fsqSize, unsigned maxInstsNum);
} dbpBtbStats;

Expand Down Expand Up @@ -815,11 +821,14 @@ class DecoupledBPUWithBTB : public BPredUnit
void resetPC(Addr new_pc);

// Helper functions for update
void resolveUpdate(unsigned &stream_id);
bool resolveUpdate(unsigned &stream_id);
void prepareResolveUpdateEntries(unsigned &stream_id);
void markCFIResolved(unsigned &stream_id, uint64_t resolvedInstPC);
void updatePredictorComponents(FetchStream &stream);
void updateStatistics(const FetchStream &stream);
void notifyResolveSuccess();
void notifyResolveFailure();
void blockPredictionOnce();

// Helper function to process FTQ entry completion
void processFetchTargetCompletion(const FtqEntry &target_to_fetch);
Expand Down
3 changes: 2 additions & 1 deletion src/cpu/pred/btb/decoupled_bpred_stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,8 @@ DecoupledBPUWithBTB::DBPBTBStats::DBPBTBStats(
ADD_STAT(btbEntriesWithDifferentStart, statistics::units::Count::get(), "number of btb entries with different start PC"),
ADD_STAT(btbEntriesWithOnlyOneJump, statistics::units::Count::get(), "number of btb entries with different start PC starting with a jump"),
ADD_STAT(predFalseHit, statistics::units::Count::get(), "false hit detected at pred"),
ADD_STAT(commitFalseHit, statistics::units::Count::get(), "false hit detected at commit")
ADD_STAT(commitFalseHit, statistics::units::Count::get(), "false hit detected at commit"),
ADD_STAT(predictionBlockedForUpdate, statistics::units::Count::get(), "prediction blocked for update priority")
{
predsOfEachStage.init(numStages);
commitPredsFromEachStage.init(numStages+1);
Expand Down
13 changes: 9 additions & 4 deletions src/cpu/pred/btb/test/btb_tage.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -901,10 +901,11 @@ TEST_F(BTBTAGETest, BankConflict) {
setupTageEntry(bankTage, 0xa0, 0, 1, false);

uint64_t conflicts_before = bankTage->tageStats.updateBankConflict;
bankTage->update(stream);
bool can_update = bankTage->canResolveUpdate(stream);

// Should detect conflict and drop update
// Should detect conflict and defer update
EXPECT_EQ(bankTage->tageStats.updateBankConflict, conflicts_before + 1);
EXPECT_FALSE(can_update);
EXPECT_FALSE(bankTage->predBankValid);
}

Expand All @@ -918,7 +919,9 @@ TEST_F(BTBTAGETest, BankConflict) {
FetchStream stream = createStream(0x104, createBTBEntry(0x104), true, meta);

uint64_t conflicts_before = bankTage->tageStats.updateBankConflict;
bankTage->update(stream);
bool can_update = bankTage->canResolveUpdate(stream);
ASSERT_TRUE(can_update);
bankTage->doResolveUpdate(stream);

// Should not detect conflict
EXPECT_EQ(bankTage->tageStats.updateBankConflict, conflicts_before);
Expand All @@ -936,7 +939,9 @@ TEST_F(BTBTAGETest, BankConflict) {
setupTageEntry(bankTage, 0xa0, 0, 1, false);

uint64_t conflicts_before = bankTage->tageStats.updateBankConflict;
bankTage->update(stream);
bool can_update = bankTage->canResolveUpdate(stream);
ASSERT_TRUE(can_update);
bankTage->doResolveUpdate(stream);

// No conflict even with same bank
EXPECT_EQ(bankTage->tageStats.updateBankConflict, conflicts_before);
Expand Down
3 changes: 3 additions & 0 deletions src/cpu/pred/btb/timed_base_pred.hh
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class TimedBaseBTBPredictor: public SimObject
virtual void update(const FetchStream &entry) {}
virtual unsigned getDelay() {return numDelay;}
virtual bool getResolvedUpdate() {return resolvedUpdate;}
// Two-phase resolved update: probe first, then apply
virtual bool canResolveUpdate(const FetchStream &entry) { return true; }
virtual void doResolveUpdate(const FetchStream &entry) { update(entry); }
#ifndef UNIT_TEST
// do some statistics on a per-branch and per-predictor basis
virtual void commitBranch(const FetchStream &entry, const DynInstPtr &inst) {}
Expand Down