さて、もう一度CoreMarkの100サイクルずつの命令実行数を見てみよう。
次は1000サイクルずつの命令実行数。
1000サイクルの方が綺麗だねえ。
1000サイクルで、良くて800命令くらいで推移している。つまり1サイクル1命令ですら動けていないということ。ぬうう。 特に中央付近の400命令程度で推移している当り、何故そのようになっているのか分からないので調べてみる。
(Cm21,D29)[PC=800011e0] R07<=00000010 : sll r07,r02,r02 (42) 128662| | | | | | (Cm22,D15)[PC=800011e4] R07<=bfc001dc : addu r07,r08,r07 (29) 128663| | | | | | | | | | | | (Cm23,D52)[PC=800011e8] R07<=8000128c : lw r07,0x0000(r07)(15) 128664| | | (Cm24,D--)[PC=800011ec] : jr r07 128665|(Cm25,D--)[PC=800011f0] : sll r00,r00,r00 128666| | | | | -------------- FLUSH -------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (Cm26,D--)[PC=8000128c] : beq r03,r11,0x0048 128667|(Cm27,D13)[PC=80001290] R03<=00000000 : addiu r03,r03,0xffd0 (62) 128668| | | | | (Cm28,D20)[PC=80001294] R03<=00000001 : sltiu r03,r03,0x000a (13) 128669| | | (Cm29,D--)[PC=80001298] : bne r03,r00,0xffe9 128670|(Cm30,D--)[PC=8000129c] : sll r00,r00,r00 128671| | | | | -------------- FLUSH -------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH | | | | | | | | | | | | | | | | | | | | | | | | (Cm31,D50)[PC=80001240] R03<=00000031 : lbu r03,0x0000(r06)(20) 128672| | | (Cm32,D--)[PC=80001244] : beq r03,r00,0xfff4 128673|(Cm33,D56)[PC=80001248] R07<=7f000586 : addu r07,r06,r00 (52) 128674| | | | | (Cm34,D--)[PC=8000124c] : bne r03,r10,0xffe4 128675|(Cm35,D36)[PC=80001250] R06<=7f000587 : addiu r06,r06,0x0001 (23) 128676| | | | | -------------- FLUSH -------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH | | | | | | | | | | | | | | | | | | | | | | | | (Cm36,D49)[PC=800011e0] R07<=00000010 : sll r07,r02,r02 (56) 128677| | | | | | (Cm37,D58)[PC=800011e4] R07<=bfc001dc : addu r07,r08,r07 (49) 128678| | | | | | | | | | | | (Cm38,D07)[PC=800011e8] R07<=8000128c : lw r07,0x0000(r07)(58) 128679| | | (Cm39,D--)[PC=800011ec] : jr r07 128680|(Cm40,D--)[PC=800011f0] : sll r00,r00,r00 128681| | | | | -------------- FLUSH -------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH --------------- FLUSH -------------- FLUSH | | | | | | | | | | | | | | |
なるほど、スッカスカね。
そもそも、JR命令は分岐予測がやりにくい。レジスタ相対分岐だからだ。レジスタの値はフェッチ時点では分からないので、正しく分岐先アドレスを計算できる保証がない。 そうすると、どうしてもレジスタ関節ジャンプは常にフラッシュを走らせる方向に実装され、あまり性能向上できない。 この辺りは、コンパイラによりこのような命令が発生することを回避する最適化が必要そうね。
そして、もう一つ重要なのは、4ワード同時にフェッチしてきて、4ワード内に分岐命令が2つ以上存在する場合、後者の分岐予測は反映できていない、ということだ。 つまり、
- 命令列に{BR, OP, BR, OP}が並んでいたとして、(右側がアドレスの若い方)
- 最初のBRでヒットしない、分岐予測しないと踏んだときに、最初のビットは分岐せずシーケンシャルに次の命令を読みにいく。
- 一方、2番目のBRでヒットする場合は、予測分岐を成立させてフラッシュは発生しない。
例はこのような感じ。1244と124c(4ワード以内)に分岐命令が2ついる。この場合、前者は高確率でヒットするのだが(ジャンプしない方向に)、 後者は高確率でジャンプする、このときにその分岐予測が出来ていないようだ。これは調査しよう。
(Cm32,D--)[PC=80001244] : beq r03,r00,0xfff4 128673|(Cm33,D56)[PC=80001248] R07<=7f000586 : addu r07,r06,r00 (52) 128674| (Cm34,D--)[PC=8000124c] : bne r03,r10,0xffe4 128675|(Cm35,D36)[PC=80001250] R06<=7f000587 : addiu r06,r06,0x0001 (23) 128676|
このとき、現在の実装では、2番目の分岐命令の分岐予測が発生しても、それが利用できていない、ということだ。 これは僕も実装を確認してみたが、何かうまく検出できていないようだ。