おうちディープラーニングPCにモニタリング環境を整える

本記事は[NTTドコモ R&D Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nttdocomo)の16日目の記事です。

# 三行でまとめると

- PCのGPU使用率などのメトリクスを取得して可視化する方法を紹介
- データの取得にはPrometheus、可視化にはGrafanaを利用
- NVIDIAだけではなくAMDのGPUにも対応

# はじめに

NTTドコモ サービスイノベーション部の三浦です。

本記事ではみなさんの家にあるGPU搭載PCのモニタリング環境を整える方法を解説します。深層学習の爆発的な流行によって巷にはGPUドライバや各種フレームワークのインストール方法を解説する記事が溢れています。しかし、セットアップを完了したのち、計算環境を更に便利にする方法や事例を紹介している記事はあまり多くない印象です。プログラムが自身の意図通りにGPUを使えているかを知ることでプログラムのリファクタリングやデバッグに役立ちます。また、プログラムのライフタイムでの各種メトリクスを知ることで、プログラム内での並列化の検討や同時実行による計算の効率化に繋げることができるでしょう。

![grafana01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261490/8f1151a3-ba48-e3af-b797-e55a20f917cd.png)

環境の構築には多少の手間がかかりますが、一度構築してしまえば常に自動的にデータが収集されて、ブラウザを開けばそのデータを遡って確認できる環境が手に入ります。それによって、データ取得用のスクリプトを毎回別のシェルで実行する手間や、その出力を整理する手間を省略することが可能になります。

以降、最初にモニタリングシステムのベースとなるPrometheusとGrafanaを簡単に説明します。次に、GPUのメトリクスを取得するための一般的なツールの紹介し、最後にそれらを組み合わせてモニタリングシステムを構築する方法を説明します。ただし、各ソフトウェアの技術的な解説や詳細な使い方までは取り扱いませんのでご注意ください。

# PrometheusとGrafanaの基礎知識

Prometheusを一言で表すならば「時系列のテキストデータを扱うのが得意なデータベースを備えたオープンソースの監視システムソフトウェア」です。実態としては中央集権的なコントローラであるPrometheusと、被モニタリング対象で動作するエージェントであるexporterの2つの主要な要素から構成されています。基本的な動作はとても単純で、Prometheusはexporterに対してHTTPリクエストを発行することでexporterが持つ値を取得して蓄積ます。もちろん他のコンポーネントも存在するのですが、今回は最も重要なこの関係だけ覚えていれば問題ありません。

なお、エージェントであるexporterは、慣例的に特定の目的ごとに作成されるため多数の種類が存在します。最も多く使われているものはおそらくですが、マシンのCPUやメモリ、ファイルシステムやIO等の基本的なメトリクスを取得するための`node_exporter`だと思います。その他にも、APIやNWインタフェースの死活監視をするための`blackbox_exporter`、MySQLの各種運用データを取得するための `mysql_exporter` なども存在します。今回は `node_exporter` と次章で説明するGPUのメトリクスを取得する exporter の2つを利用します。

https://prometheus.io/

一方、Grafanaはこちらもオープンソースのダッシュボードソフトウェアです。様々なデータソースに対応しており、手元にあるデータを用いてグラフィカルなダッシュボードの作成が可能です。Prometheusとセットで用いられることが非常に多い可視化ツールです。

https://grafana.com/

# GPUメトリクスの取得方法

前章ではモニタリングシステムのベースとなるPrometheusとexporterの関係を説明しました。本章では今回のメインテーマであるGPUのメトリクスを取得する一般的な方法とexporterを紹介します。

## NVIDIA社製GPUの場合

NVIDIA社製のGPUを計算用途に利用している人は `nvidia-smi` のコマンドを一度は実行したことがあると思います。この `nvidia-smi` はNVIDIA社のGPUのAPIを介してGPUに関する情報を取得して整形して出力するコマンドです。また、それ以外に `DCGM （NVIDIA Data Center GPU Manager)`[^dcgm]というツールも存在します。このツールはメトリクスの取得だけではなく、　複数台あるGPUをグルーピングして設定を管理したり、正常性の診断を行ったりすることが可能な機能を備えています。一般家庭向けのGTXやRTXでは一部恩恵に預かれない機能もありますが利用自体は可能です。

そして、このDCGMを動かすことによってGPUのメトリクスを取得してPrometheusに連携してくれるのが今回紹介する `dcgm_exporter` です。この `dcgm_exporter` は2021年の8月までは `NVIDIA/gpu-monitoring-tools` の一部として公開されていましたが、現在は `NVIDIA/dcgm-exporter` のリポジトリでNVIDIA社によって開発されています。

https://github.com/NVIDIA/dcgm-exporter

[^dcgm]: NVIDIA DCGM | NVIDIA Developer, https://developer.nvidia.com/dcgm

## AMD社製GPUの場合

