Hopper アーキテクチャで、変わること、変わらないこと
Akira Naruse, Developer Technology, 2022/4/26
HOPPER アーキテクチャ: 高性能、スケーラブル、セキュアな GPU
NVIDIA H100 (SXM5)
HOPPER アーキテクチャ
NVIDIA H100 GPU
132 SMs
16,896 FP32 units
528 Tensor Cores
Larger L2, 50 MB
HBM3 DRAM, 80 GB, 3 TB/s
4th-gen NVLink
900 GB/s (50 GB/s x 18 links)
SHARP, NVLink network
PCIe gen5
2nd-gen MIG
Confidential Computing
Thread Block
Clusters
世界初の HBM3 メモリ採用
3 TB/s
メモリ周波数が大幅に向上
80 GB (5 HBM sites)
新 512-bit メモリコントローラー
独立 2 チャネル /site
A100 相当の高い効率
(*) H100 の性能値は現時点の概算値です
AGENDA
Hopper アーキテクチャ
階層と局所性
非同期実行
スケーラブル
セキュリティ
HOPPER アーキテクチャ
GH100 Stream Multiprocessor
第 4 世代 Tensor Core
2 倍の FMA 性能 (FP32、FP64)
新 DPX 命令セット
L1/共有メモリのサイズ増, 256 KB
Thread Block Clusters
複数 SM 間の協調処理
Tensor Memory Accelerator (TMA)
テンソルデータの非同期コピー
Hopper Tensor Core
第 4 世代
約 3 倍の性能 UP
クロックあたり性能 2 倍 (/SM)
SM 数増: 108  132
クロック速度向上
FP8 対応
A100 H100
dense sparse dense sparse
FP64 TC 19.5 NA 60 NA
FP64 9.7 NA 30 NA
FP32 19.5 NA 60 NA
TF32 TC 156 312 500 1,000
FP/BF16 TC 312 624 1,000 2,000
FP16 78 NA 120 NA
FP8 TC NA NA 2,000 4,000
Peak TFLOPS
(*) H100 の性能値は現時点の概算値です
New
FP8 Tensor Core
FP16/BF16 の 2 倍のピーク性能
2 種類の FP8 フォーマット: E5M2 と E4M3
 E5M2 は「レンジ」重視
 E4M3 は「精度」重視
累加型と出力型は選択可能
 累加型: FP32|FP16
 出力型: FP32|FP16|BF16|FP8
TRANSFORMER ENGINE
FP8 Tensor Core の用途は?
Transformer モデルを、Hopper Tensor
Core で、高速に、精度低下ゼロで、計算
次レイヤーに適切な出力データ型を選択
Tensor Core の計算結果をモニター、その
結果に基づき、FP8 のレンジを有効活用で
きるよう、出力をスケーリング
FP8 TRAINING AND INFERENCE
FP8 の精度・メリット
GPT-3 のトレーニング、FP16/BF16 の場合
と同等の精度が得られることを確認
 Vision 系のネットワークでも同様の結果
FP8 でトレーニングすると、8-bit でインファレ
ンスするために quantization や fine
tuning が不要
better
DPX INSTRUCTIONS
動的計画法を加速
Smith-Waterman など、動的計画法コードを高速化する命令
ライブラリ提供を検討 (CUDA 12.x)
A100 に追加した機能も、そのまま使えます
AGENDA
Hopper アーキテクチャ
階層と局所性
非同期実行
スケーラブル
セキュリティ
GPU の演算リソースを効率よく使うには?
局所性と非同期実行
データ局所性
 短遅延
 高バンド幅
非同期実行
 データ転送と計算のオーバーラップ
 効率的な非同期実行機能
Load
A
Compute
A
Store
A
Load
B
Compute
B
Store
B
Load
C
Comput
C
Load
A
Compute
A
Store
A
Load
B
Compute
B
Store
B
Load
C
Compute
C
Store
C
Async
Mem Copy
Compute
Mem Copy
Compute
CUDA プログラミングモデルと GPU HW 階層
CUDA: 3階層
HW: 4階層
Grid … Block Thread
GPU GPC SM CUDA core
CUDA は 3 階層のプログラミングモデルで、データ局
所性を利用
グリッド: ブロックの集合 (カーネル)
ブロック: スレッドの集合
 一つの SM に割当。同一ブロック内のスレッドは、共
