キャッシュエミュレーションの実装
tkojima0107 opened this issue · comments
オリジナルの実装ではキャッシュらしきものはあるがdirect mapでしかも、ブロックサイズ=1のキャッシュと呼んで良いのかわからない代物。加えてライトスルー方式。
キャッシュミスペナルティも考慮したn-way associative cache化したい。
順番としては
- キャッシュとしての振る舞いをエミュレーション
- キャッシュミス時のstallを実装
という手順で進めていく。
ただし、キャッシュミス時のstallを実装するには少なくとも以下を考慮する必要がある。
- 5ステージパイプラインでは命令キャッシュとデータキャッシュでミスするステージが異なる
- 命令キャッシュはFetchスレージ
- データキャッシュはMEMスレージ
- 当然同時にミスすることも考慮しなくてはいけない
- 遅延スロットの取り扱い
- VMIPSでは厳密にパイプラインをエミュレーションできてない
- 多くはEXEステージを毎サイクル実行?
- VMIPSでは厳密にパイプラインをエミュレーションできてない
あとMIPS R3000ってデータハザードでパイプラインの停止とかインターロックって実装されてたのか忘れたから調べる
#2 を実装することを考えるとキャッシュミス時に サイクル時間 += ペナルティ
とするのではダメ
理由は以下の2つ
- キャッシュミスによるストール時にもアクセラレータは動いていなくてはいけない
- キャッシュフェッチするデータがTCIを経由したアクセラレータ内データの場合がある(TCIをちゃんとエミュレーションするならこのフェッチにかかる時間は予測不可)
16760a5 でn-way キャッシュの動作エミュレーションはできた。あとは、サイクル数をエミュレートする
8dfecc1 にてキャッシュをmapperから分離できた。
また、もともとあるDeviceExcクラスがCPUの親クラスだったので、これに
void stall(int cause);
をプロトタイプとして組み込んでみた。実際に使うとなるとこれではダメなきがするから拡張する可能性あり。
やること
- Cache::stepの実装(cache fetch/cache write back)
- mapper::readyを使ってstallをエミュレーション
- @zoubleton
- mapperにアービトレーション
- Mapper::ready()で相手に通知する (rangeインスタンスのreadyも考慮)
- アクセスの初期遅延をMapper::step()で制御
到達遅延はmapperで制御、計算による遅延はrouterで制御
- DMACの実装
- mapperにアービトレーション
stallなしでjpegした場合の結果
2757827 instructions in 0.58308 seconds (4729798.053 instructions per second) (stall ratio 1.031%)
Instruction Cache Profile
Cache Miss Ratio 0.04891%
write back ratio 0.00000%
Data Cache Profile
Cache Miss Ratio 6.48642%
write back ratio 34.27902%
やること再確認
メモリアクセスのインターフェース
Bool ready(uint32 addr, int32 mode, DeviceExc *client);
counterが0かつrange側のreadyがたったらtrueを返すvoid requstWord(uint32 addr, int32 mode, DeviceExc *client);
mapperにエントリがない場合counterを初期化、それ以外は無視 -> cpu,cache側からいくら読んでも良いuint32 fetch_word(uint32 addr, int32 mode, DeviceExc *client);
mapperのエントリを削除する
fetch_halfやstore_wordなども同様
前提
- cpuとキャッシュから同時にrequestが来ないようにする
- キャッシュのバーストアクセスを再現するには初めに全ライン分requestを飛ばし、一斉にcounterをdecrementしてもらう
キャッシュミスを考慮した結果
3751539 instructions in 0.53646 seconds (6993151.387 instructions per second) (stall ratio 27.246%)
Instruction Cache Profile
Access Count 2730713
Cache Miss Ratio 0.04889%
write back ratio 0.00000%
Data Cache Profile
Access Count 742993
Cache Miss Ratio 6.09131%
write back ratio 34.27902%
所用サイクル数が1.36倍になった。
フェッチミスの場合余分に15サイクル
データミスでライトバックありの場合31サイクル, それ以外は15サイクル余分にかかるから
フェッチのペナルティ: 2730713 * 0.00048 * 15 = 1,311
データアクセスのペナルティ: 742993 * 0.0609 * ((1 - 0.342) * 15 + 0.342 * 31) = 926,322
(2757827 + 1311 + 926322) / 2757827 = 1.33
妥当そう
ちなみにGeyser RTLシミュレーションでは
236725700: end successfully
Simulation complete via $finish(1) at time 236925700 NS + 0
../forTest/testamode.v:166 $finish;
ncsim> exit
real 1m14.382s
user 1m3.892s
sys 0m0.115s
1 cycle = 50nsなので4,734,514サイクル
オーダーは悪くない
シミュレーションにかかる時間は150倍くらい
ひとまずできたが遅い
% cumulative self self total
time seconds seconds calls us/call us/call name
99.14 87.89 87.89 3993040 22.01 22.01 Mapper::step()
0.08 87.96 0.07 3993040 0.02 0.02 CPU::pre_decode(bool&)
0.07 88.02 0.06 8041079 0.01 0.01 Cache::cache_hit()
0.07 88.08 0.06 5981261 0.01 0.02 std::_Hashtable<Mapper::RequestsKey, std::pair<Mapper::RequestsKey const, int>, std::allocator<std
::pair<Mapper::RequestsKey const, int> >, std::__detail::_Select1st, Mapper::RequestsKeyEqual, Mapper::RequestsHash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::find(Mapper::RequestsKe
y const&)
0.06 88.13 0.05 9461440 0.01 0.01 std::_Hashtable<Mapper::RequestsKey, std::pair<Mapper::RequestsKey const, int>, std::allocator<std
::pair<Mapper::RequestsKey const, int> >, std::__detail::_Select1st, Mapper::RequestsKeyEqual, Mapper::RequestsHash, std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::_M_find_before_node(uns
igned long, Mapper::RequestsKey const&, unsigned long) const
0.06 88.18 0.05 1502077 0.03 0.03 Options::optstruct(char const*, bool)
0.05 88.22 0.05 3993040 0.01 22.20 vmips::step()
0.05 88.26 0.04 2757869 0.01 0.03 CPU::fetch(bool&, bool)
0.03 88.29 0.03 3993040 0.01 0.01 CPU::pre_mem_access(bool&)
0.03 88.32 0.03 2729387 0.01 0.01 CPU::decode()
アービタの話題は #7 へ
3d22720: すべてのカウントをデクリメントするのではなく、最初のリクエスト時でのサイクル数を保持し、現在のサイクル数との差からreadyを算出するように仕様変更
a7651cf: store_wordでreadyの時リクエスト時のサイクル数を削除するように修正
1b55c04: 上に加え、readyでないときにbus_errorを起こすコミット
b14edc7: stall_emuをmerge
以下は b14edc7 を手元のMacBook Pro(Early 2015)で実行した時のシミュレーション時間
./cube_sim test_vec/jpeg.bin 0.72s user 0.01s system 98% cpu 0.740 total
速くなった。