はじめに
Nginxのmainブロック内に worker_processes があり、これについて深堀りしていく中で、そもそもCPUについて言語化出来る知識がない事に気づき、改めて調べてみようと思いました。
自分へのメモの意味合いが強い記事ですが、何かひとつでも参考になれば幸いです。
対象者
- 未来の自分
- CPUのざっくりとした知識が欲しい方
参考CPU
Intel Core Ultra Processors (Series 2)
基本的な項目
コア
原則1つの命令ストリーム(パイプライン+アウトオブオーダーの実行)を実行できるもので、作業員のようなイメージ
コアにも種類があり、Intelには下記2つがある(AMDは一般向けRyzenは基本的には均一コア構成)
・ Pコア: 高性能・高負荷処理。ゲームや動画編集などの用途。基本1コアあたり2スレッドのハイパースレッディング(HT)対応
・ Eコア: 軽いタスクを効率的に処理。ブラウザやメールなど。HT非対応なので、1コア1スレッド
※ただし、今回参考にした最新のCore Ultra (Series 2)では、電力効率や構造見直しの観点からPコアのHTが廃止され、1コア1スレッドとなっています
スレッド
HTがある場合は1コアあたり2スレッド、つまり、2つの処理を同時並行出来る
実際の命令処理では、机のすべてを使用している訳ではないので、空いているエリアも使って別の命令を走らせる
コアが同時に担当出来る作業レーン数のようなイメージで、8コア16スレッドであれば、物理的なコア数は8個だが、1コアあたり2スレッド(HT)で、論理コア数は16個となる
ただ、物理性能が2倍になるのではなく、実際には1.2~1.4倍程度に押し上げる技術
故に、10コア20スレッドと20コア20スレッドでは、同じスレッド数でも性能は違う
軽いタスクが大量にある場合は、HTがある方が効率が上がる場合が多い
クロック
CPUが1秒間に刻む動作リズムのようなもので、1秒間の命令回数ではない
クロック周波数とも言い、3.0GHz(30億回)と表記される(クロック信号の周期数)
数値が大きければ1秒間に刻む回数が多い
実際の処理性能は次に紹介するIPCとコア数の兼ね合いになる
性能 = クロック × IPC × コア数 (メモリ待ちがあるので、実際には理論通りではない)
多くのCPUには ベースクロック と ブーストクロック があり、負荷が高い時にだけ一時的に周波数を上げる機能が付いている
IPC (Instructions Per Cycle)
1クロックあたりの処理量
ワークロード依存の為、CPU固有の固定値ではなく変動するもの
製品ページなどに記載はないが、同一アーキテクチャ内では安定傾向であり、ベンチマークによる相対比較は可能
クロック周波数 × IPC = 1秒間に処理できる命令数
| CPU | クロック | IPC | 実性能イメージ |
|---|---|---|---|
| A | 3GHz | 1 | 3 (30億個) |
| B | 3GHz | 2 | 6 (60億個) |
同じクロック数でもIPCによって処理命令数は倍ほど変わる
L2, L3キャッシュ
よく使うデータと命令を一時保存する超高速メモリ
すべてのデータをRAM(メモリ)に取りに行っているとCPUの処理速度(速)に対してRAMの処理速度(遅)が追い付かない(メモリウォール)
そのため、CPU内にメモリを保持し、高速にアクセス出来るようにすることで、処理速度を高める
L1 > L2 > L3 >RAM (左から 小容量・高速 → 大容量・低速)となる
一般的な容量としては L1: 数十KB, L2: 数百KB~数MB, L3: 数MB~数十MBで、L1, L2は各コアそれぞれに専用の物があり、L3以降は全コアで共有
疑問
コアAで作業してL2キャッシュに情報を残していた物が、コアBでの作業に切り替わった場合はRAMまで再度読み込みにいくのか?
L1>L2>L3と見に行き、それでもない場合は以下のようになる。
CPUは MESIプロトコル という仕組みでキャッシュの整合性を保っています。
簡略説明:
Modified
Exclusive
Shared
Invalid
例えば:
- コアAがデータを書き換える
- そのデータはAのL1に「Modified」として存在
- コアBがそのデータを要求
- CPU内部のキャッシュコントローラが検知
- AのL1からBへデータ転送
- 状態がSharedに変わる
👉 RAMには行かずに、コア間でL3や内部パス経由でやり取りを行う
※ 同一コアで処理を行うよりコアを跨ぐことで速度は落ちるので、並列処理の場合は出来るだけ同じコアでデータを扱わせることが大事
→ どうやって同じコアでデータを扱わせるのかはChatGPTに聞いたけど、難しすぎて記事にできませんでした・・・
SIMD幅
1回で処理できるビット数であり、1命令で複数データを同時に処理する仕組み
イメージ】
# 通常(スカラー計算) → 4回命令実行
a1 * b1
a2 * b2
a3 * b3
a4 * b4
# SIMD(例: 256bit) → 1回の命令で4つ同時処理
[a1 a2 a3 a4] * [b1 b2 b3 b4]
| 命令 | 幅 | float32なら何個? |
|---|---|---|
| SSE | 128bit | 4個 |
| AVX2 | 256bit | 8個 |
| AVX-512 | 512bit | 16個 |
※AVX-512は現在主にサーバー向けCPUや一部の最新CPUでサポートされています
512/32=16個
※実際の理論FLOPSは
SIMD要素数 × FMA(2) × FMAユニット数 × クロック × コア数で決まる
IntelサーバーCPUにはAMXという行列専用ユニットもある
メモリ帯域
1秒あたりにメモリから読み書き出来るデータ量(GB/s)
帯域はDDR世代とメモリチャネル数で決まる
# 8bit換算なので、GiB換算だと微妙に違う・・・
帯域 = 転送レート(MT/s) × 8(Byte) ÷ 1000 × チャネル数
参考CPUの場合
6400 MT/s * 0.008 * 2 = 約102GB
90GB以上であれば軽量NumpyやXGBoost、小規模行列計算における機械学習ならCPUで対応可能なレベル
まとめ
CPUを見るときは、以下の項目を確認すると良い
| 項目名 | 説明 |
|---|---|
| コア | 作業員数。Intelなら構成のPコアと効率的なEコアの2種類ある。物理コア数。 |
| スレッド | HTがあると同じ20スレッドでもコア数=スレッド数に比べると性能差が出る |
| クロック | 1秒間に動作する回数で、命令回数ではない |
| IPC | 1クロックあたりの処理量 |
| L2, L3キャッシュ | 高速にアクセスできるメモリのようなもの |
| SIMD幅 | 1回で処理できるbit数であり、大きければ1回で複数処理が可能になる(行列計算など) |
| メモリ帯域 | 1秒当たりにメモリから読み書きできるデータ量 |