有メモリや L1 キャッシュ等の SM リソースを利用して、
協調実行
CUDA 階層と HW 階層に「乖離」
 CUDA では GPC を利用できない
H100: 132 SM
THREAD BLOCK CLUSTER
クラスタ
CUDA: 4階層
HW: 4階層
Grid Cluster Block Thread
GPU GPC SM CUDA core
CUDA に新しい階層を追加 (CUDA 12)
グリッド: クラスタの集合 (カーネル)
クラスタ: ブロックの集合
 ある一つの GPC 内の、複数 SM に割当
ブロック: スレッドの集合
クラスタの機能
 クラスタ内ブロックは、同時にスケジューリング
 分散共有メモリ: 互いの共有メモリにアクセス可
 高速なクラスタ内同期 (HWサポート)
H100: 132 SM
ブロックのスケジューリング
従来
各ブロックは、任意 GPC/SM に、別々に割り当てられる
他ブロックが、同時にスケジューリングされる保証は無い
Grid
0 1 2 3
0 1 2
ブロックのスケジューリング
クラスタ
クラスタ内のブロックは、ある一つの GPC に、同時に割り当てられる
 SM あたりの割り当てブロック数は 1 (default)
 クラスタあたりの最大ブロック数は 16
SM 間ネットワークを使用して、ブロック間で高速にデータ共有
Grid
0 1 2 3
0 1 2
Grid
Cluster
0 1 2 3
0 1 2 3
DISTRIBUTED SHARED MEMORY (DSMEM)
分散共有メモリ
ブロック間のデータ交換はグローバルメモリ経由 同じクラスタ内のブロックの共有メモリを直接アクセス可能
 load, store, atomics, async DMA, arrive barrier
SM 間ネットワークによる高速アクセス
より大きな粒度で協調処理 (1024スレッド超)
THREAD BLOCK CLUSTER
クラスタは、どうやって使うのか?
__global__ void kernel(...)
{
...
}
クラスタを使わない場合、コード変更不要
THREAD BLOCK CLUSTER
__cluster_dim__
__cluster_dim__ でクラスタサイズを指定
クラスタを使用するカーネルに追加
サイズは、1~3 次元で指定可能
カーネル起動は従来通り
__global__ void __cluster_dim__(4) kernel(...)
{
...
}
THREAD BLOCK CLUSTER
cooperative_groups::this_cluster()
Cooperative Groups に this_cluster() を追加
クラスタサイズや、クラスタ内ブロック番号を、カーネ
ル内で取得できる
 gridDim, blockIdx 相当
0 1 2 3
__global__ void __cluster_dim__(4) kernel(...)
{
namespace cg = cooperative_groups;
cg::cluster_group cluser = cg::this_cluster();
int cluster_size = cluster.dim_blocks().x;
int my_rank = cluster.block_rank();
...
}
THREAD BLOCK CLUSTER
cooperative_groups::this_cluster()
Cooperative Groups に this_cluster() を追加
クラスタサイズや、クラスタ内ブロック番号を、カーネ
ル内で取得できる
 gridDim, blockIdx 相当
cluster.sync() で同期
 __syncthreads() 相当
