繁体   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