深層学習といえばNVIDIAのGPUを思い浮かべる方が多いかもしれませんが、最近はAMD ROCm等も活発に開発されてきており、一般的とは言えないまでもAMD社製GPUのGPGPU利用が広まってきました。また、深層学習向けの有名なフレームワークであるPyTorchも２０２１年の５月公開したバージョン1.8でROCｍの公式サポートを発表しています[^1]。AMD社製のGPUにはオープンソースのkernelモジュールであるamdgpuが利用できます。詳細は割愛しますが、これによって `/sys/class/drm` 配下のデバイスファイル経由でGPUのメトリクスを取得することが可能になります。 

そのため、実はAMD社製GPUの場合は専用のexporterは必要なく、node_exporter（バージョン1.3.0, 2021年11月公開）単体で取得できるようになっており、なんとサーバのCPU使用率やメモリ使用量、IOの情報を取得する感覚でGPUのメトリクスを同様に取得することが可能になっています！！！素晴らしい！！！

https://github.com/prometheus/node_exporter/releases/tag/v1.3.0

[^1]: PyTorch for AMD ROCm™ Platform now available as Python package, https://pytorch.org/blog/pytorch-for-amd-rocm-platform-now-available-as-python-package/

# モニタリングシステムの構築

さて、これまでは個別のツールの話をしてきましたので、ここからはこれらを組み合わせてモニタリングシステムを構築したいと思います。今回各種ツールの実行にはDockerを用います。また、GPUを動作させるまでの工程は先人たちが残した多くの記事が存在するため省略します。具体的にはNVIDIAのGPUであれば`nvidia-smi`, AMDのGPUであれば`rocm-smi`が動作する状態を前提に以降の話を進めます。

## システム構成

今回構築するのは、監視ノードとして1台、非監視ノードとして2台の系3台構成のシステムです。機能が分かりやすいようにノードを分けていますが、例えば一台のGPUマシンだけで完結させたい場合、Grafana,Prometheus,各種exporterを一台にすべて集約してオールインワンで動作させることも可能です。また、これはあくまで「おうちディープラーニングPC」のように家のプライベートネットワーク上に構築された環境を前提としているため、例えば悪意を持って振る舞うユーザの存在や外部からの攻撃のことは考えていません。

#### ハードウェア情報

- aone (192.168.1.10)
    - 管理ノード、詳細略
- mana (192.168.1.11)
    - CPU: Intel Core i9 9900K
    - GPU: NVIDIA Geforce RTX3060
- sayu (192.168.1.12)
    - CPU: AMD Ryzen Threadripper 1950X
    - GPU: AMD Radeon RX 5500 XT

![arch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261490/fab45c4d-34e5-51ab-1609-8ca01e8abeda.png)

#### ソフトウェア情報

|ソフトウェア  |  バージョン |
|---|---|
|Ubuntu (OS)|20.04|
|Docker|20.10|
|Grafana  |8.2.5|
|Prometheus  |2.31.1|
|node_exporter|1.3.0|
|DCGM_exporter|2.3.1|
|nvidia driver|11.5|
|amdgpu|21.40|

## GPU搭載PCへのexporterのインストール

### mana (NVIDIA GPU)

まずは被監視対象から構築します。node_exporterとDCGM_exporterをdockerを使って動作させます。今回、被監視対象のホスト上に永続化させる情報はないため特に設定変更等は必要ありません。

```bash:node_exporterのインストール
$ sudo docker run -d --net="host" --pid="host" -v "/:/host:ro,rslave" \
    quay.io/prometheus/node-exporter:latest --path.rootfs=/host
```

```bash:DCGM_exporterのインストール
$ sudo docker run -d --gpus all --rm -p 9400:9400　\
　　　　　　　　nvcr.io/nvidia/k8s/dcgm-exporter:2.3.1-2.6.0-ubuntu20.04
```

### sayu (AMD GPU)

このマシンはnode_exporterのインストールのみで目的が達成できますが、オプション `--collector.drm` を追加する必要があります。このオプションはデフォルトでは無効化されているdrmのメトリクスを収集するためのオプションであり、これを付与することによってnode_exporterがGPUの情報を取得してくれるようになります（注：docker runのオプションではなく、Dockerで実行されているnode_exporterに渡すオプションです）。

```bash:node_exporterのインストール
$ sudo docker run -d --net="host" --pid="host" -v "/:/host:ro,rslave" \
    quay.io/prometheus/node-exporter --path.rootfs=/host --collector.drm
```

## PrometheusとGrafanaのインストール

Prometheusでは「蓄積するデータ」と「設定ファイル」をホストと共有することにします。これらを設定しないとPrometheusのコンテナを停止した場合それらのデータは消えてしまうことになるからです。以下のコマンドの二行目でホストにある設定ファイルをコンテナにマウントし、同様に三行目ではPrometheusが蓄積している各種データのディレクトリをマウントしています。今回はホスト側に `/home/miura/prometheus` というディレクトリを作成しそこにデータと設定ファイルを格納することにしています。自身の環境で実行する場合は読み替えてください。

