FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

分岐予測の評価キット Branch Prediction Championship Kit を試す (9. Hashed Perceptronについて1)

Branch Prediction Championship Simulatorの続きを試す。

Hashed Perceptronという分岐予測器について勉強する。論文は以下を参照している。

ieeexplore.ieee.org

とりあえず細かいことは無視してソースコードを読んでみるのがいい気がする。そのあとで論文を読んでみよう。

概要としては、TAGEと似たような複数長の分岐ヒストリを使うようなものに思える。

github.com

複数長のヒストリを持っているのだが、どこまでの長さのヒストリを使ってハッシュ値を生成するか、 というのを別々に切り替えて生成しているように見える。

#define NTABLES 16

// geometric global history lengths
int history_lengths[NTABLES] = {0, 3, 4, 6, 8, 10, 14, 19, 26, 36, 49, 67, 91, 125, 170, MAXHIST};

// 12-bit indices for the tables
#define LOG_TABLE_SIZE 12
#define TABLE_SIZE (1 << LOG_TABLE_SIZE)

// this many 12-bit words will be kept in the global history
#define NGHIST_WORDS (MAXHIST / LOG_TABLE_SIZE + 1)

// tables of 8-bit weights
int tables[NUM_CPUS][NTABLES][TABLE_SIZE];

// words that store the global history
unsigned int ghist_words[NUM_CPUS][NGHIST_WORDS];

この例だと重みテーブルは16個、それぞれ4096エントリを持っている。

そしてそれぞれの16個のテーブルのどこにアクセスするのかを決めるのだが、230ビット近くあるGHRを細かく区切りながらハッシュ関数を計算し、 PCだけで計算するか、近場のGHRの相関を使用するか、どんどん遠くの相関を使用するか、というのを決めている。

そして16個のテーブルで使用するGHRを等比数列的に配置することで、等差数列的に配置するよりも効率的にテーブルを探索できるようにしている。

bool PREDICTOR::GetPrediction(uint64_t pc)
{

  // initialize perceptron sum

  int cpu = 0;

  yout[cpu] = 0;

  // for each table...
  for (int i = 0; i < NTABLES; i++) {

    // n is the history length for this table
    int n = history_lengths[i];

    // hash global history bits 0..n-1 into x by XORing the words from the
    // ghist_words array
    unsigned int x = 0;

    // most of the words are 12 bits long
    int most_words = n / LOG_TABLE_SIZE;

    // the last word is fewer than 12 bits
    int last_word = n % LOG_TABLE_SIZE;

    // XOR up to the next-to-the-last word
    int j;
    for (j = 0; j < most_words; j++)
      x ^= ghist_words[cpu][j];

    // XOR in the last word
    x ^= ghist_words[cpu][j] & ((1 << last_word) - 1);

    // XOR in the PC to spread accesses around (like gshare)
    x ^= pc;

    // stay within the table size
    x &= TABLE_SIZE - 1;

    // remember this index for update
    indices[cpu][i] = x;

    // add the selected weight to the perceptron sum

    yout[cpu] += tables[cpu][i][x];
  }
  return yout[cpu] >= 1;
}
   MPKBr_1K           :   133.0000
   MPKBr_10K              :    23.0000
   MPKBr_100K             :     3.8600
   MPKBr_1M           :     1.5290
   MPKBr_10M              :     1.1278
   MPKBr_30M              :     1.0278
   TRACE      : ../traces/SHORT_MOBILE-24.bt9.trace.gz
   NUM_INSTRUCTIONS               : 1000000000
   NUM_BR                         :   38684342
   NUM_UNCOND_BR                  :    2221649
   NUM_CONDITIONAL_BR             :   36462693
   NUM_MISPREDICTIONS             :      39017
   MISPRED_PER_1K_INST            :     0.0390

分岐命令の実行毎にテーブルがどのように更新されるのか、簡単に見て行こうと思う。