🦖

[AWS/Inf1]Neuron Coreの使用率をカスタムメトリクスとしてCloud Watchで表示する

KAZYPinkSaurus2023/01/25に公開


AWS Neuron
@KAZYPinkSaurusです。

システムを運用する上で監視は重要です。
Inf1インスタンスを運用するなら、CPUやメモリと併せてInferentiaチップの様子も監視したいですよね。
しかしCloud Watchのメトリクスを探してもチップに関するメトリクスはありません。

AWS Neuronの公式ドキュメントを熟読していたらneuron-monitorコマンドを用いてCloud Watchへカスタムメトリクスを送信する方法が書かれていたので試してみます。

実行環境

マシンタイプ AMI
inf1.xlarge Deep Learning AMI Neuron PyTorch 1.11.0 (Ubuntu 20.04) 20221107

neuron-monitor

neuron-monitorはAWS Neuronに関する情報を取得できるコマンドです。
次のコマンドを実行します[1]

$ neuron-monitor  | jq
出力結果
{
  "neuron_runtime_data": [
    {
      "pid": 41298,
      "neuron_runtime_tag": "",
      "error": "",
      "report": {
        "execution_stats": {
          "period": 0.070935409,
          "error_summary": {
            "generic": 0,
            "numerical": 0,
            "transient": 0,
            "model": 0,
            "runtime": 0,
            "hardware": 0
          },
          "execution_summary": {
            "completed": 0,
            "completed_with_err": 0,
            "completed_with_num_err": 0,
            "timed_out": 0,
            "incorrect_input": 0,
            "failed_to_queue": 0
          },
          "latency_stats": {
            "total_latency": null,
            "device_latency": null
          },
          "error": ""
        },
        "memory_used": {
          "period": 0.070905372,
          "neuron_runtime_used_bytes": {
            "host": 626905088,
            "neuron_device": 0,
            "usage_breakdown": {
              "host": {
                "application_memory": 626905088,
                "constants": 0,
                "dma_buffers": 0,
                "tensors": 0
              },
              "neuroncore_memory_usage": {
                "0": {
                  "constants": 0,
                  "model_code": 0,
                  "model_shared_scratchpad": 0,
                  "runtime_memory": 0,
                  "tensors": 0
                },
                "1": {
                  "constants": 0,
                  "model_code": 0,
                  "model_shared_scratchpad": 0,
                  "runtime_memory": 0,
                  "tensors": 0
                },
                "2": {
                  "constants": 0,
                  "model_code": 0,
                  "model_shared_scratchpad": 0,
                  "runtime_memory": 0,
                  "tensors": 0
                },
                "3": {
                  "constants": 0,
                  "model_code": 0,
                  "model_shared_scratchpad": 0,
                  "runtime_memory": 0,
                  "tensors": 0
                }
              }
            }
          },
          "loaded_models": [
            {
              "name": "XXXXXXXXXXXXXXX",
              "uuid": "XXXXXXXXXXXXXXXX",
              "model_id": 10002,
              "is_running": false,
              "subgraphs": {
                "sg_00": {
                  "memory_used_bytes": {
                    "host": 20416944,
                    "neuron_device": 17303308,
                    "usage_breakdown": {
                      "host": {
                        "application_memory": 20404608,
                        "constants": 0,
                        "dma_buffers": 12336,
                        "tensors": 0
                      },
                      "neuron_device": {
                        "constants": 121408,
                        "model_code": 0,
                        "runtime_memory": 0,
                        "tensors": 1039040
                      }
                    }
                  },
                  "neuroncore_index": 3,
                  "neuron_device_index": 0
                }
              }
            }
          ],
          "error": ""
        },
        "neuron_runtime_vcpu_usage": {
          "period": 0.070951414,
          "vcpu_usage": {
            "user": 0,
            "system": 0
          },
          "error": ""
        },
        "neuroncore_counters": {
          "period": 0.070980417,
          "neuroncores_in_use": {
            "0": {
              "neuroncore_utilization": 0
            },
            "1": {
              "neuroncore_utilization": 0
            },
            "2": {
              "neuroncore_utilization": 0
            },
            "3": {
              "neuroncore_utilization": 0
            }
          },
          "error": ""
        }
      }
    }
  ],
  "system_data": {
    "memory_info": {
      "period": 0.069966933,
      "memory_total_bytes": 8025300992,
      "memory_used_bytes": 2521931776,
      "swap_total_bytes": 0,
      "swap_used_bytes": 0,
      "error": ""
    },
    "neuron_hw_counters": {
      "period": 0.06997763,
      "neuron_devices": [
        {
          "neuron_device_index": 0,
          "mem_ecc_corrected": 0,
          "mem_ecc_uncorrected": 0,
          "sram_ecc_uncorrected": 0,
          "sram_ecc_corrected": 0
        }
      ],
      "error": ""
    },
    "vcpu_usage": {
      "period": 0.069988574,
      "average_usage": {
        "user": 0,
        "nice": 0,
        "system": 0,
        "idle": 100,
        "io_wait": 0,
        "irq": 0,
        "soft_irq": 0
      },
      "usage_data": {
        "0": {
          "user": 0,
          "nice": 0,
          "system": 0,
          "idle": 100,
          "io_wait": 0,
          "irq": 0,
          "soft_irq": 0
        },
        "1": {
          "user": 0,
          "nice": 0,
          "system": 0,
          "idle": 100,
          "io_wait": 0,
          "irq": 0,
          "soft_irq": 0
        },
        "2": {
          "user": 0,
          "nice": 0,
          "system": 0,
          "idle": 100,
          "io_wait": 0,
          "irq": 0,
          "soft_irq": 0
        },
        "3": {
          "user": 0,
          "nice": 0,
          "system": 0,
          "idle": 100,
          "io_wait": 0,
          "irq": 0,
          "soft_irq": 0
        }
      },
      "context_switch_count": 704,
      "error": ""
    }
  },
  "instance_info": {
    "instance_name": "",
    "instance_id": "i-XXXXXXXXXXXXX",
    "instance_type": "inf1.xlarge",
    "instance_availability_zone": "ap-northeast-1a",
    "instance_availability_zone_id": "apne1-az4",
    "instance_region": "ap-northeast-1",
    "ami_id": "ami-0442925238f84cec5",
    "subnet_id": "subnet-XXXXXXXXXXXXXXX",
    "error": ""
  },
  "neuron_hardware_info": {
    "neuron_device_count": 1,
    "neuroncore_per_device_count": 4,
    "error": ""
  }
}

読み込まれたモデル情報などの様々な情報が取得できていることが確認できます。
詳しくは公式ドキュメントを御覧ください。一つ一つのフィールドの説明があります。
4つあるneuroncore_utilizationがNeuronの各Coreの使用率です。

必要な権限

一般的なカスタムメトリクスに必要なものと同じですが以下の権限が必要です。

cloudwatch:PutMetricData
cloudwatch:GetMetricStatistics
cloudwatch:ListMetrics
ec2:DescribeTags

Cloud Watchにメトリクスを送る

AWS Neuronのドキュメントに書いてあるサンプルのスクリプトを用いてクラウドウォッチにメトリクスを送ってみます。
neuron-monitor-cloudwatch.pyというスクリプトはNeuron関係のAMIにはじめから用意されているものです。

cd /opt/aws/neuron/bin
neuron-monitor | neuron-monitor-cloudwatch.py --region ap-northeast-1


4つのNeuronCoreの使用率が取得できている様子
Neuron coreのメトリクスが取得できました。Inf1.xlargeなので4コア分です。
メトリクスが取得できたものの、インスタンスに関する情報はありませんでした。

インスタンス情報ごとにメトリクスを表示する

neuron-monitor-cloudwatch.pyスクリプトのオプションを見ると--common-dimsオプションを使えばinstance_id, instance_type, ami_id, neuron_runtime_tagといったdimensionsを追加できます。

neuron-monitor-cloudwatch.pyのオプション
$ python neuron-monitor-cloudwatch.py --help
usage: neuron-monitor-cloudwatch.py [-h] [-n NAMESPACE] -r REGION [-d COMMON_DIMS] [--high-resolution-metrics]

optional arguments:
  -h, --help            show this help message and exit
  -n NAMESPACE, --namespace NAMESPACE
                        Cloudwatch namespace where to post metrics
  -r REGION, --region REGION
                        Region where to post metrics
  -d COMMON_DIMS, --common-dims COMMON_DIMS
                        Comma-separated list of dimensions to be attached to each metric. Available: instance_id, instance_type, ami_id,
                        neuron_runtime_tag
  --high-resolution-metrics
                        Use 1 second resolution metrics

instance_idとinstance_typeを追加してメトリクスを送ってみます。

$ neuron-monitor | neuron-monitor-cloudwatch.py \
                   --common-dims instance_id,instance_type \
		   --region ap-northeast-1

instance_idとinstance_typeのDimensionが増えました。


KAZY-devというNameタグをつけたマシンタイプInf1.xlargeのEC2インスタンスのNeuron Coreの使用率が確認できます。
これでインスタンスごとに監視ができますね。
うれしい。

https://aws.amazon.com/jp/cloudwatch/pricing/

その他

デフォルトは1分毎のメトリクスになりますが--high-resolution-metricsオプションを使えば毎秒の高解像度なメトリクスも送れるようです。実装を見るとStorageResolutionという値を1にしています。
https://aws.amazon.com/jp/blogs/news/new-high-resolution-custom-metrics-and-alarms-for-amazon-cloudwatch/

おわりに

Inf1インスタンスをECSで使うときはサイドカーとしてモニタリングのスクリプトを入れておけば良さそう。
次回試してみようと思います。

KAZYColorfulSaurus

脚注
  1. jqコマンドは見やすくするために使用しています ↩︎

GitHubで編集を提案
Opt Fit テックブログ

「AIでジム運営が180°変わる」ジム施設向けDXソリューションGYMDXを展開する、株式会社OptFitのテックブログです!エンジニアを積極採用中!カジュアル面談も歓迎!お気軽にご連絡ください!

Discussion

ログインするとコメントできます