サイクル精度シミュレータを使って、各種分岐予測の実装でCoremarkの性能がどのように変化するかちょっと興味があって計ってみることにした。
サイクル精度シミュレータとしてはSniperを使用する。Sniperにはフロントエンドの分岐予測器の実装があって、これをコンフィグレーションで変更することができる。
まずは、各PCでどのような分岐予測のヒット率になっているのかを見てみよう。
class BranchPredictorStats { // 統計を格納するためのデータ構造 struct Stats { size_t correct_predictions = 0; size_t incorrect_predictions = 0; size_t totalExecutions() const { return correct_predictions + incorrect_predictions; } }; // グローバルまたはクラスメンバ変数として統計を格納するマップ std::unordered_map<IntPtr, Stats> bp_stats; public: void UpdateStats (IntPtr eip, bool prediction, bool taken) { // 分岐予測の結果を統計に反映 if (prediction == taken) { bp_stats[eip].correct_predictions++; } else { bp_stats[eip].incorrect_predictions++; } } // 統計を取得するための関数を追加 void printStats() const { // マップをベクタに変換 // マップをベクタに変換 std::vector<std::pair<IntPtr, Stats>> bp_stats_vector(bp_stats.begin(), bp_stats.end()); // 実行回数でソート(降順) std::sort(bp_stats_vector.begin(), bp_stats_vector.end(), [](const std::pair<IntPtr, Stats> &a, const std::pair<IntPtr, Stats> &b) { return a.second.totalExecutions() > b.second.totalExecutions(); }); for (const auto &entry : bp_stats_vector) { IntPtr eip = entry.first; const Stats &stats = entry.second; std::cout << "EIP: " << std::hex << "0x" << eip << std::dec << " Correct: " << stats.correct_predictions << " Incorrect: " << stats.incorrect_predictions << " Accuracy: " << (stats.correct_predictions + stats.incorrect_predictions > 0 ? static_cast<double>(stats.correct_predictions) / (stats.correct_predictions + stats.incorrect_predictions) * 100.0 : 0.0) << "%" << std::endl; } } };
one_bit
EIP: 0x80001388 Correct: 57120 Incorrect: 4080 Accuracy: 93.3333% EIP: 0x80001a40 Correct: 22680 Incorrect: 6480 Accuracy: 77.7778% EIP: 0x800019b6 Correct: 22680 Incorrect: 6480 Accuracy: 77.7778% EIP: 0x80001378 Correct: 28789 Incorrect: 161 Accuracy: 99.4439% EIP: 0x80001370 Correct: 26991 Incorrect: 1879 Accuracy: 93.4915% EIP: 0x800014d6 Correct: 27640 Incorrect: 270 Accuracy: 99.0326% EIP: 0x800014cc Correct: 26001 Incorrect: 1779 Accuracy: 93.5961%
pentium_m
EIP: 0x80001388 Correct: 60819 Incorrect: 381 Accuracy: 99.3775% EIP: 0x80001a40 Correct: 25919 Incorrect: 3241 Accuracy: 88.8855% EIP: 0x800019b6 Correct: 29158 Incorrect: 2 Accuracy: 99.9931% EIP: 0x80001378 Correct: 28928 Incorrect: 22 Accuracy: 99.924% EIP: 0x80001370 Correct: 27930 Incorrect: 940 Accuracy: 96.744% EIP: 0x800014d6 Correct: 27828 Incorrect: 82 Accuracy: 99.7062% EIP: 0x800014cc Correct: 27550 Incorrect: 230 Accuracy: 99.1721% EIP: 0x80001fb6 Correct: 15840 Incorrect: 0 Accuracy: 100% EIP: 0x80001fbe Correct: 15837 Incorrect: 3 Accuracy: 99.9811% EIP: 0x80001fca Correct: 14008 Incorrect: 792 Accuracy: 94.6486%
a53
EIP: 0x80001388 Correct: 58898 Incorrect: 2302 Accuracy: 96.2386% EIP: 0x80001a40 Correct: 29040 Incorrect: 120 Accuracy: 99.5885% EIP: 0x800019b6 Correct: 28986 Incorrect: 174 Accuracy: 99.4033% EIP: 0x80001378 Correct: 28846 Incorrect: 104 Accuracy: 99.6408% EIP: 0x80001370 Correct: 26868 Incorrect: 2002 Accuracy: 93.0655% EIP: 0x800014d6 Correct: 27732 Incorrect: 178 Accuracy: 99.3622% EIP: 0x800014cc Correct: 25763 Incorrect: 2017 Accuracy: 92.7394% EIP: 0x80001fb6 Correct: 12115 Incorrect: 3725 Accuracy: 76.4836% EIP: 0x80001fbe Correct: 12044 Incorrect: 3796 Accuracy: 76.0354% EIP: 0x80001fca Correct: 11946 Incorrect: 2854 Accuracy: 80.7162%
0x80001a40は one_bitだと非常に精度が悪いが、pentium_m / a53と徐々に改善している。
一方で、a53は0x80001fb6などの精度が悪い。
80001a40: fcd814e3 bne a6,a3,80001a08
for(k=0;k<N;k++) 80001a40: fcd814e3 bne a6,a3,80001a08 <matrix_mul_matrix_bitextract+0x26> 80001a44: 00b3a023 sw a1,0(t2)
80001fb6: 12078363 beqz a5,800020dc
for( ; *str && state != CORE_INVALID; str++ ) { 80001fb0: 00164783 lbu a5,1(a2) 80001fb4: 0605 add a2,a2,1 80001fb6: 12078363 beqz a5,800020dc <core_state_transition+0x1f8>