NVIDIA Nsight Systemsを使ってCUDAのプロファイリングをやってみる


CUDAのプロファイラとして長らく`nvprof`と`nvvp`をが使われてきたと思いますが、最近これらのツールのドキュメントの最初のほうに以下のように書かれています。
> Note that Visual Profiler and nvprof will be deprecated in a future CUDA release. It is recommended to use next-generation tools NVIDIA Nsight Compute for GPU profiling and NVIDIA Nsight Systems for GPU and CPU sampling and tracing.

参考：https://docs.nvidia.com/cuda/profiler-users-guide/index.html

というわけで、そろそろ私も「移行するかー」と思い、NVIDIA Nsight Systemsについて調べたのでまとめました。

# NVIDIA Nsight ComputeとNVIDIA Nsight Systemsとは
`nvprof`、`nvvp`には主に以下の2つの機能があります。

1. CUDAカーネルのプロファイリング
2. CUDAカーネルのトレーシングとnvvpによるタイムライン表示

この2つがそれぞれ「NVIDIA Nsight Compute」と「NVIDIA Nsight Systems」に分かれた感じです。このブログではNVIDIA Nsight Systemsについてのみ説明していきます。
ちなみに、最初私は勘違いしていたのですが、昔からあるNsightとNsight Systemsは別物ですので注意してください。

# NVIDIA Nsight Systemsを使った感想
NVIDIA Nsight Systemsを使うと何がうれしいの？と思う方のために、最初に`nvprof`、`nvvp`とNVIDIA Nsight Systemsを比較して私が思ったことをまとめると、

1. `nvvp`と比較すると、GUIの動作が軽い。本当に軽い。大事なのでもう一度書きますが、すごく軽い！（私個人の体感です）
2. 複数のMPIのプロセスのプロファイルをまとめて取れる

# 検証事項と検証環境

このブログでは業務でいつも行う以下のことを実行することを想定して、インストール方法と手順を説明していきます。

1. リモート環境のCLIでCUDAコード（実際にはChainerMNのコード）のトレーシング
2. ローカル環境でトレーシング結果をタイムライン表示

また、今回の検証環境は以下の通りです。

## リモート環境

* CPU : Intel(R) Xeon(R) CPU E5-2620 x 2
* GPU : Tesla P100 x 8
* OS : Ubuntu 16.04.3 LTS
* CUDA : 9.0
* root権限はなし

## ローカル環境

* CPU : Intel Core i7-7660 
* GPU : なし
* OS : Ubuntu 16.04.3 LTS
* CUDA : 9.2

# NVIDIA Nsight Systemsのインストール
まずは、NVIDIA Nsight Systemsのインストール方法を説明していきます。
この記事ではCUDAはすでにインストールされていることを前提に説明していきます。

最初に自分の環境に適したものを以下のサイトからダウンロードします。
https://developer.nvidia.com/nsight-systems#Platforms

今回はリモートとローカル共に以下のものを落としました。
Nsight Systems 2019.3 (Linux Host)
https://developer.nvidia.com/rdp/assets/Nsight_Systems_2019_3_Linux_installer

このリンクから`Nsight_Systems_2019_3_Linux_installer`がダウンロードできます。

ダウンロード後、以下のようにファイルを解凍します。

```bash
$ sh Nsight_Systems_2019_3_Linux_installer
```
最初に利用規約の承認があるので、`y` を入力して承認してください。
解凍が終わると以下のようなディレクトリができています。

```bash

$ tree -L 1 NsightSystems-linux-public-2019.3.1.94-3891ef3/
NsightSystems-linux-public-2019.3.1.94-3891ef3/
├── Documentation
├── Host-x86_64
└── Target-x86_64
```

解凍ができたら `PATH` と `LD_LIBRARY_PATH` を以下のように通します。

