Prometheus与Grafana监控LLM:GPU利用率、SM活跃度与NVLink带宽的可视化大屏
大家好!今天我们来探讨如何使用Prometheus和Grafana监控大型语言模型(LLM)的GPU性能,特别是GPU利用率、SM(Streaming Multiprocessor)活跃度和NVLink带宽。通过搭建这样一个可视化大屏,我们可以更好地了解LLM训练和推理过程中的GPU瓶颈,从而优化模型和硬件配置。
1. 监控指标的重要性
在深入技术细节之前,我们先来了解一下这几个指标的重要性:
-
GPU利用率: 衡量GPU计算资源的整体使用情况。高利用率意味着GPU在充分工作,低利用率则可能表明存在瓶颈,例如数据加载缓慢、CPU瓶颈或代码效率低下。
-
SM活跃度: SM是GPU中执行实际计算的核心单元。SM活跃度反映了每个SM在给定时间内实际执行指令的比例。高SM活跃度意味着计算密集型任务在高效运行,而低SM活跃度可能表明存在线程束发散、内存访问瓶颈或指令依赖性等问题。
-
NVLink带宽: NVLink是NVIDIA GPU之间的高速互联技术。在多GPU训练或推理中,GPU之间需要频繁地交换数据。NVLink带宽直接影响数据传输速度,是多GPU性能的关键因素。
2. Prometheus监控数据的来源
Prometheus本身并不直接监控GPU指标。我们需要借助一些exporter来采集GPU数据,并将其转换为Prometheus可以理解的格式。常用的选择包括:
-
NVIDIA DCGM Exporter: NVIDIA Data Center GPU Manager (DCGM) 提供了丰富的GPU监控接口。
dcgm-exporter将这些接口暴露为Prometheus metrics,是监控GPU指标的首选方案。 -
NVIDIA SMI (System Management Interface):
nvidia-smi是一个命令行工具,可以查询GPU的各种信息。我们可以编写脚本定期运行nvidia-smi,并将输出转换为Prometheus metrics。这种方法比较灵活,但需要自己处理数据解析和格式转换。
我们推荐使用 dcgm-exporter,因为它提供了更全面的监控指标,并且易于集成到Prometheus生态系统中。
3. 安装和配置 NVIDIA DCGM Exporter
首先,确保你的系统上安装了NVIDIA驱动程序和DCGM。安装 dcgm-exporter 可以通过多种方式,例如使用Docker:
docker pull nvcr.io/nvidia/k8s/dcgm-exporter:3.1.7-3.1
docker run --rm --net=host --gpus all -v /var/run/dcgm:/var/run/dcgm nvcr.io/nvidia/k8s/dcgm-exporter:3.1.7-3.1
这个命令会拉取并运行 dcgm-exporter Docker镜像。 --net=host 允许exporter访问宿主机的网络, --gpus all 允许exporter访问所有的GPU, -v /var/run/dcgm:/var/run/dcgm 将宿主机的DCGM socket 挂载到容器中。
运行后,dcgm-exporter 默认会在端口 9400 上暴露 Prometheus metrics。你可以通过浏览器访问 http://localhost:9400/metrics 来查看这些metrics。
4. 配置 Prometheus 抓取 GPU Metrics
接下来,我们需要配置Prometheus来抓取 dcgm-exporter 暴露的metrics。修改Prometheus的配置文件 prometheus.yml,添加以下内容:
scrape_configs:
- job_name: 'gpu'
static_configs:
- targets: ['localhost:9400'] # 替换为你的 dcgm-exporter 地址
重启Prometheus服务,使配置生效。
5. 关键 Prometheus Metrics 和 PromQL 查询
现在,Prometheus应该能够抓取到GPU metrics了。以下是一些关键的metrics和PromQL查询,用于监控GPU利用率、SM活跃度和NVLink带宽:
-
GPU利用率:
- Metric:
DCGM_FI_DEV_GPU_UTIL - PromQL:
DCGM_FI_DEV_GPU_UTIL{gpu="0"}(替换 "0" 为你的GPU ID) - 含义:GPU 0 的利用率百分比。
- Metric:
-
SM活跃度:
- Metric:
DCGM_FI_PROF_SM_ACTIVE - PromQL:
DCGM_FI_PROF_SM_ACTIVE{gpu="0"}(替换 "0" 为你的GPU ID) - 含义:GPU 0 的 SM活跃度百分比。需要注意的是,启用 SM 活跃度指标需要开启 DCGM 的 profiling 功能。
- Metric:
-
NVLink带宽 (发送):
- Metric:
DCGM_FI_PROF_NVLINK_TX_BYTES - PromQL:
rate(DCGM_FI_PROF_NVLINK_TX_BYTES{gpu="0"}[5m]) * 8(替换 "0" 为你的GPU ID) - 含义:GPU 0 在过去 5 分钟内通过 NVLink 发送的平均带宽 (单位: bits/秒)。
rate()函数用于计算速率,* 8将字节转换为比特。
- Metric:
-
NVLink带宽 (接收):
- Metric:
DCGM_FI_PROF_NVLINK_RX_BYTES - PromQL:
rate(DCGM_FI_PROF_NVLINK_RX_BYTES{gpu="0"}[5m]) * 8(替换 "0" 为你的GPU ID) - 含义:GPU 0 在过去 5 分钟内通过 NVLink 接收的平均带宽 (单位: bits/秒)。
- Metric:
-
GPU Memory 使用量 (已使用):
- Metric:
DCGM_FI_DEV_MEM_USED - PromQL:
DCGM_FI_DEV_MEM_USED{gpu="0"}(替换 "0" 为你的GPU ID) - 含义:GPU 0 当前使用的显存大小 (单位: bytes)。
- Metric:
-
GPU Memory 总量:
- Metric:
DCGM_FI_DEV_MEM_TOTAL - PromQL:
DCGM_FI_DEV_MEM_TOTAL{gpu="0"}(替换 "0" 为你的GPU ID) - 含义:GPU 0 的总显存大小 (单位:bytes)。
- Metric:
6. Grafana 大屏设计
现在,我们可以使用Grafana来创建一个可视化大屏,展示这些GPU指标。
-
数据源配置: 在Grafana中添加Prometheus数据源,指向你的Prometheus服务器。
-
面板创建: 创建各种类型的面板来展示不同的指标。常用的面板类型包括:
- Graph: 用于展示时间序列数据,例如GPU利用率、SM活跃度和NVLink带宽的变化趋势。
- Gauge: 用于展示当前值,例如GPU温度、显存使用量。
- Stat: 用于展示统计数据,例如最大值、最小值、平均值。
-
面板配置: 在每个面板中,配置PromQL查询、数据格式、显示选项等。
以下是一些面板配置的示例:
-
GPU 利用率 (Graph):
- Title: GPU 0 Utilization
- Query:
DCGM_FI_DEV_GPU_UTIL{gpu="0"} - Y-axis Format: percent (0-100)
-
SM 活跃度 (Graph):
- Title: GPU 0 SM Activity
- Query:
DCGM_FI_PROF_SM_ACTIVE{gpu="0"} - Y-axis Format: percent (0-100)
-
NVLink 带宽 (发送, Graph):
- Title: GPU 0 NVLink TX Bandwidth
- Query:
rate(DCGM_FI_PROF_NVLINK_TX_BYTES{gpu="0"}[5m]) * 8 - Y-axis Format: bytes/s
- Unit: bits/s
-
GPU 内存使用量 (Gauge):
- Title: GPU 0 Memory Usage
- Query:
DCGM_FI_DEV_MEM_USED{gpu="0"} - Unit: bytes
- Thresholds: 80% (红色), 90% (黄色) (根据你的GPU内存大小调整阈值)
-
GPU 温度 (Gauge):
- Title: GPU 0 Temperature
- Query:
DCGM_FI_DEV_GPU_TEMP{gpu="0"} - Unit: °C
- Thresholds: 70°C (黄色), 80°C (红色) (根据你的GPU型号调整阈值)
-
多GPU监控: 如果你的系统有多个GPU,可以在每个面板中添加多个查询,分别监控每个GPU的指标。例如,要监控GPU 0 和 GPU 1 的利用率,可以使用以下查询:
DCGM_FI_DEV_GPU_UTIL{gpu="0"}DCGM_FI_DEV_GPU_UTIL{gpu="1"}
7. 优化建议
通过监控GPU指标,我们可以发现潜在的性能瓶颈,并采取相应的优化措施:
-
GPU利用率低:
- 数据加载瓶颈: 检查数据加载速度是否足够快。考虑使用更快的存储介质 (例如 SSD, NVMe),优化数据预处理流程,使用数据并行技术。
- CPU瓶颈: 检查CPU是否成为瓶颈。考虑使用更多的CPU核心,优化CPU代码。
- 代码效率低下: 检查GPU代码是否高效。考虑使用更优化的算法、减少内存访问、避免线程束发散。
-
SM活跃度低:
- 线程束发散: 线程束发散会导致部分线程空闲,降低SM活跃度。检查代码是否存在分支语句,尽量减少分支语句的使用,使用共享内存来减少全局内存访问。
- 内存访问瓶颈: 频繁的全局内存访问会降低SM活跃度。考虑使用共享内存来缓存数据,减少全局内存访问。
- 指令依赖性: 指令之间的依赖性会导致SM等待,降低SM活跃度。考虑使用指令级并行技术,减少指令之间的依赖性。
-
NVLink带宽瓶颈:
- 数据传输优化: 减少GPU之间的数据传输量。考虑使用模型并行技术,将模型分割到多个GPU上,减少数据交换。
- 数据压缩: 压缩数据可以减少传输量,提高NVLink带宽的利用率。
8. 代码示例:Python脚本生成Prometheus Metrics
虽然推荐使用 dcgm-exporter,但为了展示如何从 nvidia-smi 获取数据并转换为 Prometheus metrics,这里提供一个简单的 Python 脚本示例:
import subprocess
import time
import prometheus_client
from prometheus_client import Gauge
# 定义 Prometheus Metrics
gpu_utilization = Gauge('gpu_utilization', 'GPU Utilization Percentage', ['gpu_id'])
gpu_memory_used = Gauge('gpu_memory_used', 'GPU Memory Used (Bytes)', ['gpu_id'])
gpu_memory_total = Gauge('gpu_memory_total', 'GPU Memory Total (Bytes)', ['gpu_id'])
def get_gpu_metrics():
try:
# 执行 nvidia-smi 命令
command = "nvidia-smi --query-gpu=index,utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits"
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
output, error = process.communicate()
if error:
print(f"Error executing nvidia-smi: {error.decode()}")
return
lines = output.decode().strip().split('n')
for line in lines:
try:
gpu_id, utilization, memory_used, memory_total = line.split(',')
gpu_id = gpu_id.strip()
utilization = float(utilization.strip())
memory_used = int(memory_used.strip()) * 1024 * 1024 # Convert MB to Bytes
memory_total = int(memory_total.strip()) * 1024 * 1024 # Convert MB to Bytes
# 设置 Prometheus Metrics 的值
gpu_utilization.labels(gpu_id=gpu_id).set(utilization)
gpu_memory_used.labels(gpu_id=gpu_id).set(memory_used)
gpu_memory_total.labels(gpu_id=gpu_id).set(memory_total)
except ValueError as e:
print(f"Error parsing nvidia-smi output: {e}")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == '__main__':
# 启动 Prometheus HTTP 服务器
prometheus_client.start_http_server(8000)
print("Prometheus metrics server started on port 8000")
while True:
get_gpu_metrics()
time.sleep(5) # 每 5 秒更新一次 metrics
这个脚本会定期执行 nvidia-smi 命令,解析输出,并将GPU利用率和内存使用量转换为Prometheus metrics。你可以通过访问 http://localhost:8000/metrics 来查看这些metrics。
然后,你需要修改Prometheus的配置文件来抓取这些metrics:
scrape_configs:
- job_name: 'custom_gpu'
static_configs:
- targets: ['localhost:8000']
9. 表格:常用Prometheus Metrics和PromQL查询总结
| 指标名称 | Metric | PromQL 示例 | 描述 | 单位 |
|---|---|---|---|---|
| GPU 利用率 | DCGM_FI_DEV_GPU_UTIL |
DCGM_FI_DEV_GPU_UTIL{gpu="0"} |
GPU 的利用率百分比 | 百分比 |
| SM 活跃度 | DCGM_FI_PROF_SM_ACTIVE |
DCGM_FI_PROF_SM_ACTIVE{gpu="0"} |
SM 的活跃度百分比 | 百分比 |
| NVLink 带宽 (发送) | DCGM_FI_PROF_NVLINK_TX_BYTES |
rate(DCGM_FI_PROF_NVLINK_TX_BYTES{gpu="0"}[5m]) * 8 |
通过 NVLink 发送的平均带宽 | bits/秒 |
| NVLink 带宽 (接收) | DCGM_FI_PROF_NVLINK_RX_BYTES |
rate(DCGM_FI_PROF_NVLINK_RX_BYTES{gpu="0"}[5m]) * 8 |
通过 NVLink 接收的平均带宽 | bits/秒 |
| GPU 内存使用量 (已使用) | DCGM_FI_DEV_MEM_USED |
DCGM_FI_DEV_MEM_USED{gpu="0"} |
当前使用的显存大小 | bytes |
| GPU 内存总量 | DCGM_FI_DEV_MEM_TOTAL |
DCGM_FI_DEV_MEM_TOTAL{gpu="0"} |
总显存大小 | bytes |
| GPU 温度 | DCGM_FI_DEV_GPU_TEMP |
DCGM_FI_DEV_GPU_TEMP{gpu="0"} |
GPU 温度 | °C |
| PCIe 发送带宽 (bytes) | DCGM_FI_PROF_PCIE_TX_BYTES |
rate(DCGM_FI_PROF_PCIE_TX_BYTES{gpu="0"}[5m]) * 8 |
PCIe 发送带宽 | bits/秒 |
| PCIe 接收带宽 (bytes) | DCGM_FI_PROF_PCIE_RX_BYTES |
rate(DCGM_FI_PROF_PCIE_RX_BYTES{gpu="0"}[5m]) * 8 |
PCIe 接收带宽 | bits/秒 |
10. 持续优化和监控带来的益处
通过搭建Prometheus和Grafana监控LLM的GPU性能大屏,我们可以实时了解GPU的使用情况,及时发现潜在的性能瓶颈,并通过优化模型和硬件配置,提升LLM的训练和推理效率。
总结几句:
Prometheus和Grafana是强大的监控工具,结合DCGM Exporter可以有效监控LLM的GPU性能;通过监控GPU利用率、SM活跃度和NVLink带宽等关键指标,我们可以及时发现性能瓶颈并进行优化;持续的监控和优化可以提升LLM的训练和推理效率。