Function always returns 1

Dom324

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. However it always outputs TAKEN instead of dynamicaly changing the prediction.

#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::GetPrediction should return either TAKEN (when counter = 3 or 2) or NOT_TAKEN (when counter = 0 or 1).

PREDICTOR::UpdatePredictor is called after GetPrediction. It updates the predictor via resolveDir - resolveDir is the actual direction of the branch. If resolveDir = 1 it does saturated increment of counter (saturated means it never exceeds PHT_CTR_MAX). If resolveDir = 0 it decrements the counter.

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. My coding skills aren´t really great so I might have done something wrong - probably in the GetPrediction or UpdatePredictor function.

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). 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. Counter is updated with information from resolveDir. Lastly the global history buffer (ghr, branch history, call it what you want) is also updated.

Code of the SatIncrement and SatDecrement functions:

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.

user10605163

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.

SatIncrement(counter, PHT_CTR_MAX);

will pass the value of counter but will not modify counter itself. The return value with the new value is not used and so effectively this line does nothing. The same is true for 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:

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:

[[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.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

TOP Ranking

  1. 1

    Failed to listen on localhost:8000 (reason: Cannot assign requested address)

  2. 2

    How to import an asset in swift using Bundle.main.path() in a react-native native module

  3. 3

    Loopback Error: connect ECONNREFUSED 127.0.0.1:3306 (MAMP)

  4. 4

    pump.io port in URL

  5. 5

    Spring Boot JPA PostgreSQL Web App - Internal Authentication Error

  6. 6

    BigQuery - concatenate ignoring NULL

  7. 7

    ngClass error (Can't bind ngClass since it isn't a known property of div) in Angular 11.0.3

  8. 8

    Do Idle Snowflake Connections Use Cloud Services Credits?

  9. 9

    maven-jaxb2-plugin cannot generate classes due to two declarations cause a collision in ObjectFactory class

  10. 10

    Compiler error CS0246 (type or namespace not found) on using Ninject in ASP.NET vNext

  11. 11

    Can't pre-populate phone number and message body in SMS link on iPhones when SMS app is not running in the background

  12. 12

    Generate random UUIDv4 with Elm

  13. 13

    Jquery different data trapped from direct mousedown event and simulation via $(this).trigger('mousedown');

  14. 14

    Is it possible to Redo commits removed by GitHub Desktop's Undo on a Mac?

  15. 15

    flutter: dropdown item programmatically unselect problem

  16. 16

    Change dd-mm-yyyy date format of dataframe date column to yyyy-mm-dd

  17. 17

    EXCEL: Find sum of values in one column with criteria from other column

  18. 18

    Pandas - check if dataframe has negative value in any column

  19. 19

    How to use merge windows unallocated space into Ubuntu using GParted?

  20. 20

    Make a B+ Tree concurrent thread safe

  21. 21

    ggplotly no applicable method for 'plotly_build' applied to an object of class "NULL" if statements

HotTag

Archive