未来のいつか/hyoshiokの日記

hyoshiokの日々思うことをあれやこれや

CacheのABC

Computer Architecture, Third Edition: A Quantitative Approach (The Morgan Kaufmann Series in Computer Architecture and Design) (CA:AQA)によればメモリアクセス性能を上げるには

平均メモリアクセス時間=ヒット時間+キャッシュミス率*ミスペナルティ

となるので、ヒット時間(キャッシュにヒットした時のアクセス時間)をさらに短くするか、キャッシュミス率を下げるか、ミスペナルティ(キャッシュミスした時のアクセス時間)を下げるという方法がある。例えばL1ヒット時間が1ns(ナノセカンド、10億分の1秒)でL2ヒット時間が5ns、メインメモリアクセスが150nsで、L1ヒット率が9割、L2ヒット率が9%、とすると、

平均メモリアクセス時間=1 + 0.1*(5 + 0.1*150)=1 + 0.1*(5+15)=1+2=3ns

となる。これがL1ヒット率が5割で、L2ヒット率が25%、25%がメインメモリにアクセスするとなると、

平均メモリアクセス時間=1 + 0.5*(5 + 0.5*150)=1 + 0.5*(5+75)=1+40=41ns

10数倍時間がかかるようになる。L1/L2/メインメモリへのアクセス時間はハードウェアによって決定されるので、キャッシュミス率を下げる事が性能向上の要となる。
CA:AQAの分類によってメモリアクセス時間を削減する方法を紹介すると

  1. キャッシュミスの削減
    1. ブロックサイズの拡大
    2. 連想度向上
    3. Victimキャッシュ
    4. Pseudo-Associativeキャッシュ
    5. ハードウェアによるプリフェッチ
    6. コンパイラによるプリフェッチ
    7. コンパイラによる最適化
  2. キャッシュミスペナルティの削減
    1. 読みミスを書きミスより優先
    2. サブブロック置き換え
    3. early restart/critical word first
    4. ブロックしないキャッシュ
    5. 2次キャッシュ
  3. キャッシュヒットした時のアクセス時間の削減
    1. 小さいキャッシュ
    2. アドレス変換を避ける
    3. 書き込みのパイプライン

になる。棒読みした感じではあるが、ソフトウェアで制御できるのは、プリフェッチとかコンパイラによる最適化くらいなものである。
プリフェッチは文字通り、データが必要になる前にあらかじめデータをフェッチしておこうというものである。キャッシュにプリフェッチしたり、レジスタにプリフェッチしたりする。レジスタのプリフェッチというのは、単にメモリにアクセスしているだけなのだが、キャッシュミスをしても、その間他の命令が実行されていればデータが本当に必要になった時点までにデータを準備できればミスペナルティはなくなる。最近のプロセッサだとキャッシュミスをしても他の命令がストールすることなく実行できるので、このようなテクニックが使える。
ソフトウェアの最適化では、配列のマージ、ループの置換、ループの融合、ブロッキング、などのテクニックが紹介されている。CA:AQAにはcache pollutionという言葉は索引にも載っていなかったので、Intelの言葉なのかもしれないが(Hyper Threadingのように)、ひょっとしたらCA:AQAでは未知のテクニックなのかもしれない。