FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

HiFive1のパフォーマンスカウンタについて

前回Coremarkの測定を行ったし、その前は各命令のレイテンシを測定した。 このとき、実際にプログラムのサイクル数を測定しているわけだが、これはどのようにして実現しているのだろう。

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

まず各命令のレイテンシ、スループット測定には、以下のようなサイクル取得ルーチンを使用している。

#define rdmcycle(x)  {                                 \
    uint32_t lo, hi, hi2;                              \
    __asm__ __volatile__ ("1:\n\t"                     \
                          "csrr %0, mcycleh\n\t"       \
                          "csrr %1, mcycle\n\t"        \
                          "csrr %2, mcycleh\n\t"       \
                          "bne  %0, %2, 1b\n\t"                 \
                          : "=r" (hi), "=r" (lo), "=r" (hi2)) ; \
    *(x) = lo | ((uint64_t) hi << 32);                          \
  }

これはつまり、

  1. 現在のmcyclehの値を取得し、hiに代入する。
  2. 現在のmcycleの値を取得し、loに代入する。
  3. 現在のmcyclehの値を取得し、hi2に代入する。
  4. hiとhi2を比較し、不一致ならば1.から繰り返す。

これはmcyclehがオーバフローした場合を考慮したルーチンとなっている。

例えば、

1.を実行した時点で{mcycleh,mcycle}=0x0000_0010_ffff_ffff 2.を実行した時点で{mcycleh,mcycle}=0x0000_0011_0000_0000

となった場合、最後の計算で{mcycleh,mcycle}=0x0000_0011_ffff_ffff となってしまい、大幅にサイクル数が狂ってしまう。 これを防ぐために、mcyclehを2回ロードし、変化していないことを確認してからサイクル数を計算するという訳だ。