__global__ void __cluster_dim__(4) kernel(...)
{
namespace cg = cooperative_groups;
cg::cluster_group cluser = cg::this_cluster();
int cluster_size = cluster.dim_blocks().x;
int my_rank = cluster.block_rank();
cluster.sync();
...
}
cluster.sync()
THREAD BLOCK CLUSTER
分散共有メモリ (DSMEM)
分散共有メモリ (DSMEM)
クラスタ内のブロック番号を使って、他ブロックの共
有メモリを「マップ」して、アクセスできる
read, write, atomics
__global__ void __cluster_dim__(4) kernel(...)
{
__shared__ int smem[1];
namespace cg = cooperative_groups;
cg::cluster_group cluser = cg::this_cluster();
int cluster_size = cluster.dim_blocks().x;
int my_rank = cluster.block_rank();
int *remote_smem = cluster.map_shared_rank(
smem, (my_rank + 1) % cluster_size);
if (threadIdx.x == 0)
remote_smem[0] = my_rank;
cluster.sync();
...
}
0 1 2 3
THREAD BLOCK CLUSTER 使用例
共有メモリ・ヒストグラム
ブロック毎に、それぞれ共有メモリ上でヒストグラムをカウントした後、グローバルメモリ上の
ヒストグラムに加算
 ヒストグラム数 (N) が大きいと共有メモリに収まらない
 N = 75,000 を 32-bit integer でカウントすると 300 KB 必要
共有メモリ
(H100: ~228 KB)
N
THREAD BLOCK CLUSTER 使用例
分散共有メモリ・ヒストグラム
ブロック毎に、それぞれ共有メモリ上でヒストグラムをカウントした後、グローバルメモリ上のヒストグラム
に加算
 ヒストグラム数 (N) が大きいと共有メモリに収まらない。
 N = 75,000 を 32-bit integer でカウントすると 300 KB 必要
クラスタ (サイズ: 2) を使用、各ブロックの共有メモリにはヒストグラムを半分配置
分散共有メモリ
N/2 N/2
THREAD BLOCK CLUSTER 使用例
共有メモリ・ヒストグラム
__global__ void block_histgram(...)
{
__shared__ int smem[N];
for (int i = threadIdx.x; i < N; I += blockDim.x) {
smem[i] = 0;
}
__syncthreads();
for (...) {
int bin_id = ...;
atomicAdd(smem + bin_id, 1);
}
__syncthreads();
...
}
共有メモリ: 初期化
共有メモリ: increment
グローバルメモリ: 加算
THREAD BLOCK CLUSTER 使用例
分散共有メモリ・ヒストグラム
__global__ void __cluster_dim__(2) cluster_histgram(...)
{
__shared__ int smem[N/2];
for (int i = threadIdx.x; i < N/2; i += blockDim.x) {
smem[i] = 0;
}
cg::cluster_group cluser = cg::this_cluster();
int *dsmem[2];
for (int i = 0; i < 2; i++) {
dsmem[i] = cluster.map_shared_rank(smem, i);
}
cluster.sync();
for (...) {
int bin_id = ...;
int rank = bin_id / (N/2);
int offset = bin_id % (N/2);
atomicAdd(dsmem[rank] + offset, 1);
}
cluster.sync();
...
}
共有メモリ: 初期化
分散共有メモリ: マップ
分散共有メモリ: increment
グローバルメモリ: 加算
THREAD BLOCK CLUSTER 使用例
分散共有メモリ・ヒストグラム
__global__ void __cluster_dim__(2) cluster_histgram(...)
{
__shared__ int smem[N/2];
for (int i = threadIdx.x; i < N/2; i += blockDim.x) {
smem[i] = 0;
}
cg::cluster_group cluser = cg::this_cluster();
int *dsmem[2];
for (int i = 0; i < 2; i++) {
dsmem[i] = cluster.map_shared_rank(smem, i);
}
cluster.sync();
for (...) {
int bin_id = ...;
int rank = bin_id / (N/2);
int offset = bin_id % (N/2);
atomicAdd(dsmem[rank] + offset, 1);
}
cluster.sync();
...
}
AGENDA
Hopper アーキテクチャ
階層と局所性
非同期実行
スケーラブル
セキュリティ
GPU の演算リソースを効率よく使うには?
データ局所性と非同期実行
データ局所性
 短遅延
 高バンド幅
非同期実行
 データ転送と計算のオーバーラップ
 効率的な非同期実行機能