```bash:Prometheusのインストール
$ makedir /home/miura/prometheus/data #データを蓄積するディレクトリの作成
$ sudo docker run -d -p 9090:9090 \
    -v /home/miura/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml \
    -v /home/miura/prometheus/data:/prometheus \
    prom/prometheus
```

マウントしている設定ファイルは以下の通りです。`scrape_configs` 以下にモニタリング対象の2つのexporterの情報を記述します。他にもカスタマイズは可能ですが、今回は最低限最低限以下の項目を設定すれば動きます。

```yaml:prometheus.yml
global:
  scrape_interval: 15s
  external_labels:
    monitor: 'codelab-monitor'

scrape_configs:
  - job_name: 'gpu_nvidia' # 任意に指定可能な名称
    scrape_interval: 5s # ポーリング間隔（指定しなければglobalの値が利用される）
    static_configs: # 対象のexporterが待ち受けているホスト名（IPアドレス）とポート番号
      - targets: ['192.168.1.11:9100'] # node_exporterのデフォルトポート 9100
      - targets: ['192.168.1.11:9400'] # DCGMのデフォルトポート 9400

  - job_name: 'gpu_amd' # 同上
    scrape_interval: 5s
    static_configs:
      - targets: ['192.168.1.12:9100']
```

# Grafanaによるデータの可視化

今回は記事冒頭の図のような各GPUマシンに対して「GPU使用率」、「GPUメモリ使用量」、「CPU使用量」、「メモリ使用量」を可視化した簡単なダッシュボードです。Grafanaはコテコテに凝ったダッシュボードの作成も可能ですが、ここではなるべくシンプルに欲しい情報を見られるようにしています。もちろん取得しているデータはこれ以上に多いため、必要に応じて追加や削除をすることが可能です。

## Grafanaへの初回アクセス

Grafanaはデフォルトで3000番ポートで動作しているため、`<IPアドレス>:3000` にブラウザでアクセスすると閲覧することができます。初回はパスワードの変更を求められるので、まずはデフォルトである `admin:admin` でログイン後、新パスワードを設定するようにしてください。

## データソース（Data Source）の追加

Data Sourceとは、Grafanaがどのサービスの情報を扱うかを指定するもので今回はPrometheusを指定します。

`<IPアドレス>:3000/datasources` にアクセスして `Add data source` をクリックします。遷移した先のページのリストの一番上に `Prometheus` があるのでそれをクリックします。設定画面に飛ぶと様々な設定値を記述する箇所がありますが、今回は最低限 `URL` にPrometheusが動作するマシンのIPアドレスとポートを記入すれば動作します。別々のマシンにインストールした場合は `<IPアドレス>:9090`、オールインワン構成の場合は `localhost:9090`でアクセスできるはずです。 入力後にページ下の `Save & test` をクリックして疎通確認が取れると `Data source is working` と表示されれば準備完了です。

Data sourceの追加に関する詳細は[Data sources | Grafana Labs](https://grafana.com/docs/grafana/latest/datasources/)を参照してください。Prometheus以外のデータも読み込むことが可能です。

## ダッシュボードの作成

次に選択したData souceのデータを表示するためのダッシュボードを作成します。

Grafanaのトップページ左端にある `+` がダッシュボードの作成を始めるためのボタンです。そのボタンを押すと空のダッシュボードが作成されます。画面上に表示されている `add an empty panel`をクリックすると以下のようなグラフの作成画面に遷移します。ここに可視化したいデータのクエリを記述していくことになります。例えばNVIDIA_exporterが取得したGPU使用率のデータは `DCGM_FI_DEV_GPU_UTIL` という名称でPrometheusに蓄積されています。

![grafana02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261490/8d98e40c-c9a3-8d2a-a81c-8c21f7941de9.png)


標準で取得されるメトリクスの詳細は[こちら](https://github.com/NVIDIA/dcgm-exporter/blob/main/etc/default-counters.csv)を参照してください。また、パネル及びグラフに関する詳細は [Panels | Grafana Labs](https://grafana.com/docs/grafana/latest/panels/) を参照してください。軸や凡例の設定から色の変更まで様々なカスタマイズ項目が存在します。

# おわりに

本記事ではGrafanaとPrometheusを利用してGPUのメトリクスを取得し可視化する方法を説明しました。現在、幅広く利用されているNVIDIA社のGPUだけではなく、最近GPGPU向けのエコシステムが整備されてきたAMDのGPUにも対応可能です。自分のプログラムがCPUやメモリ、GPUのようなアクセラレータ、ファイルシステムのような計算資源をどのように利用しているかを確認することは、はじめにで述べたような有益な検討材料になるとともに、ß興味深いものでもあると思います。さあ、あなたもワンランク上のおうちディープラーニング環境を整えてみませんか？