簡體   English   中英

函數總是返回1

[英]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,分支歷史記錄,稱為所需的名稱)也將更新。

SatIncrementSatDecrement函數的代碼:

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;
}

感謝幫助。

代碼無法按預期工作的原因是SatIncrementSatDecrement會按值獲取參數並返回新值,然后必須將其重新分配給應該遞增/遞減的變量。

SatIncrement(counter, PHT_CTR_MAX);

將傳遞counter的值,但不會修改counter本身。 不使用帶有新值的返回值,因此該行實際上不執行任何操作。 SatDecrement(counter);也是如此SatDecrement(counter);

因此,分支預測變量永遠不會更改狀態,並且始終返回相同的預測。

通過遵循其他代碼示例對其進行修復:

counter = SatIncrement(counter, PHT_CTR_MAX);

counter = SatDecrement(counter);

鑒於這是一種練習,您可能無法更改SatIncrementSatDecrement ,但是在實踐中,可能會讓這些函數按引用進行參數傳遞,以便它們可以直接修改傳遞的變量,從而避免在調用站點重復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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM