1076: cudaデバッグ・プロファイリング入門
TRANSCRIPT
森野慎也, シニアCUDAエンジニア, エヌビディアジャパン
CUDAデバッグ・プロファイリング入門
アジェンダCUDAのデバッグツールの紹介
CUDAデバッガ・メモリチェッカNsight Visual Studio Edition, Nsight Eclipse Edition
cuda-memcheck範囲外アクセス・未初期化値へのアクセス・同期チェックコマンドラインツール。 Windows、Linux、MacOS X上で同じ使い方ができる。
CUDA プロファイラの紹介
Nsight Visual Studio Edition
Nsight Eclipse Edition / Visual Profiler
CUDA デバッガNsight Visual Studio Edition (NVSE)
Windows 向け。Visual Studioと統合
Nsight Eclipse Edition
Linux・MacOS 向け。EclipseベースのIDE
cuda-gdb
LInux・MacOS向け。コマンドラインデバッガ。
Nsight Eclipse Editionのバックエンド
NSIGHT VISUAL STUDIO EDITIONVisual Studioに統合されている
VS2013を使用します。
コミュニティエディションが使える!
Professional相当
無償利用も可能。詳細は、以下をご確認んください。
http://www.microsoft.com/ja-jp/dev/products/community.aspx
Ver 対応状況
VS2010 deprecated
VS2012 〇
VS2013 〇
VS2015 未対応
サンプル : PREFIX SUMWarp Shuffle + シェアードメモリ
Warp (shuffle) Warp (shuffle) Warp (shuffle) Warp (shuffle)
32 32 32 32
Warp (shuffle)
32 64 92 128
Add Add Add
1 … 32 33 … 64 65 … 92 93 … 128
1 … 32 1 … 32 1 … 32 1 … 32
1, 1, 1, 1, … 1, 1, 1, 1, … 1, 1, 1, 1, … 1, 1, 1, 1, …入力
シェアードメモリ(SM内部にある)
シェアードメモリ
結果
ビルド設定
プロジェクトメニュー
→ ビルドのカスタマイズ
CUDA 7.5を選択。
Nsight Visual Studio Edition
デバッグ設定
- 「Code Generation」
使用するGPUのCCが設定されていること。(複数指定可)
- 「Generate GPU Debug Info」
「はい(-G)」に設定
Nsight Visual Studio Editionによるデバッグ
デバッグ
- Nsightメニュー
“CUDA Debugging…”を選択
- 実演
Nsight Visual Studio Edition
Break Point
ステップ実行
スレッド内の変数表示
Warp内のスレッド変数をウォッチ
SM上のWarpの一覧ダブルクリックで選択可能
NSIGHTでのメモリチェック
- 範囲チェックのみサポート
Nsight Visual Studio Edition
メモリチェックテストプログラム
__global__ void writeToMem(int *dMem) {
dMem[threadIdx.x] = 0;
}
int main() {
int *dMem;
cudaMalloc(&dMem, sizeof(int) * 255));
writeToMem<<<1, 256>>>(dMem);
(略)
Overrun
…
…Thread
Memory×
メモリチェック
- プログラムをデバッグ実行する。
エラー発生行で停止。
- Debugビルド・Releaseビルドの両方で使える。
Nsight Visual Studio Edition
エラー発生行で停止
エラー発生状況の説明表示
カーネル中のASSERT
- C言語のassertと同じ
- #define NDEBUGで、無効化
Nsight Visual Studio Edition
__global__
void kernelAssert() {
assert(0);
}
int main() {
kernelAssert<<<1, 1>>>();
cudaError_t cuerr = cudaDeviceSynchronize();
printf("%s¥n", cudaGetErrorName(cuerr));
}
実演する
カーネル中のASSERT
- デバッグ実行時
device_runtime.h中で停止出力に、詳細情報が現れる呼び出し履歴から発生行を表示
- 通常実行時
cudaErrorAssertが返される。
Nsight Visual Studio Edition
カーネル中のPRINTFNsight Visual Studio Edition
__global__ void printfKernel() {printf("blockIdx(%d, %d, %d) threadIdx(%d, %d, %d)¥n",
blockIdx.x, blockIdx.y, blockIdx.z,threadIdx.x, threadIdx.y, threadIdx.z);
}
int main() {dim3 gridDim(2), blockDim(8);
size_t size;cudaDeviceGetLimit(&size, cudaLimitPrintfFifoSize);printf("Printf FIFO size : %d¥n", (int)size);// cudaDeviceSetLimit(cudaLimitPrintfFifoSize, size);
printfKernel<<<gridDim, blockDim>>>();(略)
NSIGHT ECLIPSE EDITIONEclipse IDEに統合されたCUDA開発環境
Linux・MacOS向け
cuda-gdbをバックエンドとして利用する。
Jetsonのリモートデバッグもサポート
今日は、MakefileでのビルドとNsightでのデバッグを行います。
CUDAソースコードのコンパイル
- nvcc : CUDA用のコンパイラ
- 内部でホスト側コンパイラを使用
- デフォルトは、cl.exe(Windows)、g++(Linux)
- --ccbin で(icc, clang)など指定可能
- ホストコンパイラのオプションも受け付ける。
-Xcompiler <ホストコンパイラオプション>
NVCCの構成
18
ソース(*.cu)
ホスト/GPU ソース分割
ホストコンパイラ
デバイスコードコンパイラ
マージ
オブジェクト (*.o)
MAKEFILEの書き方デバッグ時のオプション
-G : 最適化無効。デバッグ情報の生成
実行速度は、一桁落ちると思ってよい。
-g or –Xcompiler –g
ホストコンパイラに、デバッグ情報の生成を行わせる。
Makefileのレビュー
起動・プロジェクトのインポート
起動 : $ nsight
メニューから
File -> New
-> Makefile Project withExisting Code
Nsight Eclipse Edition プロジェクト設定
プロジェクトの作成
- Project Name
- プロジェクト名
- Existing Code Location
- 既存のソースコードの場所
- Toochain for indexer Settings
- ソースのインデキサ設定
Nsight Eclipse Edition プロジェクト設定
デバッグ設定
- 「Debug Configurations…」を開く
- 「C/C++ Application」をダブルクリック
- 以下の項目を設定
Nameプロファイル名
C/C++ Application : バイナリ
Project : ソースがあるプロジェクト
Nsight Eclipse Edition
使用するGPUの設定
- Single GPUでのデバッグ (Beta)Kepler(CC3.5以降)、Maxwellが必要
- GPUのBreak pointでの停止
- ソフトウエアで状態を保存。
- システムがGPUを利用できるようにする。
- ブレーク中に終了するとフリーズする場合がある。
Nsight Eclipse Edition
デバッグ
- Blockスコープで、ステップ実行
Nsight Eclipse Edition
Break Point
ステップ実行
スレッド内の変数表示
GPU上のThread一覧ダブルクリックで選択可能
メモリチェッカの有効化
- デバッグ設定 / Debugger ペイン
- “Enable CUDA memcheck”をチェック
- Software Preemptionは使えない。(画面を書いていないGPUを使う)
Nsight Eclipse Edition
メモリチェッカ動作例Nsight Eclipse Edition
CUDA-MEMCHECK
- 機能
memcheck : 範囲チェック、デバイスメモリのリークをチェック
initcheck : 未初期化値へのアクセスをチェック
synccheck : 同期(__syncthreads())の、すべてのスレッド上の発行をチェック
racecheck : シェアードメモリ上でのハザードを検出
- ビルド時に “-lineinfo”を指定しておくこと。
エラーログ中に、エラー発生行が出力されます。
- Windows / Linux / MacOS X上で、使用法は同じ。
- 今日は、Windowsで動作させてみます。 (配布ファイル中に、ログを入れておきます。)
メモリチェックのためのコマンドラインツール
プロファイラ (WINDOWS)
タイムライン計測
タイムラインの計測
GPUの使用率
データ転送・カーネル実行時の時系列を可視化
GPUの稼働時間は、長いほうがよい
並列に、データ転送・CPU処理も行われているとよい。
プロファイラ
タイムライン取得設定
- 「Nsight」メニューから
「Start Performance Analysis… 」を選択
- Trace Applicationを選択
- Trace Seettingsから “CUDA”をチェック
Nsight Visual Studio Edition
DEFAULT STREAMでの処理実行Stream : GPU上の処理を管理するキュー
無指定の場合、Default (NULL) Streamが使用される。
t
Memcpy
Host → DeviceKernel
Memcpy
Device → Host
Default (NULL) Stream
タイムライン取得例Nsight Visual Studio Edition
H->D
memcpy
D->H
memcpy
カーネル
同期によるレイテンシの発生CPU→GPU : 処理開始までのレイテンシ発生
GPU→CPU : 同期によるレイテンシ
t
Memcpy
Host → DeviceKernel
Memcpy
Device → Host
GPU上での実行
t
MemcpyMemcpy
Device → Host
CPUからのタスク発行
同期待ち 同期待ち
MemcpyAsync
Host → DeviceKernel
MemcpyAsync
Device → Host
Device
Synchronize()CPU上で別の処理を行う
レイテンシの削減 ・ CPU/GPU上の並列処理非同期コピー(cudaMemcpyAsync()) を使用。
tGPU上での実行
t
CPUからのタスク発行
非同期MEMCPYを用いたタイムラインNsight Visual Studio Edition
memcpy、カーネル起動処理
パイプライン化メモリ転送・カーネル実行を、オーバーラップ
複数ストリームの使用
Stream 1
Stream 2
Stream 3
Memcpy
(H->D)Kernel
Memcpy
(D->H)
Memcpy
(H->D)Kernel
Memcpy
(D->H)
Memcpy
(H->D)Kernel
Memcpy
(D->H)
パイプライン化
実行時間
34.5 ms→ 19.0 ms
Nsight Visual Studio Edition
メモリアクセス解析・ビルド設定
- ビルド時に、行番号情報を生成
- ソースレベルプロファイリングで必須
Nsight Visual Studio Edition
プロファイラ設定
- Profile CUDA Applicationを選択
- Experiment Configuration
実施する計測を指定する。
今回は”All”を指定。
Nsignt Visual Studio Edition
メモリアクセス解析GPU(Maxwell)のデータパス
SM
Regis
ter
File
(変数
)
L2 C
ache
演算
Share
d
Mem
ory
CU
DA C
ore
s
Glo
bal M
em
ory
(GPU
DRAM
)
Host
(PC)
DRAM
PCIe
高速 (数TB / sec) 低速 (~ 10 GB/sec)L1/Te
x
Cache*
*CC 5.2で、R/W可能なL1キャッシュを有効可能
Global
Tex
Local
GPU内のデータトラフィック表示
- 以下を表示できる
Bandwidth
Size (Load/Store)
Size (Load)
Size (Store)
- 遅いデータパス上でのデータアクセスを減らせないか…
Nsight Eclipse Edition
Global Memory B/W
まず確認する値
アクセスパターン分析
- AoS : Array of Structures
CPU上でのスタイル
構造化・Object志向
サンプル : memoryAccess
- SoA : Structure of Arrays
GPU上でアクセス効率がよい
struct XY {
float x;
float y;
};
XY xyArray[1024];
struct XYArray {
float x[1024];
float y[1024];
};
コアレスアクセス
コアレス(Coalesced) アクセス と呼びます
理想的なアクセス
v0 v1 v2 v3 v4 v5 v6 v7 v8
Thread
Memory
…
…
アクセスパターンの違いAoS vs SoA
x y x y
x y x y
1) xをアクセス
2) yをアクセス
x xx x
y y y y
x xx x
y y y y
AoS:
アクセスに抜けがある。効率悪い。
SoA:
アクセスが連続。効率よい。
AOSのアクセス例
- L2 Transfer Overhead
L2 → L1転送バイト数
使用されるバイト数
- 期待値は 2
- より詳細にみる
アクセスパターン分析
ソースレベルの表示アクセスパターン分析
分岐の解析Warp Divergence
Thread- 両方のパスを実行する必要がある。
- 性能が落ちる原因。if (cond) {
}else {
}
ソースコード
- Global IDが、偶数・奇数で分岐
- 最適化されないよう、メモリフェンス(__threadfence_block())を、入れてあります
分岐の解析
__global__
void divergentExecutionKernel(float *dMem) {
int gid =
blockDim.x * blockIdx.x + threadIdx.x;
float angle =
float(gid % 360) * float(M_PI / 180.f);
if (gid % 2 == 0) {
dMem[gid] = __sinf(angle);
__threadfence_block();
}
else {
dMem[gid] = __cosf(angle);
}
}
BRANCH STATISTICS
- 50 %の分岐にDivergenceがある。
- ソースコードレベルで確認する。
分岐の解析
DIVERGENT BRANCH
- 17行目の分岐が、Divergeしている。
分岐の解析
ソースコードの表示
- if分の中の__cos()での分岐を表示していた。
分岐の解析
プロファイラ (LINUX)Windows上と同等の内容を、時間の許す限り、デモンストレーションします。
THANK YOU