[英]Function always returns 1
我正在嘗試編寫一個簡單的分支預測變量,它應根據存儲在int中的歷史記錄輸出TAKEN(1)或NOT_TAKEN(0)。 但是,它始終輸出TAKEN而不是動態更改預測。
#define PHT_CTR_MAX 3
#define PHT_CTR_INIT 2
class PREDICTOR{
private:
UINT32 counter;
public:
PREDICTOR(void);
bool GetPrediction(UINT64 PC);
void UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget);
};
PREDICTOR::PREDICTOR(void){
counter = PHT_CTR_INIT;
}
bool PREDICTOR::GetPrediction(UINT64 PC){
if(counter > (PHT_CTR_MAX/2)){
return TAKEN;
}else{
return NOT_TAKEN;
}
}
void PREDICTOR::UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget){
if(resolveDir == TAKEN){
SatIncrement(counter, PHT_CTR_MAX);
}else{
SatDecrement(counter);
}
}
PREDICTOR :: PREDICTOR用於“構建”預測變量(創建數組,設置初始值...),它從一開始就被調用。
PREDICTOR :: GetPrediction應該返回TAKEN(當計數器= 3或2時)或NOT_TAKEN(當計數器= 0或1時)。
在GetPrediction之后調用PREDICTOR :: UpdatePredictor。 它通過resolveDir更新預測變量-resolveDir是分支的實際方向。 如果resolveDir = 1,它將使計數器飽和增加(飽和意味着它永遠不會超過PHT_CTR_MAX)。 如果resolveDir = 0,則計數器遞減。
盡管此預測變量確實很簡單,但它不起作用。 它拋出的結果與我剛剛執行GetPrediction {return TAKEN}完全相同,這顯然是錯誤的。 我的編碼技能不是很出色,所以我可能做錯了一些事情-可能是在GetPrediction或UpdatePredictor函數中。
這是一個可以正常工作的預測變量示例,盡管這有點復雜:
#define PHT_CTR_MAX 3
#define PHT_CTR_INIT 2
#define HIST_LEN 17
class PREDICTOR{
private:
UINT32 ghr; // global history register
UINT32 *pht; // pattern history table
UINT32 historyLength; // history length
UINT32 numPhtEntries; // entries in pht
public:
PREDICTOR(void);
bool GetPrediction(UINT64 PC);
void UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget);
PREDICTOR::PREDICTOR(void){
historyLength = HIST_LEN;
ghr = 0;
numPhtEntries = (1<< HIST_LEN);
pht = new UINT32[numPhtEntries];
for(UINT32 ii=0; ii< numPhtEntries; ii++){
pht[ii]=PHT_CTR_INIT;
}
}
bool PREDICTOR::GetPrediction(UINT64 PC){
UINT32 phtIndex = (PC^ghr) % (numPhtEntries);
UINT32 phtCounter = pht[phtIndex];
if(phtCounter > (PHT_CTR_MAX/2)){
return TAKEN;
}
else{
return NOT_TAKEN;
}
}
void PREDICTOR::UpdatePredictor(UINT64 PC, OpType opType, bool resolveDir, bool predDir, UINT64 branchTarget){
UINT32 phtIndex = (PC^ghr) % (numPhtEntries);
UINT32 phtCounter = pht[phtIndex];
if(resolveDir == TAKEN){
pht[phtIndex] = SatIncrement(phtCounter, PHT_CTR_MAX);
}else{
pht[phtIndex] = SatDecrement(phtCounter);
}
// update the GHR
ghr = (ghr << 1);
if(resolveDir == TAKEN){
ghr++;
}
}
該預測器的工作方式與我的簡單預測器相同,不同之處在於它使用的是一組計數器而不是單個計數器。 調用GetPrediction時,將通過與PC(當前分支的地址)進行XOR運算的resolveDir(分支歷史記錄,全局歷史記錄寄存器或ghr)的后17位對數組進行索引。 這將從數組中選擇適當的計數器,然后將其用於進行預測。 UpdatePredictor以相同的方式工作,對數組建立索引,然后選擇計數器。 計數器使用來自resolveDir的信息更新。 最后,全局歷史記錄緩沖區(ghr,分支歷史記錄,稱為所需的名稱)也將更新。
SatIncrement
和SatDecrement
函數的代碼:
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if(x<max) return x+1;
return x;
}
static inline UINT32 SatDecrement(UINT32 x)
{
if(x>0) return x-1;
return x;
}
感謝幫助。
代碼無法按預期工作的原因是SatIncrement
和SatDecrement
會按值獲取參數並返回新值,然后必須將其重新分配給應該遞增/遞減的變量。
SatIncrement(counter, PHT_CTR_MAX);
將傳遞counter
的值,但不會修改counter
本身。 不使用帶有新值的返回值,因此該行實際上不執行任何操作。 SatDecrement(counter);
也是如此SatDecrement(counter);
。
因此,分支預測變量永遠不會更改狀態,並且始終返回相同的預測。
通過遵循其他代碼示例對其進行修復:
counter = SatIncrement(counter, PHT_CTR_MAX);
和
counter = SatDecrement(counter);
鑒於這是一種練習,您可能無法更改SatIncrement
和SatDecrement
,但是在實踐中,可能會讓這些函數按引用進行參數傳遞,以便它們可以直接修改傳遞的變量,從而避免在調用站點重復counter
:
static inline void SatIncrement(UINT32& x, UINT32 max)
{
if(x<max) x++;
}
如果選擇了原始簽名,則由於C ++ 17,可以在函數中添加[[nodiscard]]
屬性,以使編譯器在不使用返回值的情況下顯示警告:
[[nodiscard]] static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if(x<max) return x+1;
return x;
}
它將在這里警告您,並使問題更加明確。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.