Функция всегда возвращает 1 - PullRequest
0 голосов
/ 01 января 2019

Я пытаюсь написать простой предиктор ветвления, который должен выводить либо TAKEN (1), либо NOT_TAKEN (0) в зависимости от истории, хранящейся в int.Однако он всегда выводит 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).

PREDICTOR :: UpdatePredictor вызывается после GetPrediction,Он обновляет предиктор с помощью resolDir - resolDir - фактическое направление ветви.Если resolDir = 1, это делает насыщенный прирост счетчика (насыщенный означает, что он никогда не превышает PHT_CTR_MAX).Если resolDir = 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, массив индексируется последними 17 битами resolDir (история ветвления, регистр глобальной истории или ghr), которые XORed с ПК (адрес текущей ветки).Это выбирает соответствующий счетчик из массива, который затем используется для прогнозирования.UpdatePredictor работает так же, массив индексируется, а затем выбирается счетчик.Счетчик обновляется информацией из resolDir.Наконец, также обновляется глобальный буфер истории (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;
}

Спасибо запомощь.

1 Ответ

0 голосов
/ 01 января 2019

Причина, по которой код не работает должным образом, заключается в том, что SatIncrement и SatDecrement принимают аргументы по значению и возвращают новое значение, которое затем должно быть присвоено обратно переменной, которая должна увеличиваться / уменьшаться.

SatIncrement(counter, PHT_CTR_MAX);

передаст значение counter, но не изменит само 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;
}

Он бы предупредил вас здесь и прояснил проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...