Load
A
Compute
A
Store
A
Load
B
Compute
B
Store
B
Load
C
Comput
C
Load
A
Compute
A
Store
A
Load
B
Compute
B
Store
B
Load
C
Compute
C
Store
C
Async
Mem Copy
Compute
Mem Copy
Compute
TENSOR MEMORY ACCELERATOR (TMA)
非同期メモリコピー
HW メモリコピーエンジン (SM 内)
グローバルメモリ  共有メモリ
共有メモリ  グローバルメモリ
1D ~ 5D テンソルのコピー
完全オフロード
アドレス計算
トランザクションバリアで同期 (no spin-lock)
クラスタ対応
共有メモリ  共有メモリ (クラスタ内)
2D Tensor padding
Tensor width
Tensor
height
Tensor
stride
region
to copy
Block width
Block
height
非同期メモリコピー
A100: LDGSTS
cg::memcpy_async()
スレッドがアドレス計算し、LDGSTS 命令を使って、
非同期にグローバルメモリから共有メモリにデータを
ロード
(独立な計算)
cg::wait()
スレッドが、共有メモリにデータが到着していることを、
spin で確認
SM
SMEM L1
Registers
Threads
Tensor Core
A100: LDGSTS
Global Memory
Data Loads
スレッドが
アドレス計算
spin
非同期メモリコピー
A100  H100
SM
SMEM L1
Registers
Threads
Tensor Core
SM
SMEM L1
Registers
Threads
Tensor Core
TMA
A100: LDGSTS H100: TMA
Global Memory Global Memory
Loads
Data
スレッドが
アドレス計算
spin
非同期メモリコピー
H100: TMA
SM
SMEM L1
Registers
Threads
Tensor Core
TMA
H100: TMA
Global Memory
Data +
TransCnt
Loads
TMAが
アドレス計算 sleep
cg::memcpy_async()
スレッドは、TMA にデータコピーをオフロード。TMA
がアドレス計算を行い、グローバルメモリから共有メ
モリにデータをロード。
(独立な計算)
cg::wait()
スレッドは、共有メモリにデータが到着するまで
sleep。
TMA 利用例
ステンシル計算
ブロック内のスレッドが参照する要素を全て共有メモリに load、それから、ステンシル計算
ステンシルサイズが小さい場合は L1 で十分
ステンシルサイズが大きい場合には、依然として、有効
0 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
スレッド
ブロック
(半径: 2)
ステンシル計算
共有メモリへの入力データの loading
__shared__ float smem[BY + 2*R][BX + 2*R];
int bx = blockIdx.x * BX - R;
int by = blockIdx.y * BY - R;
for (int i = threadIdx.x + threadIdx.y * BX;
i < (BY + 2*R) * (BX + 2*R);
i += BY * BX) {
int sy = i / (BX + 2*R);
int sx = i % (BX + 2*R);
int iy = by + sy;
int ix = bx + sx;
float val = 0.0;
if (((R <= sx && sx < BX + R) ||
(R <= sy && sy < BY + R)) &&
((0 <= ix && ix < NX) &&
(0 <= iy && iy < NY))) {
val = input[iy][ix];
}
}
smem[sy][sx] = val;
}
__syncthreads(); 正しく実装するのは
意外と大変
ブロックの担当領域 + halo
TMA ロード
TMA ロード
 グローバルメモリ  共有メモリ
 テンソル descriptor に、入力テンソルの形状・ストライド、ベースポインタ、共有メモリの形状、を指定
 1 スレッドで実行
 入力テンソルの範囲外の部分には、ゼロ値が代入
