Я пытаюсь написать простой предиктор ветвления, который должен выводить либо 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;
}
Спасибо запомощь.