mtkw.dev

CPU/GPUと主記憶について理解を整理

これは何

CPUやGPU内部の装置、またメモリ等の主記憶について理解をまとめました。

普段はプログラマをしていますが、CPUやGPUやメモリといったハードウェアをイメージしながら実装することは重要だと感じており理解をまとめます。まだ勉強初めなので、誤りなどあると思います。

CPU/GPUと記憶装置の全体像

PCの記憶装置の全体像

全体像としては図のようにCPUとGPUと、CPU/GPUが扱うメモリについて見ていきます。

プロセスとスレッドについて

いきなりですが、まずはプロセスとスレッドについて整理します。

プロセスとはOSが実行するプログラムのまとまりです。スレッドはそのプロセス内で命令を実行する単位です。

Process(例:Chrome)
├─ UI Thread
├─ Worker Thread
└─ IO Thread

スレッドについては「CPU Thread」と「GPU Thread」を分けて考えましょう。

  • CPU Thread:OSがCPUへスケジュールするThread
  • GPU Thread:GPU上の大量並列処理を表す論理的な実行単位

CPU ThreadはProcess内にあるThreadのことです。OSはそのThreadをCPU上へスケジューリングします。

CPU ThreadがGPU Driver/APIを通してGPUへ処理を依頼します。GPUでは、プログラム側で定義された大量のGPU ThreadをSMなどの実行資源へスケジュールし、並列に演算します。

CPU内部装置の話

CPU(Central Processing Unit)は、プログラムの命令を解釈・実行し、演算やデータ処理、他の装置の制御を行うプロセッサです。複数のCoreを持つことがあり、各Coreの中にはRegister、CPU Cache、ALU、FPUなどの実行資源があります。

Registerは、CPUコアが現在の計算や命令実行で直接使う値やアドレスを一時的に保持する記憶領域です。主記憶やCPU CacheよりもCPUの演算器に近く、非常に高速ですが容量はごく小さいです。CPU内部には複数のRegisterが存在し、それらをまとめた記憶回路をRegister Fileと呼びます。

CPU Core
├─ Register File
│  ├─ Register 0
│  ├─ Register 1
│  ├─ Register 2
│  └─ ...
├─ ALU
├─ FPU
└─ SIMD / Vector Unit

CPU Cacheは、主記憶との速度差を埋めるために、よく使うデータや命令をCPUの近くに一時保存しておく高速メモリです。
主記憶はDRAMと呼ばれる安価で大容量な記憶装置が利用されます。
CPU CacheはSRAMと呼ばれる高価で少量の記憶装置が利用されます。

ALUは Arithmetic Logic Unit(算術論理演算装置) の略です。CPUコアの中にある、整数の計算や論理演算を実際に行う演算器です。「AND・OR・XOR・NOT」といった論理演算を行います。イメージとしてはRegister -> ALU -> Registerという流れです。

FPUは Floating Point Unit(浮動小数点演算装置) の略です。CPUコアの中にある、小数を含む数値の計算を高速に行うための演算器です。イメージとしてはRegister -> FPU -> Registerという流れで処理を行います。

SIMD(Single Instruction, Multiple Data)/ Vector Unitは、複数の数値をVector Registerにまとめ、1つの命令で複数のデータに対して同じ演算を並列実行するためのCPUコア内の演算器です。
SIMDは Single Instruction, Multiple Data(単一命令・複数データ) の略です。
画像、動画、音声、行列計算など大量のデータに同じ計算を繰り返すのでSIMDとの相性が良いです。 マルチコアによる並列化とSIMDによる並列化は別物であることに注意です。

L1 Cacheや L2 CacheはCPU内部の記憶領域です。どちらもSRAMという高価で高速なメモリが利用されています。L1 Cacheは小容量ですが最も低レイテンシになるよう設計され、L2 CacheはL1より大容量である代わりにアクセスレイテンシが大きくなります。L1 CacheとL2 Cacheは各CPUコア専用になっていることが多いですが、L3は複数コアで共有されることが多いです。記憶領域としては「Register → L1 Cache → L2 Cache → L3 Cache → Main Memory(DRAM)」のように多段構成になっており、L3 Cacheは最後のキャッシュのためLLC(Last Level Cache)と呼ばれることもあります。

Memory Controllerは、CPUとDRAMの間に入り、Main Memoryへの読み書きやデータ転送を制御する回路です。現代のCPUではCPU内部に統合されていることが一般的です。

CPUでの並列処理の話

CPUでの並列処理について整理していきます。

命令レベル並列

命令レベル並列(ILP: Instruction-Level Parallelism)です。
例えば、

val a = b + c
val x = y * z

という2つの計算に依存関係がなければ1つのCoreでも複数命令を同時に実行ができます。

また、パイプラインによって複数の命令を同時に処理することができます。
パイプラインとは、1つの命令を「Fetch/Decode/Execute/Write Back」のような段階に分解し、別々の命令を各Stageで同時進行させる仕組みです。 ここで大事になるのはClock(クロック)というものです。CPU内部で処理を進めるための一定周期のタイミング信号です。「1Clock = 1命令」ではない点に注意です。

Stage 1 = Fetch       命令を取ってくる
Stage 2 = Decode      命令を解読する
Stage 3 = Execute     実際に演算する

Clock 1   命令A → Stage 1
Clock 2   命令A → Stage 2
          命令B → Stage 1
Clock 3   命令A → Stage 3
          命令B → Stage 2
          命令C → Stage 1

