简体   繁体   English

函数总是返回1

[英]Function always returns 1

I´m trying to write a simple branch predictor that should output either TAKEN (1) or NOT_TAKEN (0) depending on history stored in int. 我正在尝试编写一个简单的分支预测变量,它应根据存储在int中的历史记录输出TAKEN(1)或NOT_TAKEN(0)。 However it always outputs TAKEN instead of dynamicaly changing the prediction. 但是,它始终输出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 is used to "build" the predictor (create arrays, set initial values...), it is called right in the beginning. PREDICTOR :: PREDICTOR用于“构建”预测变量(创建数组,设置初始值...),它从一开始就被调用。

PREDICTOR::GetPrediction should return either TAKEN (when counter = 3 or 2) or NOT_TAKEN (when counter = 0 or 1). PREDICTOR :: GetPrediction应该返回TAKEN(当计数器= 3或2时)或NOT_TAKEN(当计数器= 0或1时)。

PREDICTOR::UpdatePredictor is called after GetPrediction. 在GetPrediction之后调用PREDICTOR :: UpdatePredictor。 It updates the predictor via resolveDir - resolveDir is the actual direction of the branch. 它通过resolveDir更新预测变量-resolveDir是分支的实际方向。 If resolveDir = 1 it does saturated increment of counter (saturated means it never exceeds PHT_CTR_MAX). 如果resolveDir = 1,它将使计数器饱和增加(饱和意味着它永远不会超过PHT_CTR_MAX)。 If resolveDir = 0 it decrements the counter. 如果resolveDir = 0,则计数器递减。

Although this predictor is really simple it does not work. 尽管此预测变量确实很简单,但它不起作用。 It throws out exactly same results as if I just did GetPrediction{return TAKEN} which is obviously wrong. 它抛出的结果与我刚刚执行GetPrediction {return TAKEN}完全相同,这显然是错误的。 My coding skills aren´t really great so I might have done something wrong - probably in the GetPrediction or UpdatePredictor function. 我的编码技能不是很出色,所以我可能做错了一些事情-可能是在GetPrediction或UpdatePredictor函数中。

Here is an example of predictor that works just fine, although this one is little bit more complex: 这是一个可以正常工作的预测变量示例,尽管这有点复杂:

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

This predictor works in the same way as my simple one, except that it uses an array of counters instead of single one. 该预测器的工作方式与我的简单预测器相同,不同之处在于它使用的是一组计数器而不是单个计数器。 When GetPrediction is called the array is indexed by last 17 bits of resolveDir (branch history, global history register or ghr) that are XORed with PC (adress of current branch). 调用GetPrediction时,将通过与PC(当前分支的地址)进行XOR运算的resolveDir(分支历史记录,全局历史记录寄存器或ghr)的后17位对数组进行索引。 This selects the appropriate counter from array that is then used to do the prediction. 这将从数组中选择适当的计数器,然后将其用于进行预测。 UpdatePredictor works the same way, array is indexed and then counter is choosen. UpdatePredictor以相同的方式工作,对数组建立索引,然后选择计数器。 Counter is updated with information from resolveDir. 计数器使用来自resolveDir的信息更新。 Lastly the global history buffer (ghr, branch history, call it what you want) is also updated. 最后,全局历史记录缓冲区(ghr,分支历史记录,称为所需的名称)也将更新。

Code of the SatIncrement and SatDecrement functions: 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;
}

Thanks for help. 感谢帮助。

The reason the code doesn't work as expected is that SatIncrement and SatDecrement take arguments by-value and return the new value, which then must be assigned back to the variable that is supposed to be incremented/decremented. 代码无法按预期工作的原因是SatIncrementSatDecrement会按值获取参数并返回新值,然后必须将其重新分配给应该递增/递减的变量。

SatIncrement(counter, PHT_CTR_MAX);

will pass the value of counter but will not modify counter itself. 将传递counter的值,但不会修改counter本身。 The return value with the new value is not used and so effectively this line does nothing. 不使用带有新值的返回值,因此该行实际上不执行任何操作。 The same is true for SatDecrement(counter); SatDecrement(counter);也是如此SatDecrement(counter); .

Therefore your branch predictor never changes state and always returns the same prediction. 因此,分支预测变量永远不会更改状态,并且始终返回相同的预测。

Fix it by following the other code example: 通过遵循其他代码示例对其进行修复:

counter = SatIncrement(counter, PHT_CTR_MAX);

and

counter = SatDecrement(counter);

Given that this is an exercise you probably cannot change SatIncrement and SatDecrement , however in practice one would probably let these functions take arguments by-reference, so that they can modify the passed variable directly, avoiding the repetition of counter at the call site: 鉴于这是一种练习,您可能无法更改SatIncrementSatDecrement ,但是在实践中,可能会让这些函数按引用进行参数传递,以便它们可以直接修改传递的变量,从而避免在调用站点重复counter

static inline void SatIncrement(UINT32& x, UINT32 max)
{
  if(x<max) x++;
}

If the original signature were chosen, then since C++17 one can add the [[nodiscard]] attribute to the function to make the compiler print a warning if the return value is not used: 如果选择了原始签名,则由于C ++ 17,可以在函数中添加[[nodiscard]]属性,以使编译器在不使用返回值的情况下显示警告:

[[nodiscard]] static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
  if(x<max) return x+1;
  return x;
}

It would have warned you here and made the problem clearer. 它将在这里警告您,并使问题更加明确。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM