HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • AI 基础设施深度教程

    • AI Infra 深度教程
    • GPU容器化

      • 01-GPU 架构基础
      • NVIDIA 容器运行时
      • GPU 共享与隔离
      • GPU 监控与调试
    • Kubernetes GPU调度

      • Device Plugin 机制深度解析
      • GPU 调度器实现
      • 拓扑感知调度
      • 弹性 GPU 调度
    • AI训练平台

      • 分布式训练框架
      • 训练任务调度
      • 模型存储与管理
      • 实验管理
      • 超参数优化
    • 推理服务

      • 推理引擎原理
      • 模型服务框架
      • 动态批处理
      • 推理优化技术
      • 多模型服务
    • 异构计算

      • 05-异构计算
      • 异构计算概述
      • GPU 虚拟化技术
      • NPU 与专用 AI 芯片
      • 设备拓扑感知调度
      • 算力池化与弹性调度
    • AI工作流引擎

      • 06-AI工作流引擎
      • AI 工作流引擎概述
      • Kubeflow Pipelines 深度实践
      • 03-Argo Workflows 深度实践
      • 04-数据版本管理
      • 05-实验跟踪与模型注册
    • MLOps实践

      • 07-MLOps实践
      • 01-MLOps 成熟度模型
      • 02-数据集工程
      • 03-Feature Store 特征存储
      • 04-模型评测体系
      • 05-模型安全与治理
    • AIOps实践

      • 08-AIOps实践
      • 01-AIOps概述与架构
      • 02-异常检测算法
      • 03-根因分析与告警聚合
      • 04-智能运维决策
      • 05-AIOps平台实战
    • 面试专题

      • 09-面试专题
      • 01-AI基础设施核心面试题
      • 02-大模型面试题
      • 03-系统设计面试题
    • CUDA编程与算子开发

      • 10-CUDA 编程与算子开发
      • 01-CUDA编程模型与内存层次
      • 02-高性能 Kernel 开发实战
      • 03-Tensor Core 与矩阵运算
      • 04-算子融合与优化技术
      • 05-Triton 编程入门
    • 通信与网络底层

      • 11-通信与网络底层
      • 01-NCCL 源码深度解析
      • 02-AllReduce 算法实现
      • 03-RDMA与InfiniBand原理
      • 04-网络拓扑与通信优化
      • 05-大规模集群网络架构
    • 框架源码解析

      • 12-框架源码解析
      • 01-PyTorch分布式源码解析
      • 02-DeepSpeed源码深度解析
      • 03-Megatron-LM源码解析
      • 04-vLLM推理引擎源码解析
      • 05-HuggingFace Transformers源码解析
    • 编译优化与图优化

      • 13-编译优化与图优化
      • 01-深度学习编译器概述
      • 02-TorchDynamo与torch.compile
      • 03-XLA编译器深度解析
      • 04-算子融合与Kernel优化
      • 05-自动调度与代码生成

GPU 监控与调试

掌握 GPU 监控体系,从命令行工具到企业级监控平台

本章目标

  • 深入掌握 nvidia-smi 的所有功能和输出含义
  • 理解 DCGM (Data Center GPU Manager) 架构和使用
  • 学会构建完整的 GPU 监控体系
  • 掌握 GPU 性能分析和问题排查方法

1. nvidia-smi 深度解析

1.1 nvidia-smi 架构

┌─────────────────────────────────────────────────────────────────────┐
│                    nvidia-smi 架构                                   │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                    nvidia-smi (CLI)                          │   │
│  │                                                              │   │
│  │  功能:                                                       │   │
│  │  - GPU 状态查询和监控                                         │   │
│  │  - GPU 配置管理 (时钟、电源、MIG 等)                          │   │
│  │  - 进程管理                                                  │   │
│  │  - 拓扑查询                                                  │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │                                       │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                    NVML (libnvidia-ml.so)                    │   │
│  │              NVIDIA Management Library                       │   │
│  │                                                              │   │
│  │  C API 库,提供:                                             │   │
│  │  - GPU 信息查询                                              │   │
│  │  - 性能计数器访问                                             │   │
│  │  - 事件通知                                                  │   │
│  │  - 配置管理                                                  │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │ ioctl                                 │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                    nvidia.ko (内核驱动)                       │   │
│  │                                                              │   │
│  │  - 硬件寄存器访问                                             │   │
│  │  - 性能计数器读取                                             │   │
│  │  - 中断处理                                                  │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                             │                                       │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                    GPU 硬件                                   │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

1.2 基础输出详解

$ nvidia-smi
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 输出解析                                                                         │
├─────────────────────────────────────────────────────────────────────────────────┤
│                                                                                 │
│ +-----------------------------------------------------------------------------+ │
│ | NVIDIA-SMI 535.104.05   Driver Version: 535.104.05   CUDA Version: 12.2    | │
│ |-------------------------------+----------------------+----------------------| │
│ | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC | │
│ | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. | │
│ |===============================+======================+======================| │
│ |   0  NVIDIA A100-SXM...  On   | 00000000:07:00.0 Off |                    0 | │
│ | N/A   32C    P0    52W / 400W |    412MiB / 81920MiB |      0%      Default | │
│ +-------------------------------+----------------------+----------------------+ │
│                                                                                 │
│ 字段说明:                                                                        │
│                                                                                 │
│ ┌─────────────────────┬────────────────────────────────────────────────────┐   │
│ │ NVIDIA-SMI          │ nvidia-smi 工具版本                                 │   │
│ │ Driver Version      │ NVIDIA 驱动版本                                     │   │
│ │ CUDA Version        │ 驱动支持的最高 CUDA 版本 (不是安装的 CUDA 版本)      │   │
│ ├─────────────────────┼────────────────────────────────────────────────────┤   │
│ │ GPU                 │ GPU 索引号 (从 0 开始)                              │   │
│ │ Name                │ GPU 型号名称                                        │   │
│ │ Persistence-M       │ 持久化模式 (On/Off),建议生产环境开启               │   │
│ │ Bus-Id              │ PCIe 总线地址 (Domain:Bus:Device.Function)          │   │
│ │ Disp.A              │ Display Active,是否连接显示器                      │   │
│ │ Volatile Uncorr. ECC│ 自上次重启以来的不可纠正 ECC 错误数                  │   │
│ ├─────────────────────┼────────────────────────────────────────────────────┤   │
│ │ Fan                 │ 风扇转速百分比 (N/A 表示被动散热或不支持)            │   │
│ │ Temp                │ GPU 核心温度 (摄氏度)                               │   │
│ │ Perf                │ 性能状态 P0-P12 (P0 最高性能,P12 最低)             │   │
│ │ Pwr:Usage/Cap       │ 当前功耗 / 功耗上限 (瓦特)                          │   │
│ │ Memory-Usage        │ 显存使用量 / 总显存                                 │   │
│ │ GPU-Util            │ GPU 计算单元利用率 (过去采样周期内)                  │   │
│ │ Compute M.          │ 计算模式: Default/Exclusive_Thread/Exclusive_Process │   │
│ └─────────────────────┴────────────────────────────────────────────────────┘   │
│                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────┘

1.3 性能状态 (P-State) 详解

┌─────────────────────────────────────────────────────────────────────┐
│                    GPU 性能状态 (P-State)                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  P-State 定义了 GPU 的功耗和性能级别                                  │
│                                                                     │
│  ┌──────────┬────────────────────────────────────────────────────┐ │
│  │ P-State  │ 说明                                               │ │
│  ├──────────┼────────────────────────────────────────────────────┤ │
│  │ P0       │ 最高性能状态,GPU 运行在最高时钟频率                 │ │
│  │ P1       │ 高性能状态,略低于 P0                               │ │
│  │ P2       │ 平衡状态,中等性能                                  │ │
│  │ P3-P7    │ 中间状态,逐渐降低性能                              │ │
│  │ P8       │ 基本 3D 性能                                       │ │
│  │ P10      │ DVD 播放级别                                       │ │
│  │ P12      │ 最低性能状态,空闲                                  │ │
│  └──────────┴────────────────────────────────────────────────────┘ │
│                                                                     │
│  数据中心 GPU (Tesla/A100/H100) 通常只有:                            │
│  - P0: 最高性能 (运行计算任务时)                                     │
│  - P8: 空闲状态                                                     │
│                                                                     │
│  查看当前 P-State:                                                  │
│  $ nvidia-smi -q -d PERFORMANCE                                    │
│                                                                     │
│  锁定 GPU 时钟到最高频率 (避免 P-State 切换带来的性能抖动):           │
│  $ sudo nvidia-smi -pm 1                    # 启用持久化模式         │
│  $ sudo nvidia-smi -lgc 1410                # 锁定 GPU 时钟到 1410MHz│
│  $ sudo nvidia-smi -lmc 1593                # 锁定显存时钟           │
│                                                                     │
│  解锁时钟:                                                          │
│  $ sudo nvidia-smi -rgc                     # 重置 GPU 时钟         │
│  $ sudo nvidia-smi -rmc                     # 重置显存时钟          │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

1.4 查询命令大全

# ==================== 基础查询 ====================

# 查看所有 GPU 简要信息
nvidia-smi

# 查看指定 GPU (索引为 0)
nvidia-smi -i 0

# 查看详细信息
nvidia-smi -q

# 查看指定 GPU 的详细信息
nvidia-smi -i 0 -q

# ==================== 分类查询 ====================

# 查看内存信息
nvidia-smi -q -d MEMORY
# 输出: FB Memory Usage, BAR1 Memory Usage

# 查看利用率
nvidia-smi -q -d UTILIZATION
# 输出: GPU 利用率, 内存利用率, 编码器/解码器利用率

# 查看温度
nvidia-smi -q -d TEMPERATURE
# 输出: 当前温度, 关机温度阈值, 降频温度阈值

# 查看功耗
nvidia-smi -q -d POWER
# 输出: 当前功耗, 功耗限制, 默认/最小/最大功耗限制

# 查看时钟频率
nvidia-smi -q -d CLOCK
# 输出: Graphics/SM/Memory/Video 时钟, 最大时钟, 应用时钟

# 查看 ECC 信息
nvidia-smi -q -d ECC
# 输出: ECC 模式, 各类型错误计数

# 查看性能状态
nvidia-smi -q -d PERFORMANCE
# 输出: P-State, 时钟调节原因

# 查看进程信息
nvidia-smi -q -d PIDS
# 输出: 使用 GPU 的进程列表

# 查看支持的时钟频率
nvidia-smi -q -d SUPPORTED_CLOCKS

# 查看 PCIe 信息
nvidia-smi -q -d PCIE
# 输出: PCIe 代数, 链路宽度, 吞吐量

# ==================== 格式化输出 ====================

# CSV 格式输出 (适合脚本处理)
nvidia-smi --query-gpu=name,memory.total,memory.used,memory.free,utilization.gpu,temperature.gpu --format=csv

# 带表头的 CSV
nvidia-smi --query-gpu=index,name,memory.total,memory.used,utilization.gpu --format=csv

# 不带表头和单位
nvidia-smi --query-gpu=index,memory.used --format=csv,noheader,nounits

# ==================== 可查询的字段列表 ====================

# 查看所有可查询字段
nvidia-smi --help-query-gpu

# 常用字段:
# timestamp                    - 时间戳
# driver_version              - 驱动版本
# name, gpu_name              - GPU 名称
# gpu_bus_id                  - PCIe 总线 ID
# gpu_uuid                    - GPU UUID
# memory.total                - 总显存
# memory.used                 - 已用显存
# memory.free                 - 空闲显存
# utilization.gpu             - GPU 利用率
# utilization.memory          - 显存带宽利用率
# temperature.gpu             - GPU 温度
# power.draw                  - 当前功耗
# power.limit                 - 功耗限制
# clocks.gr                   - GPU 时钟
# clocks.mem                  - 显存时钟
# pstate                      - 性能状态
# fan.speed                   - 风扇转速
# ecc.errors.corrected.*      - 可纠正 ECC 错误
# ecc.errors.uncorrected.*    - 不可纠正 ECC 错误
# pcie.link.gen.current       - 当前 PCIe 代数
# pcie.link.width.current     - 当前 PCIe 宽度

# ==================== 进程查询 ====================

# 查看使用 GPU 的进程
nvidia-smi pmon -s um -c 1
# 输出: PID, 进程类型, SM利用率, 显存利用率, 编解码器利用率, 进程名

# 持续监控进程 (每秒刷新)
nvidia-smi pmon -s um

# 查看计算进程
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv

# ==================== 拓扑查询 ====================

# 查看 GPU 拓扑矩阵
nvidia-smi topo -m
# 输出矩阵显示 GPU 之间的连接方式:
# X    = 同一个 GPU
# SYS  = 通过系统互联 (PCIe)
# NODE = 同一 NUMA 节点
# PHB  = 通过 PCIe Host Bridge
# PXB  = 通过 PCIe Bridge
# PIX  = 通过 PCIe Switch
# NV#  = 通过 NVLink (#表示连接数)

# 查看 GPU 与 CPU 的亲和性
nvidia-smi topo -a

# 查看 P2P 访问能力
nvidia-smi topo -p2p r  # 读取
nvidia-smi topo -p2p w  # 写入
nvidia-smi topo -p2p n  # NVLink
nvidia-smi topo -p2p a  # 原子操作

1.5 监控命令

# ==================== 实时监控 ====================

# 每秒刷新一次 (默认)
nvidia-smi -l 1

# 每 500 毫秒刷新一次
nvidia-smi -lms 500

# 后台循环输出到文件
nvidia-smi -l 1 -f gpu_stats.log &

# 使用 watch 命令监控
watch -n 1 nvidia-smi

# ==================== dmon - 设备监控 ====================

# 默认监控
nvidia-smi dmon
# 输出列: gpu pwr gtemp mtemp sm mem enc dec mclk pclk

# 选择监控指标
nvidia-smi dmon -s pucm
# p: 功耗
# u: 利用率
# c: 时钟频率
# m: 显存
# t: 温度
# v: ECC 错误
# e: PCIe 吞吐

# 指定采样间隔 (毫秒)
nvidia-smi dmon -d 100

# 监控指定 GPU
nvidia-smi dmon -i 0,1

# 输出到文件
nvidia-smi dmon -f dmon.log

# ==================== pmon - 进程监控 ====================

# 默认监控
nvidia-smi pmon
# 输出列: gpu pid type sm mem enc dec command

# 选择监控指标
nvidia-smi pmon -s um
# u: 利用率 (sm, mem, enc, dec)
# m: 显存使用

# 指定采样次数
nvidia-smi pmon -c 10

# 监控指定 GPU
nvidia-smi pmon -i 0

# ==================== 事件监控 ====================

# 监控 GPU 事件
nvidia-smi events -l

# 监控特定类型事件
nvidia-smi events -l -e single_bit_ecc
nvidia-smi events -l -e double_bit_ecc
nvidia-smi events -l -e pstate_change
nvidia-smi events -l -e clock_change

# ==================== 监控脚本示例 ====================

# 每秒采集一次,输出 CSV 格式,持续 1 小时
nvidia-smi --query-gpu=timestamp,index,name,temperature.gpu,utilization.gpu,utilization.memory,memory.used,power.draw \
    --format=csv -l 1 > gpu_monitor_$(date +%Y%m%d_%H%M%S).csv &

# 后台监控并设置超时
timeout 3600 nvidia-smi -l 1 -f /var/log/nvidia/gpu_stats.log &

1.6 配置管理命令

# ==================== 持久化模式 ====================

# 查看持久化模式状态
nvidia-smi -q | grep "Persistence Mode"

# 启用持久化模式 (推荐生产环境)
sudo nvidia-smi -pm 1

# 禁用持久化模式
sudo nvidia-smi -pm 0

# 为什么要启用持久化模式?
# - 保持驱动常驻内存,避免首次调用的初始化延迟
# - 保持 GPU 配置 (时钟、功耗设置)
# - 减少启动开销

# ==================== 计算模式 ====================

# 查看计算模式
nvidia-smi -q | grep "Compute Mode"

# 设置计算模式
sudo nvidia-smi -c 0  # Default: 多进程共享
sudo nvidia-smi -c 1  # Exclusive_Thread: 单线程独占 (已废弃)
sudo nvidia-smi -c 2  # Prohibited: 禁止计算
sudo nvidia-smi -c 3  # Exclusive_Process: 单进程独占

# Exclusive_Process 模式说明:
# - 一次只允许一个进程使用 GPU
# - 其他进程尝试使用时会失败
# - 适合需要独占 GPU 的场景

# ==================== 功耗管理 ====================

# 查看功耗限制
nvidia-smi -q -d POWER

# 设置功耗限制 (瓦特)
sudo nvidia-smi -pl 300  # 设置为 300W

# 恢复默认功耗限制
sudo nvidia-smi -pl $(nvidia-smi -q -d POWER | grep "Default Power Limit" | awk '{print $5}')

# 查看支持的功耗范围
nvidia-smi -q -d POWER | grep "Power Limit"

# ==================== 时钟管理 ====================

# 查看当前时钟
nvidia-smi -q -d CLOCK

# 查看支持的时钟频率
nvidia-smi -q -d SUPPORTED_CLOCKS

# 设置应用时钟 (Graphics Clock, Memory Clock)
sudo nvidia-smi -ac 1593,1410  # 显存时钟 1593MHz, GPU 时钟 1410MHz

# 锁定 GPU 时钟到固定频率
sudo nvidia-smi -lgc 1410

# 锁定显存时钟
sudo nvidia-smi -lmc 1593

# 解锁时钟
sudo nvidia-smi -rgc  # 重置 GPU 时钟
sudo nvidia-smi -rmc  # 重置显存时钟

# 重置应用时钟到默认值
sudo nvidia-smi -rac

# ==================== ECC 管理 ====================

# 查看 ECC 状态
nvidia-smi -q -d ECC

# 启用 ECC
sudo nvidia-smi -e 1
# 需要重启才能生效

# 禁用 ECC
sudo nvidia-smi -e 0

# 清除 ECC 错误计数
sudo nvidia-smi -p 0  # 清除 Volatile 计数
sudo nvidia-smi -p 1  # 清除 Aggregate 计数

# ==================== MIG 管理 ====================

# 查看 MIG 状态
nvidia-smi -q | grep "MIG Mode"

# 启用 MIG
sudo nvidia-smi -i 0 -mig 1
sudo nvidia-smi -i 0 -r  # 重置 GPU 使配置生效

# 禁用 MIG
sudo nvidia-smi -i 0 -mig 0
sudo nvidia-smi -i 0 -r

# MIG 实例管理见上一章

# ==================== GPU 重置 ====================

# 重置 GPU (清除所有进程和配置)
sudo nvidia-smi -r -i 0

# 注意: 重置前确保没有进程使用该 GPU

1.7 nvidia-smi 实战脚本

#!/bin/bash
# gpu_health_check.sh - GPU 健康检查脚本

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

echo "=========================================="
echo "       GPU Health Check Report"
echo "       $(date)"
echo "=========================================="

# 检查 nvidia-smi 是否可用
if ! command -v nvidia-smi &> /dev/null; then
    echo -e "${RED}[ERROR] nvidia-smi not found${NC}"
    exit 1
fi

# 获取 GPU 数量
GPU_COUNT=$(nvidia-smi --query-gpu=count --format=csv,noheader,nounits | head -1)
echo -e "\n${GREEN}Found $GPU_COUNT GPU(s)${NC}\n"

# 遍历每个 GPU
for i in $(seq 0 $((GPU_COUNT-1))); do
    echo "----------------------------------------"
    echo "GPU $i:"
    echo "----------------------------------------"

    # 获取 GPU 信息
    GPU_INFO=$(nvidia-smi -i $i --query-gpu=name,driver_version,memory.total,memory.used,memory.free,temperature.gpu,power.draw,power.limit,utilization.gpu,utilization.memory,pstate,ecc.errors.uncorrected.volatile.total --format=csv,noheader,nounits)

    IFS=',' read -r NAME DRIVER MEM_TOTAL MEM_USED MEM_FREE TEMP POWER POWER_LIMIT UTIL_GPU UTIL_MEM PSTATE ECC_ERRORS <<< "$GPU_INFO"

    echo "  Name:           $NAME"
    echo "  Driver:         $DRIVER"
    echo ""

    # 显存检查
    MEM_PERCENT=$(echo "scale=1; $MEM_USED / $MEM_TOTAL * 100" | bc)
    if (( $(echo "$MEM_PERCENT > 90" | bc -l) )); then
        echo -e "  Memory:         ${RED}$MEM_USED / $MEM_TOTAL MiB ($MEM_PERCENT%)${NC}"
    elif (( $(echo "$MEM_PERCENT > 70" | bc -l) )); then
        echo -e "  Memory:         ${YELLOW}$MEM_USED / $MEM_TOTAL MiB ($MEM_PERCENT%)${NC}"
    else
        echo -e "  Memory:         ${GREEN}$MEM_USED / $MEM_TOTAL MiB ($MEM_PERCENT%)${NC}"
    fi

    # 温度检查
    TEMP=$(echo $TEMP | tr -d ' ')
    if (( TEMP > 85 )); then
        echo -e "  Temperature:    ${RED}${TEMP}°C (CRITICAL)${NC}"
    elif (( TEMP > 75 )); then
        echo -e "  Temperature:    ${YELLOW}${TEMP}°C (WARNING)${NC}"
    else
        echo -e "  Temperature:    ${GREEN}${TEMP}°C${NC}"
    fi

    # 功耗检查
    POWER=$(echo $POWER | tr -d ' ')
    POWER_LIMIT=$(echo $POWER_LIMIT | tr -d ' ')
    POWER_PERCENT=$(echo "scale=1; $POWER / $POWER_LIMIT * 100" | bc)
    echo "  Power:          ${POWER}W / ${POWER_LIMIT}W ($POWER_PERCENT%)"

    # 利用率
    UTIL_GPU=$(echo $UTIL_GPU | tr -d ' ')
    UTIL_MEM=$(echo $UTIL_MEM | tr -d ' ')
    echo "  GPU Util:       ${UTIL_GPU}%"
    echo "  Memory BW Util: ${UTIL_MEM}%"

    # P-State
    PSTATE=$(echo $PSTATE | tr -d ' ')
    echo "  P-State:        $PSTATE"

    # ECC 错误检查
    ECC_ERRORS=$(echo $ECC_ERRORS | tr -d ' ')
    if [[ "$ECC_ERRORS" != "[N/A]" ]] && [[ "$ECC_ERRORS" != "0" ]] && [[ -n "$ECC_ERRORS" ]]; then
        echo -e "  ECC Errors:     ${RED}$ECC_ERRORS (CRITICAL - Consider GPU replacement)${NC}"
    else
        echo -e "  ECC Errors:     ${GREEN}0${NC}"
    fi

    echo ""
done

# 检查持久化模式
echo "----------------------------------------"
echo "Configuration Check:"
echo "----------------------------------------"

PM_STATUS=$(nvidia-smi -q | grep "Persistence Mode" | head -1 | awk '{print $4}')
if [[ "$PM_STATUS" == "Enabled" ]]; then
    echo -e "  Persistence Mode: ${GREEN}Enabled${NC}"
else
    echo -e "  Persistence Mode: ${YELLOW}Disabled (Recommend enabling for production)${NC}"
fi

# 检查 GPU 进程
echo ""
echo "----------------------------------------"
echo "GPU Processes:"
echo "----------------------------------------"
nvidia-smi --query-compute-apps=gpu_uuid,pid,process_name,used_memory --format=csv 2>/dev/null || echo "  No compute processes running"

echo ""
echo "=========================================="
echo "Health check completed"
echo "=========================================="
#!/usr/bin/env python3
"""
gpu_monitor.py - GPU 监控和告警脚本
用于生产环境的 GPU 监控,支持阈值告警
"""

import subprocess
import json
import time
import sys
from datetime import datetime
from typing import Dict, List, Optional
import argparse

class GPUMonitor:
    """GPU 监控类"""

    # 默认告警阈值
    DEFAULT_THRESHOLDS = {
        'temperature': {'warning': 75, 'critical': 85},
        'memory_percent': {'warning': 85, 'critical': 95},
        'power_percent': {'warning': 90, 'critical': 100},
        'ecc_errors': {'warning': 1, 'critical': 10},
    }

    def __init__(self, thresholds: Optional[Dict] = None):
        self.thresholds = thresholds or self.DEFAULT_THRESHOLDS

    def query_gpus(self) -> List[Dict]:
        """查询所有 GPU 状态"""
        query_fields = [
            'index',
            'name',
            'uuid',
            'driver_version',
            'memory.total',
            'memory.used',
            'memory.free',
            'temperature.gpu',
            'power.draw',
            'power.limit',
            'utilization.gpu',
            'utilization.memory',
            'pstate',
            'ecc.errors.uncorrected.volatile.total',
            'ecc.errors.corrected.volatile.total',
            'pcie.link.gen.current',
            'pcie.link.width.current',
        ]

        cmd = [
            'nvidia-smi',
            f'--query-gpu={",".join(query_fields)}',
            '--format=csv,noheader,nounits'
        ]

        try:
            result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        except subprocess.CalledProcessError as e:
            print(f"Error running nvidia-smi: {e}", file=sys.stderr)
            return []
        except FileNotFoundError:
            print("nvidia-smi not found", file=sys.stderr)
            return []

        gpus = []
        for line in result.stdout.strip().split('\n'):
            if not line:
                continue
            values = [v.strip() for v in line.split(',')]

            # 解析数值,处理 [N/A] 情况
            def parse_value(v, default=0):
                if v in ['[N/A]', '[Not Supported]', '']:
                    return default
                try:
                    return float(v)
                except ValueError:
                    return v

            gpu = {
                'index': int(values[0]),
                'name': values[1],
                'uuid': values[2],
                'driver_version': values[3],
                'memory_total': parse_value(values[4]),
                'memory_used': parse_value(values[5]),
                'memory_free': parse_value(values[6]),
                'temperature': parse_value(values[7]),
                'power_draw': parse_value(values[8]),
                'power_limit': parse_value(values[9]),
                'utilization_gpu': parse_value(values[10]),
                'utilization_memory': parse_value(values[11]),
                'pstate': values[12],
                'ecc_uncorrected': parse_value(values[13]),
                'ecc_corrected': parse_value(values[14]),
                'pcie_gen': parse_value(values[15]),
                'pcie_width': parse_value(values[16]),
            }

            # 计算百分比
            if gpu['memory_total'] > 0:
                gpu['memory_percent'] = (gpu['memory_used'] / gpu['memory_total']) * 100
            else:
                gpu['memory_percent'] = 0

            if gpu['power_limit'] > 0:
                gpu['power_percent'] = (gpu['power_draw'] / gpu['power_limit']) * 100
            else:
                gpu['power_percent'] = 0

            gpus.append(gpu)

        return gpus

    def check_alerts(self, gpu: Dict) -> List[Dict]:
        """检查告警条件"""
        alerts = []

        # 温度告警
        temp = gpu['temperature']
        if temp >= self.thresholds['temperature']['critical']:
            alerts.append({
                'level': 'CRITICAL',
                'metric': 'temperature',
                'message': f"GPU {gpu['index']} temperature critical: {temp}°C",
                'value': temp
            })
        elif temp >= self.thresholds['temperature']['warning']:
            alerts.append({
                'level': 'WARNING',
                'metric': 'temperature',
                'message': f"GPU {gpu['index']} temperature high: {temp}°C",
                'value': temp
            })

        # 显存告警
        mem_pct = gpu['memory_percent']
        if mem_pct >= self.thresholds['memory_percent']['critical']:
            alerts.append({
                'level': 'CRITICAL',
                'metric': 'memory',
                'message': f"GPU {gpu['index']} memory critical: {mem_pct:.1f}%",
                'value': mem_pct
            })
        elif mem_pct >= self.thresholds['memory_percent']['warning']:
            alerts.append({
                'level': 'WARNING',
                'metric': 'memory',
                'message': f"GPU {gpu['index']} memory high: {mem_pct:.1f}%",
                'value': mem_pct
            })

        # ECC 错误告警
        ecc = gpu['ecc_uncorrected']
        if ecc >= self.thresholds['ecc_errors']['critical']:
            alerts.append({
                'level': 'CRITICAL',
                'metric': 'ecc_errors',
                'message': f"GPU {gpu['index']} ECC uncorrected errors critical: {ecc}",
                'value': ecc
            })
        elif ecc >= self.thresholds['ecc_errors']['warning']:
            alerts.append({
                'level': 'WARNING',
                'metric': 'ecc_errors',
                'message': f"GPU {gpu['index']} ECC uncorrected errors: {ecc}",
                'value': ecc
            })

        return alerts

    def format_output(self, gpus: List[Dict], format: str = 'text') -> str:
        """格式化输出"""
        if format == 'json':
            output = {
                'timestamp': datetime.now().isoformat(),
                'gpus': gpus
            }
            return json.dumps(output, indent=2)

        # 文本格式
        lines = []
        lines.append(f"GPU Monitor - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        lines.append("=" * 80)

        for gpu in gpus:
            lines.append(f"\nGPU {gpu['index']}: {gpu['name']}")
            lines.append(f"  UUID: {gpu['uuid']}")
            lines.append(f"  Memory: {gpu['memory_used']:.0f} / {gpu['memory_total']:.0f} MiB ({gpu['memory_percent']:.1f}%)")
            lines.append(f"  Temperature: {gpu['temperature']:.0f}°C")
            lines.append(f"  Power: {gpu['power_draw']:.1f} / {gpu['power_limit']:.1f} W ({gpu['power_percent']:.1f}%)")
            lines.append(f"  GPU Util: {gpu['utilization_gpu']:.0f}%")
            lines.append(f"  Memory BW Util: {gpu['utilization_memory']:.0f}%")
            lines.append(f"  P-State: {gpu['pstate']}")
            lines.append(f"  PCIe: Gen{gpu['pcie_gen']:.0f} x{gpu['pcie_width']:.0f}")
            lines.append(f"  ECC Errors: {gpu['ecc_uncorrected']:.0f} uncorrected, {gpu['ecc_corrected']:.0f} corrected")

            # 检查告警
            alerts = self.check_alerts(gpu)
            if alerts:
                lines.append("  Alerts:")
                for alert in alerts:
                    lines.append(f"    [{alert['level']}] {alert['message']}")

        return '\n'.join(lines)

    def run_continuous(self, interval: int = 5, format: str = 'text'):
        """持续监控"""
        try:
            while True:
                gpus = self.query_gpus()
                output = self.format_output(gpus, format)

                # 清屏并输出
                print('\033[2J\033[H', end='')
                print(output)

                time.sleep(interval)
        except KeyboardInterrupt:
            print("\nMonitoring stopped.")


def main():
    parser = argparse.ArgumentParser(description='GPU Monitoring Tool')
    parser.add_argument('-f', '--format', choices=['text', 'json'], default='text',
                        help='Output format')
    parser.add_argument('-c', '--continuous', action='store_true',
                        help='Continuous monitoring mode')
    parser.add_argument('-i', '--interval', type=int, default=5,
                        help='Monitoring interval in seconds (for continuous mode)')
    parser.add_argument('--json', action='store_true',
                        help='Output in JSON format (shortcut for -f json)')

    args = parser.parse_args()

    format = 'json' if args.json else args.format
    monitor = GPUMonitor()

    if args.continuous:
        monitor.run_continuous(interval=args.interval, format=format)
    else:
        gpus = monitor.query_gpus()
        print(monitor.format_output(gpus, format))


if __name__ == '__main__':
    main()

2. DCGM (Data Center GPU Manager)

2.1 DCGM 架构概览

┌─────────────────────────────────────────────────────────────────────┐
│                    DCGM 架构                                         │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                     客户端工具                               │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐    │   │
│  │  │ dcgmi    │  │dcgm-exporter│ │ 自定义   │  │ 集成应用 │    │   │
│  │  │ (CLI)    │  │(Prometheus)│ │  应用    │  │(SLURM等) │    │   │
│  │  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘    │   │
│  │       └─────────────┼─────────────┼─────────────┘          │   │
│  └─────────────────────┼─────────────┼────────────────────────┘   │
│                        │             │                             │
│                        ▼             ▼                             │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                   DCGM API                                   │   │
│  │  ┌─────────────────────────────────────────────────────┐    │   │
│  │  │ libdcgm.so                                          │    │   │
│  │  │                                                     │    │   │
│  │  │ - C/C++ API                                         │    │   │
│  │  │ - Python bindings (pydcgm)                          │    │   │
│  │  │ - Go bindings (dcgm-go)                             │    │   │
│  │  └─────────────────────────────────────────────────────┘    │   │
│  └─────────────────────────────┬───────────────────────────────┘   │
│                                │                                    │
│                                ▼                                    │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                 nv-hostengine (守护进程)                      │   │
│  │                                                              │   │
│  │  功能:                                                       │   │
│  │  - GPU 发现和管理                                            │   │
│  │  - 健康检查和诊断                                            │   │
│  │  - 性能指标采集                                              │   │
│  │  - 策略管理                                                  │   │
│  │  - 配置管理                                                  │   │
│  │                                                              │   │
│  │  运行模式:                                                   │   │
│  │  - Embedded (嵌入): 库直接访问 GPU                           │   │
│  │  - Standalone (独立): 通过 hostengine 访问                   │   │
│  │  - Remote (远程): 跨机器访问                                 │   │
│  └──────────────────────────┬───────────────────────────────────┘   │
│                             │                                       │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │                       NVML                                   │   │
│  │                 (底层 GPU 管理库)                             │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
│  DCGM vs nvidia-smi 对比:                                           │
│  ┌────────────────────┬────────────────────┬────────────────────┐  │
│  │ 特性               │ nvidia-smi         │ DCGM               │  │
│  ├────────────────────┼────────────────────┼────────────────────┤  │
│  │ 主要用途           │ 交互式查询/简单脚本 │ 数据中心监控      │  │
│  │ 健康检查           │ 基础               │ 完整诊断测试      │  │
│  │ 指标数量           │ ~30                │ ~150+             │  │
│  │ 历史数据           │ 不支持             │ 支持              │  │
│  │ GPU 分组           │ 不支持             │ 支持              │  │
│  │ 策略/告警          │ 不支持             │ 支持              │  │
│  │ 远程访问           │ 不支持             │ 支持              │  │
│  │ Prometheus 集成    │ 需要自己解析       │ 原生支持          │  │
│  └────────────────────┴────────────────────┴────────────────────┘  │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2.2 DCGM 安装与配置

# ==================== 安装 DCGM ====================

# Ubuntu/Debian
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg

curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

sudo apt-get update
sudo apt-get install -y datacenter-gpu-manager

# RHEL/CentOS
sudo yum install -y datacenter-gpu-manager

# 验证安装
dcgmi --version

# ==================== 启动 nv-hostengine ====================

# 启动守护进程
sudo systemctl start nvidia-dcgm
sudo systemctl enable nvidia-dcgm

# 或手动启动
sudo nv-hostengine -n  # -n 表示在前台运行

# 验证服务状态
systemctl status nvidia-dcgm

# 检查连接
dcgmi discovery -l

# ==================== 配置文件 ====================

# /etc/nvidia-dcgm/dcgm.conf
# 配置示例:

# 监听地址 (默认只监听本地)
# listen-address = 127.0.0.1:5555

# 远程访问 (允许所有地址)
# listen-address = 0.0.0.0:5555

# 日志级别
# log-level = INFO

# 日志文件
# log-file = /var/log/nvidia-dcgm/nv-hostengine.log

2.3 dcgmi 命令详解

# ==================== GPU 发现 ====================

# 列出所有 GPU
dcgmi discovery -l
# 输出:
# 4 GPUs found.
# +--------+----------------------------------------------------------------------+
# | GPU ID | Device Information                                                   |
# +========+======================================================================+
# | 0      | Name: NVIDIA A100-SXM4-80GB                                         |
# |        | PCI Bus ID: 00000000:07:00.0                                        |
# |        | Device UUID: GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx               |
# +--------+----------------------------------------------------------------------+

# 查看系统信息
dcgmi discovery -i

# 查看 NVSwitch 信息 (如果有)
dcgmi discovery -s

# ==================== 设备属性查询 ====================

# 查看所有属性
dcgmi dmon -e 1

# 查看指定 GPU
dcgmi dmon -i 0

# 常用查询
dcgmi dmon -e 150,155,203,204,1001,1002,1003,1004,1005,1006,1007,1008,1009
# 150: SM 时钟
# 155: 内存时钟
# 203: GPU 温度
# 204: 功耗
# 1001: GPU 利用率
# 1002: 内存利用率
# 1003: 编码器利用率
# 1004: 解码器利用率
# 1005: 显存已用
# 1006: 显存空闲
# 1007: ECC 单比特错误
# 1008: ECC 双比特错误
# 1009: PCIe 重放次数

# ==================== GPU 分组 ====================

# 创建 GPU 组
dcgmi group -c "training-gpus" -a 0,1,2,3
# 输出: Successfully created group "training-gpus" with a group ID of 1

# 列出所有组
dcgmi group -l

# 查看组详情
dcgmi group -g 1 -i

# 删除组
dcgmi group -d 1

# 使用组进行操作
dcgmi health -g 1 -c  # 对组内所有 GPU 运行健康检查

# ==================== 健康检查 ====================

# 查看健康检查状态
dcgmi health -g 1 -c
# 输出示例:
# +----------------------------------------------------------------------------+
# | Health Monitor Report                                                       |
# +============+========+=======================================================+
# | GPU ID     | Health | Info                                                  |
# +============+========+=======================================================+
# | 0          | Pass   | All health checks passed                             |
# | 1          | Pass   | All health checks passed                             |
# +------------+--------+-------------------------------------------------------+

# 设置健康监控类型
dcgmi health -g 1 -s p  # PCIe 检查
dcgmi health -g 1 -s m  # 内存检查
dcgmi health -g 1 -s i  # 内部检查
dcgmi health -g 1 -s t  # 热量检查
dcgmi health -g 1 -s n  # NVLink 检查
dcgmi health -g 1 -s a  # 所有检查

# 持续健康监控
dcgmi health -g 1 -c -j  # JSON 格式输出

# ==================== 诊断测试 ====================

# 运行诊断测试 (不同级别)
dcgmi diag -g 1 -r 1  # Level 1: 快速测试 (~15秒)
dcgmi diag -g 1 -r 2  # Level 2: 中等测试 (~2分钟)
dcgmi diag -g 1 -r 3  # Level 3: 完整测试 (~10分钟)

# Level 3 测试包括:
# - SM Stress Test (计算压力测试)
# - Diagnostic (诊断测试)
# - PCIe Bandwidth Test (PCIe 带宽测试)
# - Memory Bandwidth Test (显存带宽测试)
# - Targeted Stress Test (定向压力测试)

# 指定测试
dcgmi diag -g 1 -r 3 -j  # JSON 格式输出

# ==================== 策略管理 ====================

# 设置策略 (当条件满足时触发动作)
dcgmi policy -g 1 --set 0,0 -t 85 -T 90 -p 350
# --set: 设置策略
# -t: 温度警告阈值
# -T: 温度临界阈值
# -p: 功耗限制

# 查看策略
dcgmi policy -g 1 -l

# 清除策略
dcgmi policy -g 1 --clear

# ==================== 配置管理 ====================

# 查看配置
dcgmi config -g 1 --get

# 设置配置
dcgmi config -g 1 --set -c 1410 -m 1593  # 设置时钟
dcgmi config -g 1 --set -p 300           # 设置功耗限制

# 强制配置 (覆盖当前设置)
dcgmi config -g 1 --enforce

# ==================== 性能统计 ====================

# 启动统计收集
dcgmi stats -g 1 -e

# 查看统计
dcgmi stats -g 1 -v

# 导出统计
dcgmi stats -g 1 -x stats_export.json

# 停止统计收集
dcgmi stats -g 1 -d

# ==================== 字段查询 ====================

# 列出所有可查询字段
dcgmi dmon --list

# 查询特定字段
dcgmi dmon -e 150,155,203,204,1001,1002 -d 1000
# -e: 字段 ID 列表
# -d: 采样间隔 (毫秒)

# 常用字段 ID:
# 100: 驱动版本
# 101: NVML 版本
# 140: 序列号
# 150: SM 时钟
# 155: 内存时钟
# 156: 视频时钟
# 203: GPU 温度
# 204: 功耗
# 206: 总能耗
# 210: 风扇转速
# 220: PCIe 发送吞吐
# 221: PCIe 接收吞吐
# 230: PCIe 重放次数
# 240: ECC 模式
# 310: 显存带宽利用率
# 312: 编码器利用率
# 313: 解码器利用率
# 1001: GPU 利用率
# 1002: 显存利用率
# 1004-1008: 各种 ECC 错误计数

2.4 dcgm-exporter (Prometheus 集成)

# dcgm-exporter 是 DCGM 的 Prometheus 导出器
# 将 GPU 指标暴露为 Prometheus 格式

# ==================== Kubernetes 部署 ====================

# dcgm-exporter DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: dcgm-exporter
  namespace: monitoring
  labels:
    app: dcgm-exporter
spec:
  selector:
    matchLabels:
      app: dcgm-exporter
  template:
    metadata:
      labels:
        app: dcgm-exporter
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9400"
    spec:
      nodeSelector:
        nvidia.com/gpu: "true"
      containers:
      - name: dcgm-exporter
        image: nvcr.io/nvidia/k8s/dcgm-exporter:3.3.0-3.2.0-ubuntu22.04
        ports:
        - name: metrics
          containerPort: 9400
        securityContext:
          runAsNonRoot: false
          runAsUser: 0
        env:
        - name: DCGM_EXPORTER_LISTEN
          value: ":9400"
        - name: DCGM_EXPORTER_KUBERNETES
          value: "true"
        - name: DCGM_EXPORTER_COLLECTORS
          value: "/etc/dcgm-exporter/default-counters.csv"
        volumeMounts:
        - name: pod-resources
          mountPath: /var/lib/kubelet/pod-resources
          readOnly: true
        - name: dcgm-counters
          mountPath: /etc/dcgm-exporter
      volumes:
      - name: pod-resources
        hostPath:
          path: /var/lib/kubelet/pod-resources
      - name: dcgm-counters
        configMap:
          name: dcgm-exporter-counters

---
# Service for Prometheus to scrape
apiVersion: v1
kind: Service
metadata:
  name: dcgm-exporter
  namespace: monitoring
  labels:
    app: dcgm-exporter
spec:
  ports:
  - name: metrics
    port: 9400
    targetPort: 9400
  selector:
    app: dcgm-exporter

---
# ServiceMonitor for Prometheus Operator
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: dcgm-exporter
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: dcgm-exporter
  endpoints:
  - port: metrics
    interval: 15s

---
# ConfigMap for custom counters
apiVersion: v1
kind: ConfigMap
metadata:
  name: dcgm-exporter-counters
  namespace: monitoring
data:
  default-counters.csv: |
    # 格式: DCGM 字段, Prometheus 指标名, 类型, 帮助信息
    # 可用类型: gauge, counter

    # 基础指标
    DCGM_FI_DEV_SM_CLOCK, DCGM_FI_DEV_SM_CLOCK, gauge, SM clock frequency (MHz)
    DCGM_FI_DEV_MEM_CLOCK, DCGM_FI_DEV_MEM_CLOCK, gauge, Memory clock frequency (MHz)
    DCGM_FI_DEV_GPU_TEMP, DCGM_FI_DEV_GPU_TEMP, gauge, GPU temperature (C)
    DCGM_FI_DEV_MEMORY_TEMP, DCGM_FI_DEV_MEMORY_TEMP, gauge, Memory temperature (C)
    DCGM_FI_DEV_POWER_USAGE, DCGM_FI_DEV_POWER_USAGE, gauge, Power usage (W)
    DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION, DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION, counter, Total energy consumption (mJ)

    # 利用率指标
    DCGM_FI_DEV_GPU_UTIL, DCGM_FI_DEV_GPU_UTIL, gauge, GPU utilization (%)
    DCGM_FI_DEV_MEM_COPY_UTIL, DCGM_FI_DEV_MEM_COPY_UTIL, gauge, Memory utilization (%)
    DCGM_FI_DEV_ENC_UTIL, DCGM_FI_DEV_ENC_UTIL, gauge, Encoder utilization (%)
    DCGM_FI_DEV_DEC_UTIL, DCGM_FI_DEV_DEC_UTIL, gauge, Decoder utilization (%)

    # 显存指标
    DCGM_FI_DEV_FB_FREE, DCGM_FI_DEV_FB_FREE, gauge, Framebuffer free memory (MiB)
    DCGM_FI_DEV_FB_USED, DCGM_FI_DEV_FB_USED, gauge, Framebuffer used memory (MiB)

    # PCIe 指标
    DCGM_FI_DEV_PCIE_TX_THROUGHPUT, DCGM_FI_DEV_PCIE_TX_THROUGHPUT, counter, PCIe TX throughput (bytes)
    DCGM_FI_DEV_PCIE_RX_THROUGHPUT, DCGM_FI_DEV_PCIE_RX_THROUGHPUT, counter, PCIe RX throughput (bytes)
    DCGM_FI_DEV_PCIE_REPLAY_COUNTER, DCGM_FI_DEV_PCIE_REPLAY_COUNTER, counter, PCIe replay count

    # NVLink 指标 (如果适用)
    DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, counter, NVLink total bandwidth (bytes)

    # ECC 错误
    DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, counter, Single-bit ECC errors
    DCGM_FI_DEV_ECC_DBE_VOL_TOTAL, DCGM_FI_DEV_ECC_DBE_VOL_TOTAL, counter, Double-bit ECC errors

    # 性能指标
    DCGM_FI_PROF_GR_ENGINE_ACTIVE, DCGM_FI_PROF_GR_ENGINE_ACTIVE, gauge, Ratio of time graphics engine is active
    DCGM_FI_PROF_SM_ACTIVE, DCGM_FI_PROF_SM_ACTIVE, gauge, Ratio of cycles SM is active
    DCGM_FI_PROF_SM_OCCUPANCY, DCGM_FI_PROF_SM_OCCUPANCY, gauge, Ratio of warps resident on SMs
    DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, gauge, Ratio of cycles tensor (HMMA) pipe is active
    DCGM_FI_PROF_DRAM_ACTIVE, DCGM_FI_PROF_DRAM_ACTIVE, gauge, Ratio of cycles DRAM interface is active
    DCGM_FI_PROF_PCIE_TX_BYTES, DCGM_FI_PROF_PCIE_TX_BYTES, counter, PCIe TX bytes
    DCGM_FI_PROF_PCIE_RX_BYTES, DCGM_FI_PROF_PCIE_RX_BYTES, counter, PCIe RX bytes
# Docker 方式运行 dcgm-exporter
docker run -d --gpus all --rm \
    -p 9400:9400 \
    --name dcgm-exporter \
    nvcr.io/nvidia/k8s/dcgm-exporter:3.3.0-3.2.0-ubuntu22.04

# 验证指标
curl localhost:9400/metrics

# 输出示例:
# DCGM_FI_DEV_SM_CLOCK{gpu="0",UUID="GPU-xxx",device="nvidia0"} 1410
# DCGM_FI_DEV_GPU_TEMP{gpu="0",UUID="GPU-xxx",device="nvidia0"} 32
# DCGM_FI_DEV_POWER_USAGE{gpu="0",UUID="GPU-xxx",device="nvidia0"} 52
# DCGM_FI_DEV_GPU_UTIL{gpu="0",UUID="GPU-xxx",device="nvidia0"} 0
# DCGM_FI_DEV_FB_FREE{gpu="0",UUID="GPU-xxx",device="nvidia0"} 81508
# DCGM_FI_DEV_FB_USED{gpu="0",UUID="GPU-xxx",device="nvidia0"} 412

2.5 DCGM Python API

#!/usr/bin/env python3
"""
dcgm_monitor.py - 使用 DCGM Python API 进行 GPU 监控
"""

import pydcgm
import dcgm_fields
import dcgm_structs
import time
from typing import List, Dict, Optional
import json

class DCGMMonitor:
    """DCGM 监控封装类"""

    def __init__(self, embedded: bool = True):
        """
        初始化 DCGM 连接

        Args:
            embedded: True 使用嵌入模式, False 连接到 nv-hostengine
        """
        if embedded:
            self.handle = pydcgm.DcgmHandle(
                opMode=dcgm_structs.DCGM_OPERATION_MODE_AUTO
            )
        else:
            self.handle = pydcgm.DcgmHandle(
                ipAddress='127.0.0.1',
                opMode=dcgm_structs.DCGM_OPERATION_MODE_AUTO
            )

        self.system = self.handle.GetSystem()
        self.group = None

    def discover_gpus(self) -> List[int]:
        """发现所有 GPU"""
        gpu_ids = self.system.discovery.GetAllSupportedGpuIds()
        return list(gpu_ids)

    def create_group(self, name: str, gpu_ids: Optional[List[int]] = None) -> pydcgm.DcgmGroup:
        """创建 GPU 组"""
        if gpu_ids is None:
            gpu_ids = self.discover_gpus()

        self.group = self.system.GetGroupWithGpuIds(name, gpu_ids)
        return self.group

    def get_gpu_info(self, gpu_id: int) -> Dict:
        """获取 GPU 基本信息"""
        attributes = self.system.discovery.GetGpuAttributes(gpu_id)
        return {
            'gpu_id': gpu_id,
            'name': attributes.identifiers.deviceName,
            'uuid': attributes.identifiers.uuid,
            'pci_bus_id': attributes.identifiers.pciBusId,
            'serial': attributes.identifiers.serial,
            'driver_version': attributes.identifiers.driverVersion,
            'memory_total': attributes.memoryInfo.memorySizeGb,
        }

    def get_gpu_metrics(self, gpu_id: int) -> Dict:
        """获取 GPU 实时指标"""
        field_ids = [
            dcgm_fields.DCGM_FI_DEV_GPU_TEMP,
            dcgm_fields.DCGM_FI_DEV_POWER_USAGE,
            dcgm_fields.DCGM_FI_DEV_GPU_UTIL,
            dcgm_fields.DCGM_FI_DEV_MEM_COPY_UTIL,
            dcgm_fields.DCGM_FI_DEV_FB_FREE,
            dcgm_fields.DCGM_FI_DEV_FB_USED,
            dcgm_fields.DCGM_FI_DEV_SM_CLOCK,
            dcgm_fields.DCGM_FI_DEV_MEM_CLOCK,
            dcgm_fields.DCGM_FI_DEV_ECC_SBE_VOL_TOTAL,
            dcgm_fields.DCGM_FI_DEV_ECC_DBE_VOL_TOTAL,
        ]

        field_group = pydcgm.DcgmFieldGroup(
            self.handle,
            name="metrics_group",
            fieldIds=field_ids
        )

        # 创建临时组用于查询
        temp_group = self.system.GetGroupWithGpuIds("temp", [gpu_id])

        # 启用监控
        temp_group.samples.WatchFields(
            field_group,
            updateFreq=1000000,  # 1秒
            maxKeepAge=10.0,
            maxKeepSamples=10
        )

        time.sleep(1)  # 等待数据收集

        # 获取数据
        data = temp_group.samples.GetLatest(field_group)

        metrics = {}
        for gpu_data in data.values:
            for field_data in gpu_data:
                field_id = field_data.fieldId
                value = field_data.value

                field_name = dcgm_fields.DcgmFieldGetById(field_id).tag
                metrics[field_name] = value

        # 清理
        field_group.Delete()
        temp_group.Delete()

        return metrics

    def run_health_check(self, gpu_ids: Optional[List[int]] = None) -> Dict:
        """运行健康检查"""
        if self.group is None:
            self.create_group("health_check_group", gpu_ids)

        health = self.group.health

        # 设置健康监控
        health.Set(dcgm_structs.DCGM_HEALTH_WATCH_ALL)

        # 获取健康状态
        result = health.Check()

        return {
            'overall_health': result.overallHealth,
            'incidents': [
                {
                    'gpu_id': incident.entityInfo.entityId,
                    'health': incident.health,
                    'error_string': incident.error.msg,
                }
                for incident in result.incidents
            ]
        }

    def run_diagnostic(self, level: int = 1, gpu_ids: Optional[List[int]] = None) -> Dict:
        """
        运行诊断测试

        Args:
            level: 诊断级别 1-3
        """
        if self.group is None:
            self.create_group("diag_group", gpu_ids)

        diag = self.group.action.RunDiagnostic(
            dcgm_structs.DCGM_DIAG_LVL_SHORT if level == 1 else
            dcgm_structs.DCGM_DIAG_LVL_MED if level == 2 else
            dcgm_structs.DCGM_DIAG_LVL_LONG
        )

        results = []
        for test_result in diag.perGpuResponses:
            results.append({
                'gpu_id': test_result.gpuId,
                'status': test_result.status,
                'info': test_result.info,
                'warning': test_result.warning,
            })

        return {
            'level': level,
            'version': diag.version,
            'results': results
        }

    def close(self):
        """关闭 DCGM 连接"""
        if self.group:
            self.group.Delete()
        self.handle.Shutdown()


def main():
    monitor = DCGMMonitor(embedded=True)

    try:
        # 发现 GPU
        gpu_ids = monitor.discover_gpus()
        print(f"Found {len(gpu_ids)} GPU(s)")

        # 获取每个 GPU 信息
        for gpu_id in gpu_ids:
            info = monitor.get_gpu_info(gpu_id)
            print(f"\nGPU {gpu_id}:")
            print(json.dumps(info, indent=2))

            metrics = monitor.get_gpu_metrics(gpu_id)
            print("Metrics:")
            print(json.dumps(metrics, indent=2))

        # 运行健康检查
        print("\n=== Health Check ===")
        health = monitor.run_health_check()
        print(json.dumps(health, indent=2))

        # 运行快速诊断
        print("\n=== Diagnostic (Level 1) ===")
        diag = monitor.run_diagnostic(level=1)
        print(json.dumps(diag, indent=2))

    finally:
        monitor.close()


if __name__ == '__main__':
    main()

3. GPU 性能分析工具

3.1 NVIDIA Nsight Systems

# Nsight Systems - 系统级性能分析工具
# 分析 CPU-GPU 交互、kernel 调度、内存传输等

# ==================== 基础使用 ====================

# 采集 profile 数据
nsys profile -o my_report python train.py

# 指定输出格式
nsys profile -o my_report --export=sqlite,json python train.py

# 只采集 CUDA 活动
nsys profile --trace=cuda python train.py

# 采集多种活动
nsys profile --trace=cuda,nvtx,osrt python train.py
# cuda: CUDA API 和 kernel
# nvtx: NVIDIA Tools Extension 标注
# osrt: OS Runtime (系统调用)

# ==================== 高级选项 ====================

# 延迟开始采集
nsys profile --delay=10 -d 30 python train.py
# --delay=10: 启动后等待 10 秒开始采集
# -d 30: 采集 30 秒

# 设置采样频率
nsys profile --sampling-frequency=10000 python train.py

# 采集 GPU 指标
nsys profile --gpu-metrics-device=all python train.py

# 采集 CUDA 内存操作
nsys profile --cuda-memory-usage=true python train.py

# ==================== 分析报告 ====================

# 查看报告统计
nsys stats my_report.nsys-rep

# 导出为其他格式
nsys export --type=json my_report.nsys-rep

# 在 GUI 中打开 (需要图形界面)
nsys-ui my_report.nsys-rep

# ==================== 常见分析场景 ====================

# 1. 分析训练循环
nsys profile \
    --trace=cuda,nvtx \
    --cuda-memory-usage=true \
    --gpu-metrics-device=all \
    -o training_profile \
    python train.py --epochs=1

# 2. 分析推理延迟
nsys profile \
    --trace=cuda \
    --stats=true \
    -o inference_profile \
    python inference.py

# 3. 分析数据加载
nsys profile \
    --trace=cuda,osrt \
    --sample=cpu \
    -o dataload_profile \
    python train.py
# 使用 NVTX 标注代码区域
import torch
import nvtx

class TrainingLoop:
    def __init__(self, model, optimizer):
        self.model = model
        self.optimizer = optimizer

    def train_epoch(self, dataloader):
        for batch_idx, (data, target) in enumerate(dataloader):
            # 标注数据传输
            with nvtx.annotate("Data to GPU", color="blue"):
                data = data.cuda()
                target = target.cuda()

            # 标注前向传播
            with nvtx.annotate("Forward", color="green"):
                output = self.model(data)
                loss = F.cross_entropy(output, target)

            # 标注反向传播
            with nvtx.annotate("Backward", color="red"):
                self.optimizer.zero_grad()
                loss.backward()

            # 标注优化器更新
            with nvtx.annotate("Optimizer Step", color="yellow"):
                self.optimizer.step()

# PyTorch 内置的 profiler 也可以导出 nsys 格式
with torch.profiler.profile(
    activities=[
        torch.profiler.ProfilerActivity.CPU,
        torch.profiler.ProfilerActivity.CUDA,
    ],
    schedule=torch.profiler.schedule(wait=1, warmup=1, active=3),
    on_trace_ready=torch.profiler.tensorboard_trace_handler('./log'),
    record_shapes=True,
    with_stack=True
) as prof:
    for step in range(5):
        train_step()
        prof.step()

3.2 NVIDIA Nsight Compute

# Nsight Compute - Kernel 级性能分析工具
# 深入分析单个 CUDA kernel 的性能

# ==================== 基础使用 ====================

# 分析所有 kernel
ncu python train.py

# 分析特定 kernel
ncu --kernel-name "volta_sgemm" python train.py

# 分析前 N 个 kernel
ncu --launch-count 10 python train.py

# 跳过前 N 个 kernel
ncu --launch-skip 100 --launch-count 10 python train.py

# ==================== 指标集 ====================

# 使用预定义指标集
ncu --set full python train.py
# full: 完整指标集
# detailed: 详细指标
# basic: 基础指标
# roofline: Roofline 分析

# 指定单个指标
ncu --metrics sm__throughput.avg.pct_of_peak_sustained_elapsed python train.py

# 指定多个指标
ncu --metrics \
    sm__throughput.avg.pct_of_peak_sustained_elapsed,\
    dram__throughput.avg.pct_of_peak_sustained_elapsed,\
    gpu__compute_memory_throughput.avg.pct_of_peak_sustained_elapsed \
    python train.py

# ==================== 输出格式 ====================

# 输出到文件
ncu -o kernel_analysis python train.py

# CSV 格式
ncu --csv python train.py > kernel_metrics.csv

# 页面格式 (适合查看)
ncu --page raw python train.py

# ==================== 高级分析 ====================

# Roofline 分析
ncu --set roofline -o roofline_report python train.py

# 源码关联 (需要编译时带 -lineinfo)
ncu --set source python train.py

# 比较两次运行
ncu --import baseline.ncu-rep --import optimized.ncu-rep

# ==================== 常用指标解释 ====================

# Throughput 指标:
# sm__throughput: SM 吞吐量 (计算利用率)
# dram__throughput: 显存带宽利用率

# 执行指标:
# sm__warps_active: 活跃的 warps 数
# sm__cycles_elapsed: 执行周期数

# 内存指标:
# l1tex__t_bytes: L1 cache 访问字节
# lts__t_bytes: L2 cache 访问字节
# dram__bytes: 显存访问字节

# 指令指标:
# sm__inst_executed: 执行的指令数
# sm__sass_inst_executed_op_tensor: Tensor Core 指令数

3.3 PyTorch Profiler

#!/usr/bin/env python3
"""
pytorch_profiler.py - PyTorch GPU 性能分析
"""

import torch
import torch.nn as nn
import torch.profiler
from torch.profiler import profile, record_function, ProfilerActivity
import time

def create_model():
    """创建示例模型"""
    return nn.Sequential(
        nn.Linear(1024, 4096),
        nn.ReLU(),
        nn.Linear(4096, 4096),
        nn.ReLU(),
        nn.Linear(4096, 1024),
    ).cuda()

def profile_basic():
    """基础性能分析"""
    model = create_model()
    x = torch.randn(32, 1024).cuda()

    # 预热
    for _ in range(10):
        model(x)
    torch.cuda.synchronize()

    # 性能分析
    with profile(
        activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
        record_shapes=True,
        profile_memory=True,
        with_stack=True,
    ) as prof:
        with record_function("model_inference"):
            output = model(x)

    # 打印结果
    print(prof.key_averages().table(
        sort_by="cuda_time_total",
        row_limit=20
    ))

    # 导出 Chrome trace
    prof.export_chrome_trace("trace.json")

    # 导出 stacks (火焰图)
    prof.export_stacks("stacks.txt", "self_cuda_time_total")

def profile_training_loop():
    """分析训练循环"""
    model = create_model()
    optimizer = torch.optim.Adam(model.parameters())
    criterion = nn.MSELoss()

    x = torch.randn(32, 1024).cuda()
    y = torch.randn(32, 1024).cuda()

    # 使用 schedule 控制采集
    with profile(
        activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
        schedule=torch.profiler.schedule(
            wait=1,      # 等待 1 步
            warmup=1,    # 预热 1 步
            active=3,    # 采集 3 步
            repeat=2     # 重复 2 次
        ),
        on_trace_ready=torch.profiler.tensorboard_trace_handler('./log/profiler'),
        record_shapes=True,
        profile_memory=True,
        with_stack=True,
    ) as prof:
        for step in range(10):
            with record_function("forward"):
                output = model(x)
                loss = criterion(output, y)

            with record_function("backward"):
                optimizer.zero_grad()
                loss.backward()

            with record_function("optimizer"):
                optimizer.step()

            prof.step()  # 标记步结束

def profile_memory():
    """内存分析"""
    model = create_model()

    # 重置内存统计
    torch.cuda.reset_peak_memory_stats()
    torch.cuda.empty_cache()

    print(f"Initial memory: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")

    with profile(
        activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
        profile_memory=True,
        record_shapes=True,
    ) as prof:
        x = torch.randn(64, 1024).cuda()
        print(f"After input: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")

        output = model(x)
        print(f"After forward: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")

        loss = output.sum()
        loss.backward()
        print(f"After backward: {torch.cuda.memory_allocated() / 1024**2:.2f} MB")

    # 打印内存事件
    print("\n=== Memory Events ===")
    print(prof.key_averages().table(
        sort_by="self_cuda_memory_usage",
        row_limit=10
    ))

    print(f"\nPeak memory: {torch.cuda.max_memory_allocated() / 1024**2:.2f} MB")

def profile_custom_kernels():
    """分析自定义操作"""
    model = create_model()
    x = torch.randn(32, 1024).cuda()

    with profile(
        activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
        with_stack=True,
    ) as prof:
        # 标注不同阶段
        with record_function("stage_1_preprocess"):
            x_norm = (x - x.mean()) / x.std()

        with record_function("stage_2_inference"):
            output = model(x_norm)

        with record_function("stage_3_postprocess"):
            result = torch.softmax(output, dim=-1)

    # 打印按阶段分组的结果
    print(prof.key_averages(group_by_input_shape=True).table(
        sort_by="cuda_time_total",
        row_limit=20
    ))

class GPUMemoryTracker:
    """GPU 内存追踪器"""

    def __init__(self, device=0):
        self.device = device
        self.history = []

    def snapshot(self, tag: str = ""):
        """记录当前内存状态"""
        self.history.append({
            'tag': tag,
            'allocated': torch.cuda.memory_allocated(self.device),
            'reserved': torch.cuda.memory_reserved(self.device),
            'max_allocated': torch.cuda.max_memory_allocated(self.device),
            'timestamp': time.time()
        })

    def report(self):
        """生成报告"""
        print("\n=== GPU Memory Report ===")
        print(f"{'Tag':<30} {'Allocated':<15} {'Reserved':<15} {'Max Alloc':<15}")
        print("-" * 75)

        for h in self.history:
            print(f"{h['tag']:<30} "
                  f"{h['allocated']/1024**2:>12.2f} MB "
                  f"{h['reserved']/1024**2:>12.2f} MB "
                  f"{h['max_allocated']/1024**2:>12.2f} MB")

    def reset(self):
        """重置统计"""
        self.history = []
        torch.cuda.reset_peak_memory_stats(self.device)
        torch.cuda.empty_cache()


def analyze_tensor_core_usage():
    """分析 Tensor Core 使用情况"""
    # Tensor Core 需要特定的数据类型和维度
    # FP16 或 BF16, 矩阵维度是 8 的倍数

    # 不使用 Tensor Core
    a = torch.randn(1000, 1000).cuda()
    b = torch.randn(1000, 1000).cuda()

    with profile(activities=[ProfilerActivity.CUDA]) as prof:
        with record_function("FP32_matmul"):
            c = torch.mm(a, b)

    print("FP32 (No Tensor Core):")
    print(prof.key_averages().table(row_limit=5))

    # 使用 Tensor Core (FP16, 维度是 8 的倍数)
    a_fp16 = torch.randn(1024, 1024, dtype=torch.float16).cuda()
    b_fp16 = torch.randn(1024, 1024, dtype=torch.float16).cuda()

    with profile(activities=[ProfilerActivity.CUDA]) as prof:
        with record_function("FP16_matmul"):
            c_fp16 = torch.mm(a_fp16, b_fp16)

    print("\nFP16 (With Tensor Core):")
    print(prof.key_averages().table(row_limit=5))


if __name__ == '__main__':
    print("=== Basic Profiling ===")
    profile_basic()

    print("\n=== Training Loop Profiling ===")
    profile_training_loop()

    print("\n=== Memory Profiling ===")
    profile_memory()

    print("\n=== Custom Kernels Profiling ===")
    profile_custom_kernels()

    print("\n=== Tensor Core Analysis ===")
    analyze_tensor_core_usage()

4. GPU 问题排查

4.1 常见问题诊断

┌─────────────────────────────────────────────────────────────────────┐
│                    GPU 问题排查流程图                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  问题现象                                                           │
│      │                                                              │
│      ▼                                                              │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 1. 检查 GPU 是否被识别                                        │   │
│  │    nvidia-smi                                                │   │
│  │    lspci | grep -i nvidia                                    │   │
│  │                                                              │   │
│  │    ✗ 未识别 → 检查硬件连接、驱动安装                          │   │
│  │    ✓ 已识别 → 继续下一步                                      │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │                                       │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 2. 检查驱动状态                                               │   │
│  │    cat /proc/driver/nvidia/version                           │   │
│  │    dmesg | grep -i nvidia                                    │   │
│  │                                                              │   │
│  │    ✗ 驱动错误 → 重新安装驱动                                  │   │
│  │    ✓ 驱动正常 → 继续下一步                                    │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │                                       │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 3. 检查 GPU 健康状态                                          │   │
│  │    nvidia-smi -q -d ECC     # ECC 错误                       │   │
│  │    nvidia-smi -q -d POWER   # 功耗状态                       │   │
│  │    nvidia-smi -q -d TEMPERATURE  # 温度                      │   │
│  │    dcgmi health -c          # DCGM 健康检查                   │   │
│  │                                                              │   │
│  │    ✗ 硬件问题 → 联系硬件支持                                  │   │
│  │    ✓ 硬件正常 → 继续下一步                                    │   │
│  └──────────────────────────┬──────────────────────────────────┘   │
│                             │                                       │
│                             ▼                                       │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │ 4. 检查应用层问题                                             │   │
│  │    - CUDA 版本兼容性                                         │   │
│  │    - 显存不足 (OOM)                                          │   │
│  │    - 进程冲突                                                │   │
│  │    - 性能问题                                                │   │
│  └─────────────────────────────────────────────────────────────┘   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

4.2 问题排查命令集

# ==================== 驱动和硬件检查 ====================

# 检查 GPU 是否被系统识别
lspci | grep -i nvidia
# 输出示例: 07:00.0 3D controller: NVIDIA Corporation GA100 [A100]

# 检查驱动版本
cat /proc/driver/nvidia/version
# 输出: NVRM version: NVIDIA UNIX x86_64 Kernel Module  535.104.05

# 检查内核模块
lsmod | grep nvidia
# nvidia_uvm, nvidia_drm, nvidia_modeset, nvidia

# 检查驱动加载日志
dmesg | grep -i nvidia | tail -50

# 检查 GPU 设备文件
ls -la /dev/nvidia*

# ==================== ECC 错误检查 ====================

# 查看 ECC 状态
nvidia-smi -q -d ECC

# 关键指标:
# - Volatile: 自上次驱动加载以来的错误
# - Aggregate: GPU 生命周期内的总错误

# 如果看到大量 ECC 错误,特别是 Double Bit 错误:
# - 可能是硬件问题
# - 需要联系供应商更换

# 清除 ECC 计数器 (用于排查是否是偶发)
sudo nvidia-smi -p 0  # 清除 volatile
# 然后运行一段时间工作负载,再检查

# ==================== 温度问题排查 ====================

# 查看温度
nvidia-smi -q -d TEMPERATURE

# 关键阈值:
# - GPU Shutdown Temp: 通常 90-100°C
# - GPU Slowdown Temp: 通常 80-85°C

# 如果温度过高:
# 1. 检查散热系统
# 2. 检查机房温度
# 3. 检查 GPU 负载是否异常
# 4. 考虑降低功耗限制

# 监控温度变化
nvidia-smi dmon -s t -d 1000  # 每秒采集一次温度

# ==================== 功耗问题排查 ====================

# 查看功耗状态
nvidia-smi -q -d POWER

# 检查是否被限制
nvidia-smi -q | grep "Performance State"
# P0 = 最高性能
# 如果不在 P0,检查:
# - 功耗限制
# - 温度限制
# - 时钟限制

# 查看限制原因
nvidia-smi -q | grep -A 10 "Clocks Throttle Reasons"
# Idle: GPU 空闲
# Applications Clocks Setting: 应用时钟设置
# SW Power Cap: 软件功耗限制
# HW Slowdown: 硬件降频 (温度/功耗)
# Sync Boost: 同步加速限制
# SW Thermal Slowdown: 软件温度降频
# HW Thermal Slowdown: 硬件温度降频
# HW Power Brake Slowdown: 功耗制动

# ==================== 显存问题排查 ====================

# 查看显存使用
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv

# 查找显存泄漏
# 1. 记录初始状态
nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits
# 2. 运行一段时间后再检查
# 3. 如果持续增长,可能存在泄漏

# 清理显存 (PyTorch)
# torch.cuda.empty_cache()

# 强制杀死占用 GPU 的进程
sudo fuser -v /dev/nvidia*
sudo kill -9 <pid>

# ==================== PCIe 问题排查 ====================

# 查看 PCIe 信息
nvidia-smi -q -d PCIE

# 关键检查:
# - Link Gen: 应该是 Gen4 或 Gen5
# - Link Width: 应该是 x16

# 如果 Link Width 降级 (如变成 x1):
# - 检查物理连接
# - 检查主板 BIOS 设置
# - 检查 PCIe 插槽是否正常

# 查看 PCIe 带宽测试
nvidia-smi topo -m

# 运行带宽测试
dcgmi diag -r 2  # 包含 PCIe 带宽测试

# ==================== NVLink 问题排查 ====================

# 查看 NVLink 状态
nvidia-smi nvlink -s

# 查看 NVLink 错误计数
nvidia-smi nvlink -e

# 查看 NVLink 拓扑
nvidia-smi topo -m

# ==================== 进程问题排查 ====================

# 查看使用 GPU 的进程
nvidia-smi pmon -s um

# 查看进程详情
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv

# 检查 zombie GPU 进程
# 有时进程退出但 GPU 资源未释放
ps aux | grep -E "python|cuda" | grep -v grep
nvidia-smi

# 如果发现不一致,尝试:
sudo nvidia-smi -r  # 重置 GPU (会杀死所有进程)

4.3 性能问题排查

# ==================== GPU 利用率低 ====================

# 诊断步骤:

# 1. 检查 GPU 利用率
nvidia-smi dmon -s u -d 1000

# 2. 如果 GPU 利用率低,可能原因:
#    a. CPU 瓶颈 (数据加载跟不上)
#    b. 内存带宽瓶颈
#    c. I/O 瓶颈
#    d. 同步点太多

# 3. 使用 nsys 分析
nsys profile --trace=cuda,osrt python train.py

# 查看 CUDA API 调用时间分布
# 如果 cudaMemcpy 占比高 → 数据传输瓶颈
# 如果 cudaStreamSynchronize 占比高 → 同步开销大

# 4. 检查数据加载
# PyTorch DataLoader num_workers 设置
# 使用 pin_memory=True
# 使用 prefetch_factor

# ==================== 显存带宽瓶颈 ====================

# 1. 检查显存带宽利用率
nvidia-smi dmon -s u -d 1000
# 看 Memory Utilization 列

# 2. 使用 ncu 分析
ncu --metrics dram__throughput.avg.pct_of_peak_sustained_elapsed python inference.py

# 如果接近峰值,说明是带宽瓶颈
# 优化方法:
# - 使用更小的数据类型 (FP16/INT8)
# - 减少内存访问 (算子融合)
# - 使用 Flash Attention 等优化算法

# ==================== Tensor Core 未使用 ====================

# 检查是否使用 Tensor Core
ncu --metrics sm__inst_executed_pipe_tensor python train.py

# 如果 Tensor 指令数为 0,检查:
# 1. 数据类型: 需要 FP16/BF16/TF32
# 2. 矩阵维度: 需要是 8 的倍数
# 3. 是否启用 TF32: torch.backends.cuda.matmul.allow_tf32 = True

# ==================== CUDA kernel 优化 ====================

# 使用 ncu 分析单个 kernel
ncu --set full --kernel-name "ampere_sgemm" python train.py

# 关注指标:
# - SM Throughput: 计算利用率
# - Memory Throughput: 内存带宽利用率
# - Achieved Occupancy: SM 占用率

# Roofline 分析
ncu --set roofline -o roofline python train.py

4.4 容器中的 GPU 问题排查

# ==================== 容器 GPU 访问问题 ====================

# 1. 检查容器是否能看到 GPU
docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi

# 2. 如果失败,检查 nvidia-container-runtime
nvidia-container-cli info

# 3. 检查 Docker 配置
cat /etc/docker/daemon.json | grep nvidia

# 4. 检查容器内的设备
docker run --rm --gpus all nvidia/cuda:12.0-base ls -la /dev/nvidia*

# 5. 检查驱动库是否正确挂载
docker run --rm --gpus all nvidia/cuda:12.0-base ldconfig -p | grep nvidia

# ==================== Kubernetes GPU 问题 ====================

# 1. 检查节点 GPU 资源
kubectl describe node <node-name> | grep -A 10 "Allocatable"

# 2. 检查 device plugin 状态
kubectl get pods -n kube-system | grep nvidia
kubectl logs -n kube-system <nvidia-device-plugin-pod>

# 3. 检查 Pod 是否获得 GPU
kubectl describe pod <pod-name> | grep -A 5 "Limits"

# 4. 进入 Pod 检查 GPU
kubectl exec -it <pod-name> -- nvidia-smi

# 5. 检查 MIG 配置 (如果使用)
kubectl get node <node> -o jsonpath='{.status.allocatable}' | jq

# ==================== 常见容器问题 ====================

# 问题: "Failed to initialize NVML"
# 原因: 驱动版本不匹配
# 解决: 使用与宿主机驱动兼容的 CUDA 镜像

# 问题: "no CUDA-capable device is detected"
# 原因: --gpus 参数未传递或配置错误
# 解决: 检查 Docker/containerd 配置

# 问题: 容器内 GPU 数量与预期不符
# 原因: NVIDIA_VISIBLE_DEVICES 环境变量
# 解决: 检查环境变量设置

# 问题: 容器内 GPU 性能低于预期
# 原因: 可能是共享 GPU 或 MIG
# 解决: 检查 GPU 共享配置

5. 生产环境监控体系

5.1 完整监控架构

┌─────────────────────────────────────────────────────────────────────────────┐
│                    生产环境 GPU 监控架构                                      │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│                          ┌─────────────────┐                                │
│                          │    Grafana      │                                │
│                          │   Dashboard     │                                │
│                          └────────┬────────┘                                │
│                                   │                                         │
│                          ┌────────┴────────┐                                │
│                          │   Prometheus    │                                │
│                          │                 │                                │
│                          │  - 指标存储     │                                │
│                          │  - 告警规则     │                                │
│                          │  - 查询引擎     │                                │
│                          └────────┬────────┘                                │
│                                   │                                         │
│         ┌────────────────────────┬┴──────────────────────────┐              │
│         │                        │                           │              │
│         ▼                        ▼                           ▼              │
│  ┌─────────────┐         ┌─────────────┐          ┌─────────────────┐      │
│  │dcgm-exporter│         │node-exporter│          │kube-state-metrics│     │
│  │             │         │             │          │                 │      │
│  │ GPU 指标    │         │ 系统指标    │          │ K8s 资源指标    │      │
│  │ - 利用率    │         │ - CPU       │          │ - Pod 状态      │      │
│  │ - 显存      │         │ - 内存      │          │ - GPU 请求      │      │
│  │ - 温度      │         │ - 磁盘      │          │                 │      │
│  │ - 功耗      │         │ - 网络      │          │                 │      │
│  └──────┬──────┘         └──────┬──────┘          └────────┬────────┘      │
│         │                       │                          │               │
│  ┌──────┴──────┐         ┌──────┴──────┐          ┌────────┴────────┐      │
│  │   GPU Node  │         │  All Nodes  │          │  Kubernetes     │      │
│  │             │         │             │          │  API Server     │      │
│  │  ┌───────┐  │         │             │          │                 │      │
│  │  │ GPU 0 │  │         │             │          │                 │      │
│  │  │ GPU 1 │  │         │             │          │                 │      │
│  │  │  ...  │  │         │             │          │                 │      │
│  │  └───────┘  │         │             │          │                 │      │
│  └─────────────┘         └─────────────┘          └─────────────────┘      │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

5.2 Prometheus 告警规则

# prometheus-gpu-alerts.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: gpu-alerts
  namespace: monitoring
spec:
  groups:
  - name: gpu.rules
    rules:
    # GPU 温度告警
    - alert: GPUTemperatureWarning
      expr: DCGM_FI_DEV_GPU_TEMP > 75
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "GPU temperature warning on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} on {{ $labels.instance }} temperature is {{ $value }}°C"

    - alert: GPUTemperatureCritical
      expr: DCGM_FI_DEV_GPU_TEMP > 85
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "GPU temperature critical on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} on {{ $labels.instance }} temperature is {{ $value }}°C"

    # GPU 显存告警
    - alert: GPUMemoryUsageHigh
      expr: (DCGM_FI_DEV_FB_USED / (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)) * 100 > 90
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "GPU memory usage high on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} memory usage is {{ $value | printf \"%.1f\" }}%"

    # GPU 利用率告警 (低利用率可能表示问题)
    - alert: GPULowUtilization
      expr: DCGM_FI_DEV_GPU_UTIL < 10 and DCGM_FI_DEV_FB_USED > 1000
      for: 30m
      labels:
        severity: warning
      annotations:
        summary: "GPU underutilized on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} has low utilization ({{ $value }}%) but memory is allocated"

    # ECC 错误告警
    - alert: GPUECCErrorsDetected
      expr: increase(DCGM_FI_DEV_ECC_DBE_VOL_TOTAL[1h]) > 0
      labels:
        severity: critical
      annotations:
        summary: "GPU ECC double-bit errors detected on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} has ECC errors. Consider replacement."

    # GPU 掉线告警
    - alert: GPUDown
      expr: up{job="dcgm-exporter"} == 0
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "GPU monitoring down on {{ $labels.instance }}"
        description: "dcgm-exporter is not responding on {{ $labels.instance }}"

    # 功耗告警
    - alert: GPUPowerLimitReached
      expr: (DCGM_FI_DEV_POWER_USAGE / DCGM_FI_DEV_POWER_LIMIT) * 100 > 95
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "GPU power limit reached on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} is at {{ $value | printf \"%.1f\" }}% of power limit"

    # PCIe 错误告警
    - alert: GPUPCIeReplayErrors
      expr: increase(DCGM_FI_DEV_PCIE_REPLAY_COUNTER[1h]) > 100
      labels:
        severity: warning
      annotations:
        summary: "High PCIe replay errors on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} has high PCIe replay count"

    # NVLink 错误告警
    - alert: GPUNVLinkErrors
      expr: increase(DCGM_FI_DEV_NVLINK_CRC_FLIT_ERROR_COUNT_TOTAL[1h]) > 0
      labels:
        severity: warning
      annotations:
        summary: "NVLink errors detected on {{ $labels.gpu }}"
        description: "GPU {{ $labels.gpu }} has NVLink CRC errors"

  - name: gpu.capacity
    rules:
    # GPU 资源碎片告警
    - alert: GPUResourceFragmentation
      expr: |
        (
          sum(kube_node_status_allocatable{resource="nvidia_com_gpu"}) -
          sum(kube_pod_container_resource_requests{resource="nvidia_com_gpu"})
        ) > 2
        and
        count(kube_pod_status_phase{phase="Pending"} == 1) > 0
      for: 15m
      labels:
        severity: warning
      annotations:
        summary: "GPU resource fragmentation detected"
        description: "There are free GPUs but pending pods cannot be scheduled"

    # GPU 利用率低于期望
    - alert: ClusterGPUUnderutilized
      expr: avg(DCGM_FI_DEV_GPU_UTIL) < 30
      for: 1h
      labels:
        severity: info
      annotations:
        summary: "Cluster GPU underutilization"
        description: "Average GPU utilization is {{ $value | printf \"%.1f\" }}%"

5.3 Grafana Dashboard

{
  "dashboard": {
    "title": "GPU Monitoring Dashboard",
    "panels": [
      {
        "title": "GPU Utilization",
        "type": "graph",
        "targets": [
          {
            "expr": "DCGM_FI_DEV_GPU_UTIL",
            "legendFormat": "GPU {{gpu}} - {{instance}}"
          }
        ]
      },
      {
        "title": "GPU Memory Usage",
        "type": "graph",
        "targets": [
          {
            "expr": "DCGM_FI_DEV_FB_USED / 1024",
            "legendFormat": "GPU {{gpu}} Used (GiB)"
          },
          {
            "expr": "(DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE) / 1024",
            "legendFormat": "GPU {{gpu}} Total (GiB)"
          }
        ]
      },
      {
        "title": "GPU Temperature",
        "type": "gauge",
        "targets": [
          {
            "expr": "DCGM_FI_DEV_GPU_TEMP"
          }
        ],
        "thresholds": {
          "mode": "absolute",
          "steps": [
            {"color": "green", "value": null},
            {"color": "yellow", "value": 70},
            {"color": "red", "value": 80}
          ]
        }
      },
      {
        "title": "GPU Power Usage",
        "type": "graph",
        "targets": [
          {
            "expr": "DCGM_FI_DEV_POWER_USAGE",
            "legendFormat": "GPU {{gpu}} Power (W)"
          }
        ]
      },
      {
        "title": "GPU SM Clock",
        "type": "graph",
        "targets": [
          {
            "expr": "DCGM_FI_DEV_SM_CLOCK",
            "legendFormat": "GPU {{gpu}} SM Clock (MHz)"
          }
        ]
      },
      {
        "title": "GPU Memory Bandwidth Utilization",
        "type": "graph",
        "targets": [
          {
            "expr": "DCGM_FI_DEV_MEM_COPY_UTIL",
            "legendFormat": "GPU {{gpu}}"
          }
        ]
      },
      {
        "title": "ECC Errors (Uncorrected)",
        "type": "stat",
        "targets": [
          {
            "expr": "sum(DCGM_FI_DEV_ECC_DBE_VOL_TOTAL) by (gpu)"
          }
        ]
      },
      {
        "title": "PCIe Throughput",
        "type": "graph",
        "targets": [
          {
            "expr": "rate(DCGM_FI_DEV_PCIE_TX_THROUGHPUT[5m]) / 1024 / 1024",
            "legendFormat": "GPU {{gpu}} TX (MB/s)"
          },
          {
            "expr": "rate(DCGM_FI_DEV_PCIE_RX_THROUGHPUT[5m]) / 1024 / 1024",
            "legendFormat": "GPU {{gpu}} RX (MB/s)"
          }
        ]
      }
    ]
  }
}

6. 本章总结

6.1 核心知识点

┌─────────────────────────────────────────────────────────────────────┐
│                    GPU 监控与调试知识图谱                             │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  nvidia-smi                                                         │
│  ├── 基础查询: nvidia-smi, nvidia-smi -q                            │
│  ├── 分类查询: -d MEMORY/UTILIZATION/TEMPERATURE/POWER/ECC          │
│  ├── 格式化输出: --query-gpu, --format=csv                          │
│  ├── 实时监控: -l, dmon, pmon                                       │
│  └── 配置管理: -pm, -pl, -lgc, -mig                                 │
│                                                                     │
│  DCGM                                                               │
│  ├── 架构: nv-hostengine + libdcgm + dcgmi                         │
│  ├── 功能: GPU 分组、健康检查、诊断测试、策略管理                    │
│  ├── 指标: 150+ 种指标,覆盖性能、健康、配置                         │
│  └── 集成: dcgm-exporter → Prometheus → Grafana                     │
│                                                                     │
│  性能分析工具                                                        │
│  ├── Nsight Systems: 系统级分析 (CPU-GPU 交互)                      │
│  ├── Nsight Compute: Kernel 级分析 (Roofline)                       │
│  └── PyTorch Profiler: 深度学习框架级分析                           │
│                                                                     │
│  问题排查                                                           │
│  ├── 硬件问题: ECC 错误、温度、功耗、PCIe/NVLink                     │
│  ├── 驱动问题: 版本兼容、模块加载                                    │
│  ├── 性能问题: 利用率低、带宽瓶颈、Tensor Core 未使用               │
│  └── 容器问题: GPU 访问、设备挂载、K8s 调度                          │
│                                                                     │
│  生产监控                                                           │
│  ├── 指标采集: dcgm-exporter + Prometheus                           │
│  ├── 告警规则: 温度、显存、ECC、功耗                                 │
│  └── 可视化: Grafana Dashboard                                      │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

6.2 面试要点

  1. nvidia-smi 和 DCGM 的区别?

    • nvidia-smi: 交互式工具,适合简单查询和脚本
    • DCGM: 数据中心级别,支持 GPU 分组、健康检查、远程访问、更多指标
  2. 如何判断 GPU 是否正常工作?

    • 检查 ECC 错误(特别是 Double-Bit)
    • 检查温度是否正常
    • 检查功耗和时钟是否被限制
    • 运行 DCGM 诊断测试
  3. GPU 利用率低的可能原因?

    • CPU 瓶颈(数据加载跟不上)
    • I/O 瓶颈
    • 同步点太多
    • Batch size 太小
  4. 如何分析 CUDA kernel 性能?

    • 使用 Nsight Compute 进行 kernel 级分析
    • 关注 SM Throughput、Memory Throughput
    • 使用 Roofline 分析定位瓶颈
  5. 生产环境如何监控 GPU?

    • dcgm-exporter 采集指标
    • Prometheus 存储和告警
    • Grafana 可视化
    • 设置合理的告警阈值

6.3 下一章预告

下一章我们将进入 Kubernetes GPU 调度,深入探讨:

  • Device Plugin 机制
  • GPU 调度器实现
  • 拓扑感知调度
  • 弹性 GPU 调度

参考资料

  • nvidia-smi 官方文档
  • DCGM 官方文档
  • Nsight Systems 用户指南
  • Nsight Compute 用户指南
  • PyTorch Profiler
  • dcgm-exporter GitHub
Prev
GPU 共享与隔离