0 1 2 3 4 5 6 7
8 9 10 11 12 13 14 15
16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31
1つの TMA ロードで完了
ステンシル計算
共有メモリへの入力データの loading (TMA 使用)
0
0
0 0 0 0
0
0
0
0 0 0 0
__shared__ float smem[(BY + 2*R) * (BX + 2*R)];
...
int bx = blockIdx.x * BX - R;
int by = blockIdx.y * BY – R;
if (threadIdx.x == 0) {
memcpy_async(smem, tensor_desc, bx, by, barrier);
}
barrier.wait();
0 0 0 0
0 0
0 0
0
(*) API 変更の可能性有り
TMA の効果例
ステンシル計算
ステンシルサイズが小さいケースでは、
共有メモリ利用の効果は少ない
ステンシルサイズが大きいケースでは、
共有メモリを利用する価値がある
共有メモリ実装と比べると、TMA 実
装は、実装が簡潔で、高性能
ASYNC BARRIER (A100)
非同期バリア
Barrier を Arrive と Wait に分離
Arrive … データ生成が完了した
Wait … データ消費を開始したい
Arrive (non-blocking)
通過したスレッド数をカウント
Wait (blocking)
全スレッドが Arrive を通過していたら、開放
それまで、待ちスレッドはここで spin
bar.arrive()
bar.wait()
Produce Data
Consume Data
Independent
Work
Threads
spin
ASYNC TRANSACTION BARRIER (H100)
非同期トランザクションバリア
Arrive (non-blocking)
通過したスレッド数をカウント
Barrier は、共有メモリへの store 数もカウント
共有メモリにデータが到着したら、トランザクションカ
ウントが増加
Wait (blocking)
全スレッドが Arrive を通過しており、かつ、トランザ
クションカウント数が指定数に達していたら、開放
それまで、待ちスレッドはここで sleep
bar.arrive()
bar.wait()
Produce Data
Consume Data
Independent
Work
Threads
Async
SMEM stores
sleep
非同期トランザクションバリアを用いたブロック間通信
ブロック間で高速にデータ交換
Consumer ブロックの共有メモリ上で Data と
Barrier を同時に更新
Flag より先に Data が更新されるのを保証するには
メモリフェンスが必要
AGENDA
Hopper アーキテクチャ
階層と局所性
非同期実行
スケーラブル
セキュリティ
HOPPER アーキテクチャ
NVIDIA H100 GPU
4th-gen NVLink
900 GB/s (50 GB/s x 18 links)
SHARP, NVLink network
DGX A100
2 CPUs, 8 GPUs, 8 NICs
PCIe gen4
PCIe Switch
CX6
3rd gen NVLink
 600 GB/s (bi-direction)
 12 links * 50 GB/s
A100 A100 A100 A100 A100 A100 A100 A100
CPU CPU
NV Switches
PCIe
gen4
PCIe
gen4
NVLink gen3
CX6 CX6 CX6 CX6 CX6 CX6 CX6 CX6
PCIe SW PCIe SW PCIe SW PCIe SW
DGX A100
DGX H100
2 CPUs, 8 GPUs, 8 NICs
PCIe gen5
CX7
 with PCIe bridge
4th gen NVLink
 900 GB/s (bi-direction)
 18 links * 50 GB/s
3rd gen NVSwitch
 SHARP support
H100 H100 H100 H100 H100 H100 H100 H100
CPU CPU
CX7 CX7 CX7 CX7 CX7 CX7 CX7 CX7
NV Switches
PCIe
gen5
PCIe
gen5
NVLink gen4
A100 H100 Speedup
Bisection
[GB/s]
Reduce
[GB/s]
Bisection
[GB/s]
Reduce
[GB/s]
Bisection Reduce
1 DGX (8 GPUs) 2,400 3,600 1.5x
DGX H100
Step 1: Reduce
Step 2: Broadcast
NVLINK SHARP ACCELERATION
All-reduce
A100
N send
N recv
N send
N recv
A100 H100 + NVLink SHARP
NVS
A100
A100 A100
A100 A100
A100 A100
A100
NVS
A100
A100 A100
A100 A100
A100 A100
2N send, 2N recv N send, N recv
(*) N は All-reduce のメッセージサイズ
SHARP で、必要 NVLink 帯域を、概ね半減
H100
NVS
H100
H100 H100
H100 H100
H100 H100
N*7/8 send
N/8 recv
Reduce
A100
NVS
H100
H100 H100
H100 H100
H100 H100
N/8 send
N*7/8 recv
Multi-cast
DGX H100
2 CPUs, 8 GPUs, 8 NICs
PCIe gen5
CX7
 with PCIe bridge
4th-gen NVLink
 900 GB/s (bi-direction)
 18 links * 50 GB/s
3rd gen NVSwitch
 SHARP support