```bash
export NSIGHT_SYSTEMS_ROOT=/path/to/NsightSystems-linux-public-2019.3.1.94-3891ef3
export PATH=$PATH:$NSIGHT_SYSTEMS_ROOT/Host-x86_64
export PATH=$PATH:$NSIGHT_SYSTEMS_ROOT/Target-x86_64/x86_64
```

上記のことをリモート環境、ローカル環境の両方でやります。

# リモート環境のCLIでプロファイリングを取る
リモート環境にsshで入り、プロファイルを取ってみます。
NVIDIA Nsight Systemsでは `nsys` というコマンドを利用し、以下のようにプロファイリングを行います。

```bash
$ nsys profile <application> [application-arguments]
```

また、ChainerMNのようにMPIを使う場合は以下の2つのやり方でプロファイリングができます。

```bash
# プロファイル結果を一つのファイルにまとめる
$ nsys [nsys options] mpirun [mpi options]
```

```bash
# MPIプロセス毎に結果を分ける
$ mpirun [mpi options] nsys profile [nsys options]
```

今回は以下のコードをベースにしたものを利用して、MPIの複数のプロセスのプロファイル結果を1つにして出力する例を示します。
https://github.com/chainer/chainercv/blob/master/examples/fpn/train_multi.py

実際のコマンドは以下のようになります。

```bash
$ nsys profile -o report1 \
     mpirun -n $NUM_PROCESSES \
          -- python3 train_multi.py 
```

`-o` でプロファイル結果の出力先を指定できます。`-o report1` を付けた場合、実行したディレクトリに `report1.qdrep`というファイルができています。 `-o` がない場合はhomeにファイルができます。

`nsys` のその他のオプションは以下を参照してください。
https://docs.nvidia.com/nsight-systems/index.html#nsight_systems/2019.3.1-x86/06-cli-profiling.htm

# ローカルのGUIでプロファイル結果を表示する

予め、リモート環境で実行したプロファイル結果の `report1.qdrep`をローカルにコピーしておきます。

ローカルにコピーしてきた後、NVIDIA Nsight SystemsのGUIを起動し、結果を表示していきます。
GUIを起動するには以下のコマンドを実行します。

```bash
$ nsight-sys
```

起動するとこのような画面が表示されます。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21366/9b965726-5951-fc8a-a548-d1543dc3db11.png)

画面が表示されたら、[File]→[Open...]を選択します。
選択すると以下のような画面が表示されます。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21366/f8d0549a-af23-adc5-2337-15ce11741485.png)

[File]→[Import...]ではないので、注意してください。

ここで、先にリモート環境からコピーしてきたプロファイル結果の`report1.qdrep`を選択し、[Open] を選択します。

選択後、プロファイル結果のロードが始まるので終わるまで待ちます（ここは少し長いです）。

ロードが終わると以下のように表示されます。
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21366/49f94056-b5ad-43d7-dd34-ef567625df21.png)

私の環境では最初「Timeline View」は真っ白でしたが、しばらく待っていたり、別のビューに切り替えて、また「Timeline View」を選択するとちゃんと表示されました。

あとは「Ctrl + スクロール」で拡大、縮小したり、いろんなところをポチポチおして、結果を確認してみてください

どんなものが表示できるかは以下のドキュメントを読むと良いと思います。（長いですが）
https://docs.nvidia.com/nsight-systems/index.html#nsight_systems/2019.3.1-x86/01-overview.htm

# 最後に
個人的にはnvvpよりも圧倒的に軽いので、それだけでもNVIDIA Nsight Systemsを使う価値があるかなと考えています。
ドキュメントだと解りづらいですが、次にNVIDIAが公開している動画のURLを張っておくので、そちらも合わせてを見ると、さらにわかりやすいかと思います。

# 参考
* 公式ドキュメント
https://docs.nvidia.com/nsight-systems/index.html#nsight_systems/2019.3.1-x86/01-overview.htm

* 使い方動画
https://www.youtube.com/watch?v=UaFnnXH6U4E