43
あなたのお家に届くまで CPUキャッシュアーキテクチャ入門(その1Dora. Panda October 18th, 2014

Cpu cache arch

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Cpu cache arch

あなたのお家に届くまでCPUキャッシュアーキテクチャ入門(その1) !

Dora. Panda October 18th, 2014

Page 2: Cpu cache arch

今日のお題

CPUがデータを読み込むまでの長い長いお話です。

ソフトウェアからは見ることのできないCPU内部動作について説明します。

Page 3: Cpu cache arch

ハードウェア構成左図の構成で説明を進めます

CPUによって実装が異なるので、機種固有の説明は省きます。

私なりに考えた「キャッシュの基礎を理解する」ための仮想CPUです。

「そこそこ」ワーストケースで考えます。

TLBヒット、L1、L2キャッシュはミスヒット。

細かい用語は後ほど。

ChipProcessor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 4: Cpu cache arch

メモリからロードしてみよう

例えば、以下のC言語プログラム上は左の赤枠のような命令に置き換えられます。

!

※ARM命令の場合

int hoge = *__bss_start__;

Page 5: Cpu cache arch

–The Little Prince

“Le plus important est invisible” “大切な物は目に見えないんだよ”

メモリからデータを読み出し、CPUレジスタにロードされるまで 長い旅路の物語

Page 6: Cpu cache arch

と、その前に…レジスタって?

パソコン初心者向け説明

CPUはメモリに情報を置く

メモリに入りきらないときはHDDに退避

CPU

DRAM HDD

Page 7: Cpu cache arch

レジスタ=CPU内部のメモリ領域CPUはレジスタのデータに対してのみ演算可能。

メモリの値を直接制御できない。

データ読み出しはメモリからレジスタに転送し、レジスタを読む。

データ書き込みはレジスタに書き、レジスタの内容をメモリに転送する。

CPU

DRAM HDD

演算回路

レジスタレジスタ

キャッシュ

Page 8: Cpu cache arch

MEMORY MANAGEMENT UNIT

About MMU ChipProcessor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 9: Cpu cache arch

MMU

CPUがデータをロードするとき、MMUに対してアドレスを出力します。

MMUでは仮想メモリと物理メモリ変換を行います。

TLBというアドレス変換情報キャッシュがあります。

CPU Core

MMU仮想アドレス 物理アドレス仮想アドレス 物理アドレス仮想アドレス 物理アドレス

仮想アドレス 物理アドレス

仮想アドレス

物理アドレス

Page 10: Cpu cache arch

物理アドレスと仮想アドレス物理アドレス

連続的な実際のアドレス。

仮想アドレス

OSが実行時に動的に割り当てるアドレス

ページ単位の割り当て

4kB、16kB、64kBなど。

不連続なページを連続的に見せる。

プロセス毎に独立したアドレス

あるプロセスからほかのプロセスのアドレスにはアクセス不可。(メモリ保護)

物理アドレス 仮想アドレス

Page 11: Cpu cache arch

MMU

仮想アドレス(32bit)00000000000 00000000000 000000000000

仮想~物理アドレス変換

Page Table物理アドレス

物理アドレス(32bit)00000000000000000000 000000000000

Page TablePage Table

Page TablePage Table

物理アドレス物理アドレス物理アドレス

Page Table Entry(PTE)を使ってアドレス変換

TLBはPTEのキャッシュ

TLBミスヒット時はPTEを検索

エントリ数は32~128個程度

PTEミスヒット時はページイン(Disk

-> RAM)

Page 12: Cpu cache arch

LEVEL 1 CACHE

About Level 1 Cache Processor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 13: Cpu cache arch

LEVEL 1 CACHE

CPUが最初にアクセスするメモリ領域

一番高速&一番サイズが小さいメモリ

CPUクロックと同一クロックで読み書き可能

数k~数100kBytes程度

MMU

物理アドレスLevel 1 Cache

データ物理アドレスデータ物理アドレスデータ物理アドレス

データ物理アドレス

Miss Hit Hit

Page 14: Cpu cache arch

DETAILS OF CACHE

Level 1 Cache

アドレス00000000000000000 000000000 000000

データ(1 word)00000000 00000000 00000000 00000000

Cache Entry Table

タグ(上位アドレス) データタグ(上位アドレス) データタグ(上位アドレス) データ

タグ(上位アドレス) データ

=?

データ1

1 word (4bytes)

データ2

データ3

データn①

②③

01

511

Page 15: Cpu cache arch

CACHE ALGORITHMtypedef struct { unsigned long tag; int data[8]; } CLine; !typedef struct { CLine entry[512 / (8 * sizeof(int)]; // 16 line } ETable; ETable cache; !bool GetData(int* adrs, int *data) { unsigned long i = (adrs & 0x000001E0) >> 5; ! if (cache.entry[i].tag == adrs & 0xFFFFFE00) { *data = cache.entry[i].data[adrs & 0x0000001F]; }

キャッシュ :512バイト ラインあたりのワード数 :8ワード ライン数 :16ライン

~キャッシュの動作をC/C++で表現してみました~

Page 16: Cpu cache arch

CACHE ALGORITHMtypedef struct { unsigned long tag; int data[8]; } CLine; !typedef struct { CLine entry[512 / (8 * sizeof(int)]; } ETable; ETable cache; !bool GetData(int* adrs, int *data) { unsigned long i = (adrs & 0x000001E0) >> 5; ! if (cache.entry[i].tag == adrs & 0xFFFFFE00) { *data = cache.entry[i].data[adrs & 0x0000001F]; }

・タグ :0xFFFFFE00

・インデックス :0x000001E0

・ライン内オフセット :0x0000001F

アドレスからインデックスを抽出

Page 17: Cpu cache arch

CACHE ALGORITHMtypedef struct { unsigned long tag; int data[8]; } CLine; !typedef struct { CLine entry[512 / (8 * sizeof(int)]; } ETable; ETable cache; !bool GetData(int* adrs, int *data) { unsigned long i = (adrs & 0x000001E0) >> 5; ! if (cache.entry[i].tag == adrs & 0xFFFFFE00) { *data = cache.entry[i].data[adrs & 0x0000001F]; }

・タグ :0xFFFFFE00

・インデックス :0x000001E0

・ライン内オフセット :0x0000001F

アドレスからタグを抽出して比較

Page 18: Cpu cache arch

CACHE ALGORITHMtypedef struct { unsigned long tag; int data[8]; } CLine; !typedef struct { CLine entry[512 / (8 * sizeof(int)]; } ETable; ETable cache; !bool GetData(int* adrs, int *data) { unsigned long i = (adrs & 0x000001E0) >> 5; ! if (cache.entry[i].tag == adrs & 0xFFFFFE00) { *data = cache.entry[i].data[adrs & 0x0000001F]; }

・タグ :0xFFFFFE00

・インデックス :0x000001E0

・ライン内オフセット :0x0000001F

アドレスからライン内オフセットを抽出

↑ここはちょっと変だけど許してね

Page 19: Cpu cache arch

Cache Entry TableCache Entry Table

Cache Entry TableCache Entry Table

タグ(上位アドレス) データタグ(上位アドレス) データタグ(上位アドレス) データ

タグ(上位アドレス) データ

N-WAY ASSOCIATEVE CACHE

nウェイアソシアティブ

キャッシュを複数(n)毎持つ

ダイレクトマップの欠点を解決

同一インデックスに対して複数エントリを持つことでヒット率向上。

アドレス000000000000000000 000000000 00000

=?Hit or Miss ?

Page 20: Cpu cache arch

MISS HIT!

キャッシュ内のデータをライトバック

データを読み込むためのキャッシュエントリを確保するため。

LRU/ランダム/ラウンドロビン

L2キャッシュから読み出し

読み出し終わるまでCPUはストール(パイプライン完全停止)

L2 Cache

Level 1 Cacheデータ物理アドレスデータ物理アドレスデータ物理アドレス

データ物理アドレス

Page 21: Cpu cache arch

LEVEL 2 CACHE

About Level 2 Cache Processor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 22: Cpu cache arch

LEVEL2 CACHE SEQUENCE

Address

確定Tag

出力比較

Data出力

確定

Bus ClockL1 Cacheがアドレスを出力

L2 cacheがアドレスを確定

Tag読み出し制御

Tagが出力される

Tag比較 -> Hit !

Data読み出し制御Dataが出力される

L1 Cacheへデータを返す

読み出しに8 Clock必要

Page 23: Cpu cache arch

DYNAMIC RANDOM ACCESS MEMORY

About DRAM Processor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 24: Cpu cache arch

外部デバイスアクセス

DRAMは外部デバイス

制御用のHWが必要

非常に低速

CPUクロックの5~10分の1

Page 25: Cpu cache arch

DDR3-SDRAM READ TIMING参考資料: http://www.samsung.com/global/business/semiconductor/file/product/ddr3_device_operation_timing_diagram_rev121.pdf

10 Clock@8wordバーストリード(キャッシュ1ラインフィルに相当)

Page 26: Cpu cache arch

DDR3-SDRAM STATE CHART

DDR3-SDRAMの内部状態遷移図

HW IPとして提供されることが多いのでこれを理解している人は少ないと思います。

重要キーワード

ModeRegister

プリチャージ

リフレッシュ

Page 27: Cpu cache arch

DRAMとキャッシュDRAMはキャッシュに接続される前提で機能実装

ラインフィルに必要なバーストモード

全てシングルアクセスすると致命的に遅い

要求されたデータから順にリード可能

Single Word Read = 7 Clock/Word

8 Words Burst Read = 1.25 Clock/Word (10 Clock / 8 Words)

DRAMとキャッシュは密接な関係にあります

Page 28: Cpu cache arch

ヒット率と アクセス時間に関する考察

Consideration Processor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 29: Cpu cache arch

CPUの待ち時間

今までのワーストケースで1wordを読み出す時間を計算 tL1 = 1 Clock tL2 = 16 Clock (8 × 2CPUの半分のクロックで動作と過程)

tDDR3 = 28 Clock (7 × 4 CPUバスの半分のクロックで動作と過程)

tAllMiss = tL1 + tL2 + tDDR3 = 45 [Clock] CPUやシステムによって上記の値は全然違います。 実際の値を適用すると、もっとすごいことになります。

http://www.7-cpu.com/cpu/Cortex-A9.html

Page 30: Cpu cache arch

キャッシュヒット率を考慮キャッシュヒット率(仮定)

L1、L2ともにhit率 = 90.0%と仮定。 Avarage Access Time = tL1×0.9 + tL2 × (1 - 0.9) + tDDR3 × (1 - 0.9) × 0.9 = 4.22[clock]

バスクロックが遅いと? 同一クロックであっても外部バス速度が遅いCPUがあります。 例:Core2Duo 667MHz、Celeron 533MHz

Avarage Access Time = tL1×0.9 + (tL2 × (1 - 0.9) + tDDR3 × (1 - 0.9) × 0.9) × 667/533 = 5.05[clock] ざっくり計算です。

Page 31: Cpu cache arch

キャッシュやメモリ制御回路が 大部分を占めます。

Page 32: Cpu cache arch

実験してみよう

Study Processor

CPU Core

L2 Cache

Mem Ctrl

DRAM

PCIe

HW…

MMU

L1 Cache

Page 33: Cpu cache arch

Intel Performance Counter Monitorで実験してみましょう。

通常のループ

残念なループ

ブロッキング

アンローリング

行列計算

フォールスシェアリング

Page 34: Cpu cache arch

通常のループsrc[row] += dst[row][col]

dstのサイズ>>キャッシュ

キャッシュ1ラインのワード数ごとにキャッシュミスヒット。

0

1

src

9

row0 0

1

dst65535

1 0

9 65534

9 65535

row col

キャッシュ サイズ

for (unsigned long row = 0; row < ROW_SIZE; row++) { for (unsigned long col = 0; col < COL_SIZE; col++) { *(dst + row) += *(src + row * COL_SIZE + col); } }

Page 35: Cpu cache arch

残念なループrowのインクリメントを先にする。

インクリメント>>キャッシュ

毎回ミスヒットする。

0

1

src

9

row0 0

1

dst65535

1 0

9 65534

9 65535

row col

キャッシュ サイズ

for (int col = 0; col < COL_SIZE; col++) { for (int row = 0; row < ROW_SIZE; row++) { *(dst + row) += *(src + row * COL_SIZE + col); } }

Page 36: Cpu cache arch

ブロッキングキャッシュサイズの範囲内で一通り処理する。

終わったら次の領域に移る。

ミスヒットが格段に減る。

0

1

src

9

row0 0

1

dst65535

1 0

9 65534

9 65535

row col

キャッシュ サイズ

for (int Blk = 0; Blk < COL_SIZE; Blk += BLKSIZE) { for (int row = 0; row < ROW_SIZE; row++) { for (int col = Blk; col < Blk + BLKSIZE; col++) { *(dst + row) += *(src + Blk * BLKSIZE + col); } } }

ブロックサイズ

Page 37: Cpu cache arch

ループアンローリングループ処理を展開して分岐命令を削減

展開しすぎるとプログラムが大きくなり、命令キャッシュミスが増える

for (unsigned long row = 0; row < ROW_SIZE; row++) { for (unsigned long col = 0; col < COL_SIZE;) { *(data_dst + row) += *(data_src + row * COL_SIZE + col++); *(data_dst + row) += *(data_src + row * COL_SIZE + col++); *(data_dst + row) += *(data_src + row * COL_SIZE + col++); …略… *(data_dst + row) += *(data_src + row * COL_SIZE + col++); } }

処理 インクリメント 分岐判定処理 インクリメント 分岐判定

処理 インクリメント 分岐判定

処理 インクリメント

処理 インクリメント

処理 インクリメント

……

実行命令数が減る =処理時間も減る

プログラムサイズは 増える

Page 38: Cpu cache arch

行列計算

普通にアルゴリズムを書くと、先ほどの「普通のループ」と「残念なループ」の組み合わせになる。

片方をわざと行列を入れ替えて定義する

int A[row][col]; int B[col]row];

int A[row][col]; int B[row][col];

Page 39: Cpu cache arch

フォールスシェアリング

複数のスレッドが同一キャッシュラインのデータにライトアクセスするときに発生し得る問題。

Core1 Core2

Cache Line Cache Line

DRAM

Core 1とCore2は異なるアドレスにライトする。

アドレスは異なるが、キャッシュラインは同一。

Core1がデータを書き換える。

他コアもキャッシュしているため、DRAMにライトバック。

Core2はDRAMとキャッシュが不一致のため、キャッシュされていたデータは「無効(データ無し)」とする。

Core2がデータを書き換える。

ミスヒットが発生し、DRAMからデータを読み出す。

Page 40: Cpu cache arch

フォールスシェアリング解決策

複数のスレッドで共有する必要の無いデータはアドレスが64バイト以上離れるようにする。

Core1 Core2

Cache Line Cache Line

DRAM

void worker_thread1(void) { for (int i = 0; i < MAX; i++) dstArea[0] += srcArea[i]; } !void worker_thread2(void) { for (int i = 0; i < MAX; i++) dstArea[1] += srcArea[i]; } !void worker_thread3(void) { for (int i = 0; i < MAX; i++) dstArea[64] += srcArea[i]; }

thread1と2はフォールスシェアリング thread1と3は無し

Page 41: Cpu cache arch

実験結果:ループ「残念なループ」はキャッシュヒット率が低く、DRAMアクセスが多い。

「ブロッキング」はDRAMアクセスが少ない。

簡単なプログラムのため差が出にくかったかも。

テストプログラム以外のプロセスのカウント値も含まれていると思われます。

時間 L1 HIT DRAM READ

普通 1.68 99.82 5542MB

残念 14.09 89.54 41100MB

ブロッキング

1.63 99.95 283MB

アンローリング

1.62 99.91 5460MB

Page 42: Cpu cache arch

実験結果:行列計算/シェアリング

行列を入れ替えるとキャッシュヒット率が向上しDRAMアクセスが減る。

フォールスシェアリングを回避することによりDRAMアクセスが半分になっている。

「ループ」、「行列計算」、「シェアリング」はそれぞれ異なるテストプログラムを実行しています。

時間 L1 HIT DRAM READ

通常 13.33 92.30 49.8GB

行列入れ替え

2.06 99.75 10.7GB

時間 L1 HIT DRAM READ

FALSE SHARE 10.54 95.42 926MB

NONE SHARED 4.62 98.77 421MB

Page 43: Cpu cache arch

参考資料アーキテクチャ全般

David A.Patterson/John L.Hennessy; パターソン&ヘネシー コンピュータの構成と設計 第4版,

日経BP社, 2011年.

中森 章; マイクロプロセッサ・アーキテクチャ入門, CQ出版, 2004年.

CPU実例

ARM

Cortex-A9 テクニカルリファレンスマニュアル, r2p2

CoreLink Level 2 Cache Controller L2C-310 Technical Reference Manual, r3p3

Intel

Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3A: System Programming Guide, Part 1

Intel® 64 and IA-32 Architectures Optimization Reference Manual

Performance Analysis Guide for Intel® Core™ i7 Processor and Intel® Xeon™ 5500 processors