【JupyterLab集成】GPU性能监控可视化组件
文章目录
- 监控集成项目概述
- 方案调研
- 实现流程
- 相关基础知识
- NVDashboard
- 昇腾MindX DL的模型资源监控插件
- 参考博客
监控集成项目概述
方案调研
实现流程
- NV环境
- 直接集成NVDashboard即可
- 昇腾集成方案1(仿照NVDashboard)
- 原理
- 底层数据采集:AscendCL接口调用
- AscendCL作为昇腾平台的核心开发接口,提供设备管理、资源监控等API
- 已验证通过AscendCL获取CPU/GPU利用率(如acl.rt.get_device_utilization_rate),但其他指标(如内存占用、算子耗时)需进一步探索接口
- 数据中转:Prometheus集成
- 周期性调用AscendCL接口采集指标,通过自定义Exporter将数据推送至Prometheus
- 前端展示:JupyterLab嵌入式方案
- 在Prometheus暴露指标后,通过Grafana等工具生成监控面板。
- 使用jupyter_server_proxy将监控面板内嵌至JupyterLab,实现一体化开发环境
- 底层数据采集:AscendCL接口调用
- 问题:依赖华为底层库开放的接口函数,获取的功能数据有限
- 原理
- 昇腾集成方案2
- 如果已经存在AIOP可观测平台,并且也是使用的npu-exporter方案
- 可以确认网络架构方案,给容器开放网络服务,从而在容器内能够获取GPU指标数据
相关基础知识
NVDashboard
- 概述
- 定义:NVDashboard 是一个开源软件包,用于在交互式Jupyter Lab环境中
实时可视化 NVIDIA GPU 指标
- 作用:通过可视化系统硬件指标,方便开发人员和用户验证AI任务对于GPU资源的利用情况
- 定义:NVDashboard 是一个开源软件包,用于在交互式Jupyter Lab环境中
- 支持的核心指标
- GPU计算利用率
- 作用:指GPU流式多处理器(SMs)执行计算任务的活跃时间占比,反映GPU核心的利用效率
- 特点:
>90%
表示GPU利用效率较高,但是长时间可能造成过热降频。过低可能是任务分配不均、内存瓶颈等问题
- GPU内存消耗
- 作用:指GPU显存的实际使用量(单位:GB),包括模型参数、中间结果等数据存储需求
- 特点:高带宽可加速数据存取,但显存不足会导致数据溢出到系统内存,显著降低性能
- PCIe 吞吐量
- 作用:通过PCIe总线传输数据的速率(单位:GB/s),包括数据包头和有效负载
- 特点:多GPU共享PCIe总线时,带宽争用导致吞吐下降,所以适合单GPU或低并行任务(如推理),高并行任务需NVLink补充
- NVLink 吞吐量
- 作用:GPU间通过NVLink互连的数据传输速率(单位:GB/s),专为高速通信优化
- 特点:多GPU协作,在NVLink吞吐>200GB/s时,集体通信(如All-Reduce)效率显著提升
- GPU计算利用率
- 主要实现
- 构建在基于 Python 的仪表板服务器上
- 服务器支持 Bokeh 可视化库在实时中显示和更新图形
- Jupyter Lab 扩展将这些仪表板作为可移动窗口嵌入到交互式环境中
- 架构设计
- 整体架构:NVDashboard作为 GPU
资源监控工具
,其核心架构遵循数据采集 - 处理 - 可视化
的三层逻辑 - 具体设计:采用客户端 - 服务器(C/S)和嵌入式架构
- 底层
采集
- 硬件接口调用:直接对接 NVIDIA 硬件接口,通过NVIDIA 的原生接口进行指标采集
- 采集策略:可以设定采集周期和事件触发模式
- 中层
处理
:- 数据清洗与标准化:过滤无效数据、统一指标单位
- 聚合与趋势分析:采用滑动窗口算法,基于历史数据和预测模型预测 GPU 负载趋势,提前预警资源瓶颈
- 异常检测机制:内置多维度告警规则,
- 顶层
可视化
- 交互界面嵌入:Jupyter Lab 扩展将这些仪表板作为可移动窗口嵌入到交互式环境中,以 Web 或桌面应用形式呈现可视化界面
- 实时数据推送:基于 WebSocket 实现双向通信
- 交互式图表渲染:采用 WebGL 加速的 Canvas 绘图,支持 100 + 数据点的流畅渲染
- 底层
- 整体架构:NVDashboard作为 GPU
- 原理
- 数据采集层
- 数据采集:主要通过对接 NVIDIA Management Library(NVML)、NVIDIA System Management Interface(SMI)等原生接口,直接访问GPU底层状态(如温度、功耗、进程信息)
- 周期获取:轮询GPU指标(默认间隔约1秒),数据更新频率可配置至 50-100毫秒(v0.10版本)。
- 系统级监控:监控
整个机器的GPU资源
,不限于JupyterLab进程。
- 数据传输与处理
- Bokeh服务器架构:使用Bokeh库构建实时图表,通过ColumnDataSource动态更新数据源。
- WebSocket协议(v0.10+):取代REST API,实现低延迟数据流,减少连接开销。
- 异步数据处理:避免阻塞JupyterLab主线程,确保交互流畅性。
- 可视化层
- 动态仪表板:时间序列图表支持刷选(Brush)功能:用户可选取特定时间范围分析历史数据。
- 同步提示符(Sync Tooltips) :跨图表联动显示同一时间点的多指标数据。
- 数据采集层
昇腾MindX DL的模型资源监控插件
- 资源监测特性
- 是一个基础特性,所以不区分训练或者推理场景
- 也不区分使用Volcano调度器或者使用其他调度器场景。
- 图形化方式
- Prometheus:
- 需要在部署Prometheus后通过调用NPU Exporter相关接口,实现资源监测
- 开源的完整监测解决方案,具有易管理、高效、可扩展、可视化等特点,搭配NPU Exporter组件使用,可实现对昇腾AI处理器利用率、温度、电压、内存,以及昇腾AI处理器在容器中的分配状况等信息的实时监测。
- 支持对Atlas 推理系列产品的虚拟NPU(vNPU)的AI Core利用率、vNPU总内存和vNPU使用中内存进行监测。
- Telegraf:
- 则需要部署和运行Telegraf,实现资源监测。
- Telegraf用于收集系统和服务的统计数据,具有内存占用小和支持其他服务的扩展等功能。
- 搭配NPU Exporter组件使用,可以在环境上通过回显查看上报的昇腾AI处理器的相关信息。
- Prometheus:
- 资源检测
- 安装NPU Exporter:https://www.hiascend.com/document/detail/zh/mindcluster/70rc1/clustersched/dlug/dlug_installation_018.html
- 安装NPU Exporter:https://www.hiascend.com/document/detail/zh/mindcluster/70rc1/clustersched/dlug/dlug_installation_018.html
- 资源监控原理
- NPU Exporter组件通过gRPC服务调用K8s中的标准化接口CRI,获取容器相关信息
- 通过exec调用hccn_tool工具,获取芯片的网络信息
- 通过dlopen/dlsym调用DCMI接口,获取芯片信息,并上报给Prometheus
- 底层接口库
- 华为底层库文档链接
- 华为底层库文档链接
- 获取npu的利用率
typedef struct aclrtUtilizationInfo {int32_t cubeUtilization; // Cube利用率int32_t vectorUtilization; // Vector利用率int32_t aicpuUtilization; // AI CPU利用率int32_t memoryUtilization; // Device内存利用率aclrtUtilizationExtendInfo *utilizationExtend; // 预留参数,当前设置为null
} aclrtUtilizationInfo;
8. 代码(有一些接口函数名称不正确,需要确认依赖库的版本)
import ctypes# 加载 AscendCL 动态库
acl_lib = ctypes.CDLL("libascendcl.so")# 初始化 AscendCL
def init_acl():# 初始化ret = acl_lib.aclInit(None)if ret != 0:print(f"初始化失败,错误码: {ret}")return False, 0# 获取设备数量device_count = ctypes.c_uint32(0)ret = acl_lib.aclrtGetDeviceCount(ctypes.byref(device_count))if ret != 0 or device_count.value == 0:print(f"获取设备数量失败,错误码: {ret}")return False, 0print(f"发现 {device_count.value} 个昇腾设备")return True, device_count.value# 获取设备温度
def get_device_temperature(device_id):temperature = ctypes.c_uint32(0)ret = acl_lib.aclrtGetTemperature(device_id, 0, ctypes.byref(temperature))if ret != 0:print(f"获取温度失败,错误码: {ret}")return Nonereturn temperature.value# 获取功耗信息
def get_device_power(device_id):power = ctypes.c_uint32(0)ret = acl_lib.aclrtGetChipPower(device_id, ctypes.byref(power))if ret != 0:print(f"获取功耗失败,错误码: {ret}")return Nonereturn power.value / 1000 # 转换为瓦# 获取 AI Core 利用率
def get_ai_core_utilization(device_id):class AclrtRuningParam(ctypes.Structure):_fields_ = [("aiCoreFrequence", ctypes.c_uint32),("aiCoreUtilization", ctypes.c_uint32),("cpuFrequence", ctypes.c_uint32),("ddrBandwidth", ctypes.c_uint64),("npuCacheHitRate", ctypes.c_uint32),("memoryUsage", ctypes.c_uint32),]param = AclrtRuningParam()ret = acl_lib.aclrtGetRuningParam(device_id, ctypes.byref(param))if ret != 0:print(f"获取运行参数失败,错误码: {ret}")return Nonereturn param.aiCoreUtilization# 获取内存使用情况
def get_memory_usage(device_id):total_mem = ctypes.c_uint64(0)used_mem = ctypes.c_uint64(0)ret = acl_lib.aclrtGetDeviceTotalMemSize(device_id, ctypes.byref(total_mem))if ret != 0:print(f"获取总内存失败,错误码: {ret}")return None, Noneret = acl_lib.aclrtGetDeviceUsedMemSize(device_id, ctypes.byref(used_mem))if ret != 0:print(f"获取已使用内存失败,错误码: {ret}")return None, Nonereturn used_mem.value / (1024**3), total_mem.value / (1024**3) # 转换为 GB# 主函数
def main():# 初始化success, device_count = init_acl()if not success:return# 遍历所有设备并获取指标for i in range(device_count):print(f"\n设备 {i} 信息:")# 获取各项指标temp = get_device_temperature(i)power = get_device_power(i)util = get_ai_core_utilization(i)used_mem, total_mem = get_memory_usage(i)# 打印指标if temp is not None:print(f"温度: {temp} °C")if power is not None:print(f"功耗: {power:.2f} W")if util is not None:print(f"AI Core 利用率: {util} %")if used_mem is not None and total_mem is not None:print(f"内存使用: {used_mem:.2f} GB / {total_mem:.2f} GB")# 释放资源acl_lib.aclFinalize()if __name__ == "__main__":main()
参考博客
- NV方案Jupyter 实验室中的 GPU 仪表板
- 昇腾社区GPU资源监控插件
- 待定引用
- 待定引用
- 待定引用
- 待定引用
- 待定引用
- 待定引用