パイプライン化しておけば、ALU/FPU/SIMDなどの実行ユニットでの実行に至るまでにはFetchやDecodeといった処理を同時実行ができます。

SIMDによる並列

前述にもありましたが、SIMDという実行ユニットを利用すると1つの命令で複数データを並列計算できます。

Vector Register A
[ 1 |  2 |  3 |  4 ]

Vector Register B
[10 | 10 | 10 | 10 ]

          ↓

    SIMD / Vector Unit

          ↓

[11 | 12 | 13 | 14]

ILPは複数命令を並行処理するアプローチでしたが、SIMDは1つの命令で複数データを並列計算します。

SMTによる並列

SMT(Simultaneous Multithreading) です。IntelのHyper-Threadingが有名です。

Physical Core
│
├─ Hardware Thread 0
└─ Hardware Thread 1

これは物理的には1Coreでも、OSからは2つの論理CPUに見せる技術であり、当然2つの物理Coreになったわけではありません。
CPU内の演算資源を遊ばせにくくすることを目的としています。

複数コアによる並列処理

物理的に別々のコアを利用して同時に処理することです。一般的にプログラマが意識するマルチコアによる並列処理はこれにあたります。

GPU内部の話

GPU(Graphics Processing Unit)は、同じ種類の計算を大量のデータに対して並列に実行するのが得意なプロセッサです。もともとは画面描画や3Dグラフィックス向けに発達しましたが、現在は画像処理、動画処理、機械学習、行列計算などにも広く使われます。

GPUではCPUと異なりコアという呼び方はしません。NVIDIAであればSM(Streaming Multiprocessor)、AMDではCU(Compute Unit)という呼び方をします。以降はSMで記述します。

1つのSMの中には、大量のGPU Threadを支えるための大きなRegister Fileと、それらThreadでの命令を実行する多数の演算装置があります。

GPUにはSIMT(Single Instruction, Multiple Threads)という実行を行います。SIMTでは、多数のThreadをグループ化し、それらのThreadに同じ命令を実行させながら、それぞれ異なるデータを処理します。

例えば、画像処理で100万pixelに全て補正するとします。

Pixel 0 → +10
Pixel 1 → +10
Pixel 2 → +10
Pixel 3 → +10
...

各pixelの値は異なりますが、やっている演算は全部+10です。

このような場合、

Thread 0 ─┐
Thread 1  ├→ 同じ ADD 命令
Thread 2  ┤   ただし扱うデータはそれぞれ違う
...       │
Thread 31 ┘

大量のGPU Threadを定義し、それらを多数のSM・演算器で並列に実行できます。

一方で、CPUは複雑な処理が得意です。

if (user.isAdmin) {
    ...
} else if (user.isGuest) {
    ...
} else {
    ...
}

分岐の多い処理はCPUが得意であり、前の結果に強く依存する逐次処理が得意です。

L1 Cacheは「各SMの近くにあるローカル寄りの高速Cache」、L2 Cacheは「GPU全体で共有される、より大きなCache」という位置付けです。どちらもSRAMであり、CPUのキャッシュと考え方が同じです。

CPUの主記憶

CPUの文脈での主記憶は一般にMain Memoryと呼ばれ、実態としてはDRAMが使われます。CPUがプログラムを実行するときに実行中のコードやデータは主にMain Memoryに配置されます。Main Memoryには、DRAM系メモリとして主にDDRやLPDDRが利用されます。

DDR(Double Data Rate)は、PCやサーバーなどによく利用されます。

LPDDR(Low Power Double Data Rate)は、省電力性を重視してスマートフォンやノートPCでよく利用されます。

GPUの主記憶

GPUの文脈での主記憶はGPUが大量のデータを置いておくメモリ領域でVRAM(Video Random Access Memory)と呼ばれています。Videoとついていますが用途は映像に限定されません。VRAMには現在、GDDR系とHBM系の2種類が利用されています。

GDDR(Graphics Double Data Rate) は、GPU向けに高いデータ転送速度を実現したDRAMです。GPUの周囲に複数のメモリチップを配置する構成が一般的で、GDDR6やGDDR7などの世代があります。HBMと比較すると比較的低コストで、コンシューマ向けGPUなどに広く利用されています。

HBM(High Bandwidth Memory) は、複数のDRAMダイを縦方向に積層し、非常に広いメモリインターフェースを使うことで高いメモリ帯域を実現するDRAMです。コストは高くなりますが、AIアクセラレータやHPC向けなど、高いメモリ帯域が求められるGPUで利用されています。

AIアクセラレータは、AI・機械学習、とくに行列計算やTensor計算を高速化するためのプロセッサです。GPUもその代表例で、ほかにもTPUやNPUなどがあります。たとえば生成AIでは、巨大なモデルの重みや中間データをメモリから大量に読み出して行列計算するので、演算性能だけでなくメモリ帯域も非常に重要です。

HPC(High Performance Computing)は、大規模な数値計算やシミュレーションを高速に処理する高性能計算の分野です。HPC用途では高性能GPUが利用されることがあります。

CPU/GPUと主記憶の主なメーカー

CPU/GPUと主記憶の主なメーカー

  • CPU → Intel / AMD
  • GPU → NVIDIAが圧倒的
  • DRAM全般 → Samsungが最大手
  • HBM → SK hynixが圧倒的に強い.

ざっくりこのような位置関係と理解しました。今後各企業についても調べていきたいと思います。
スマホ・PC・サーバーなど用途によって違うと思うので、単純に比較はできないと思うので、今後調査していきたいと思いました。