chroot("/home/hibari")

備忘録とかに使えそうなノート

Intel Ice Lakeのプロセッサは整数除算命令がアツい

特に理由はないのですが,intelのIce Lakeのプロセッサに対して謎の高揚感等を感じている.

Ice Lakeというコードネームのプロセッサの代表的な特色として,AI推論命令セットとなるIntel Deep Learning Boostであったり,グラフィック機能も持った10nm製造プロセスなどなど,満載感があふれている.

 

しかしこのアーキテクチャにはあまり表沙汰になっていない進化もしており,なんとinteger dividerのレイテンシも低減させているという.

除算命令,もといdiv命令系はもともとレイテンシが大きく,四則演算の中でもadd, sub, mulと比較しても処理が重い命令として有名である.そんな除算命令のレイテンシが抑えられたというのであれば,これは進化といえるであろうと思う.

ということで,今回はこのdividerに着目し,実際に動かしてみてこの目で確かめてみようではないかというのが記事の目的である.

今回の評価では,除算命令が高速化されていそうである,というのが分かる程度の計測を行う.厳密なレイテンシの計測などのレベルになるととても難しい上にしんどいので...

 

雑に実装

というわけで,符号付きの除算命令であるidiv命令について簡単に計測しようと思う.

そのために,以下のようなidiv命令をひたすら実行しまくるような素晴らしく単純なインラインアセンブリを記述した.

 

        __asm__ volatile(
            "mov $156707, %rax;"
            "mov $9999883, %rcx;"
            "mov $-1, %r10"
        );

        for(i=0; i<N; i++){
            __asm__ volatile(
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                "mov %%r10, %%rdx;"
                "idiv %%rcx;"
                ::: "rax", "rdx", "rcx", "r10"
            );
        }

 

被除数である rdx:rax のrdxには-1,raxには適当な素数を入れておき,除数であるrcxにも適当な素数を入れておいた.

ループ内でアンローリングしているような書き方をしているのは,一回idivをやるたびにcmpとjmpをするのもなあという適当な勘によるもの.

また,idivを実行するたびにrdxに-1をいちいち入れているのは,idiv命令を実行したあとのrdxレジスタには計算結果の剰余が入り,そのまま被除数の上半分として引き継いで次のidiv命令を実行すると,場合によってはfloating point exceptionが発生して落ちるからである.要するに,「念の為」である.

 

実験

今回の実験では,Nは1000万とした.つまり,idiv命令は1億回実行されることになるはずである.

またコンパイルオプションには-O3を指定し,for文のカウンタもレジスタのみで済ませていただくようにした.

 

その前に

今回のタイトルでは,Ice Lakeプロセッサと言っているが,そんなものが手元にあるのかと言われると執筆現在においては所持していない.

ではこの実験が出来ないのか,と言われると実はそうではない.

Intelが出しているプロセッサの1つに,Cannon Lakeプロセッサという10nm製造プロセスのプロセッサが,実はしれっと存在している.このプロセッサはIce Lakeの前身的なものであり,個人的にはIce Lakeの試作品のものと思っている.

現にCannon Lakeに分類するプロセッサは1つしか出荷されていない.

しかし,試作品のようなものであれば,Ice Lakeと似たアーキテクチャをしているのではないかということで,今回の実験に至った.

 

使用プロセッサ

使用したプロセッサは以下の2つである.

  • Intel(R) Core(TM) i7-7820X CPU @ 3.60GHz (Skylake-X)
  • Intel(R) Core(TM) i3-8121U CPU @ 2.20GHz (Cannon Lake)

 

要するにdividerの進化前と進化後を比べてみようというもの.

見ての通りそれぞれ動作周波数が異なるため,単純に実行時間で比較するのはさすがにと思ったため,今回はTime Stamp Counter(TSC)を使用し,idivしまくる部分をrdtscp命令を使って実質クロック数の観点で比較した.

 

実験結果

  • Skylake

$ ./a.out
diff = 4915734904 

  • 実質Ice Lake(Cannon Lake)

$ ./a.out
diff = 1067339400 

ざっくり5分の1程度のクロック数でidiv命令が処理された.

さらにこの実験してて明確に実行時間に違いを感じたので,timeにかけて再度実行してみた結果が以下である.

  • Skylake

$ time ./a.out

diff = 4923881440
real 0m1.369s

user 0m1.368s

sys 0m0.000s

  • 実質Ice Lake(Cannon Lake)

$ time ./eval

diff = 1067358772
real 0m0.487s

user 0m0.483s

sys 0m0.004s

 

実行時間の観点では,Ice Lake(Cannon Lake)がSkylakeに対しておよそ3分の1程度の実行時間で整数除算を処理した.

つまり,

「Ice Lakeプロセッサに進化したことによって整数除算のレイテンシが軽減され,ある程度低周波でも高周波数の進化前プロセッサよりも高速に除算を処理することができる」

ということがわかった.

 

このゆるふわ実験から,整数除算命令が高速化されていることが確認された.相当integer dividerを改良したんだなあ.