H100 H100 H100 H100 H100 H100 H100 H100
CPU CPU
CX7 CX7 CX7 CX7 CX7 CX7 CX7 CX7
NV Switches
PCIe
gen5
PCIe
gen5
NVLink gen4
A100 H100 Speedup
Bisection
[GB/s]
Reduce
[GB/s]
Bisection
[GB/s]
Reduce
[GB/s]
Bisection Reduce
1 DGX (8 GPUs) 2,400 150 3,600 450 1.5x 3x
72 links
DGX H100
2 CPUs, 8 GPUs, 8 NICs
H100 H100 H100 H100 H100 H100 H100 H100
CPU CPU
CX7 CX7 CX7 CX7 CX7 CX7 CX7 CX7
NV Switch NV Switch NV Switch NV Switch
144 links (8 GPUs * 18 links)
PCIe gen5
CX7
 with PCIe bridge
4th-gen NVLink
 900 GB/s (bi-direction)
 18 links * 50 GB/s
3rd gen NVSwitch
 SHARP support
 64 ports per NVSwitch
NVLink
gen4
DGX H100 256 POD
32x DGX H100
DGX H100
32 nodes
(256 GPUs)
NVLink
Switch
NVLink
Switch
NVLink
Switch
NVLink
Switch
NVLink 全結合網
2304 links (32 nodes * 72 links)
A100 H100 Speedup
Bisection
[GB/s]
Reduce
[GB/s]
Bisection
[GB/s]
Reduce
[GB/s]
Bisection Reduce
1 DGX (8 GPUs) 2,400 150 3,600 450 1.5x 3x
32 DGXs (256 GPUs) 6,400 100 57,600 450 9x 4.5x
8x HDR NICs per node NVLink 全結合
AGENDA
Hopper アーキテクチャ
階層と局所性
非同期実行
スケーラブル
セキュリティ
CONFIDENTIAL COMPUTING
パブリッククラウドでの懸念
クラウドプロバイダー
特権管理者
ハイパーバイザー
仮想マシン
コンフィデンシャル・コンピューティング
利用中のデータの暗号化
CONFIDENTIAL COMPUTING
HW based Trusted Execution Environment
(TEE)
 TEE を GPU に拡張
 CPU と GPU 間 (PCIe)、GPU 間 (NVLink) のデータ
転送を HW で暗号化 (AES-GCM 256)
Hardware Root of Trust
 認証された firmware と GPU 認証
CUDA アプリのコード変更は不要
利用中のデータの暗号化
Secure Pass-Thru
CONFIDENTIAL COMPUTING
HW based Trusted Execution Environment
(TEE)
 TEE を GPU に拡張
 CPU と GPU 間 (PCIe)、GPU 間 (NVLink) のデータ
転送を HW で暗号化 (AES-GCM 256)
Hardware Root of Trust
 認証された firmware と GU 認証
CUDA アプリのコード変更は不要
利用中のデータの暗号化
Secure Pass-Thru
CONFIDENTIAL COMPUTING AND H100 MIG
Trusted Execution Environment (TEE) per MIG
 GPU ハードの仮想化 (PCIe SR-IOV)
 GPU インスタンス間のメモリ・L2 はファームウェアで隔離
Secure MIG: 1 VM per GPU instance
マルチインスタンス GPU (MIG)
Multi-Tenant, Single GPU
AGENDA
Hopper アーキテクチャ
階層と局所性
非同期実行
スケーラブル
セキュリティ
まとめ
HOPPER アーキテクチャ: 高性能、スケーラブル、セキュアな GPU
まとめ
H100 の新機能の多くは、ライブラリや
ファームで提供される
基本的に、コード変更は不要
Thread Block Cluster や TMA を有
効活用するには、コード変更が必要
NVIDIA H100 (SXM5)
POINTERS
GTC 2022 talks
Inside the NVIDIA Hopper Architecture (S42663)
Optimizing CUDA Applications for NVIDIA Hopper Architecture (S41489)
CUDA: New Features and Beyond (S41486)
White paper
NVIDIA H100 Tensor Core GPU Architecture
Hopper アーキテクチャで、変わること、変わらないこと

Hopper アーキテクチャで、変わること、変わらないこと