【JupyterLab集成】GPU性能监控可视化组件

文章目录


😊点此到文末惊喜↩︎


监控集成项目概述

方案调研

实现流程
  1. NV环境
    • 直接集成NVDashboard即可
  2. 昇腾集成方案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,实现一体化开发环境
    • 问题:依赖华为底层库开放的接口函数,获取的功能数据有限
  3. 昇腾集成方案2
    • 如果已经存在AIOP可观测平台,并且也是使用的npu-exporter方案
    • 可以确认网络架构方案,给容器开放网络服务,从而在容器内能够获取GPU指标数据

相关基础知识

NVDashboard
  1. 概述
    • 定义:NVDashboard 是一个开源软件包,用于在交互式Jupyter Lab环境中实时可视化 NVIDIA GPU 指标
    • 作用:通过可视化系统硬件指标,方便开发人员和用户验证AI任务对于GPU资源的利用情况
  2. 支持的核心指标
    • 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)效率显著提升
  3. 主要实现
    • 构建在基于 Python 的仪表板服务器上
    • 服务器支持 Bokeh 可视化库在实时中显示和更新图形
    • Jupyter Lab 扩展将这些仪表板作为可移动窗口嵌入到交互式环境中
  4. 架构设计
    • 整体架构:NVDashboard作为 GPU 资源监控工具,其核心架构遵循数据采集 - 处理 - 可视化 的三层逻辑
    • 具体设计:采用客户端 - 服务器(C/S)和嵌入式架构
      • 底层采集
        • 硬件接口调用:直接对接 NVIDIA 硬件接口,通过NVIDIA 的原生接口进行指标采集
        • 采集策略:可以设定采集周期和事件触发模式
      • 中层处理
        • 数据清洗与标准化:过滤无效数据、统一指标单位
        • 聚合与趋势分析:采用滑动窗口算法,基于历史数据和预测模型预测 GPU 负载趋势,提前预警资源瓶颈
        • 异常检测机制:内置多维度告警规则,
      • 顶层可视化
        • 交互界面嵌入:Jupyter Lab 扩展将这些仪表板作为可移动窗口嵌入到交互式环境中,以 Web 或桌面应用形式呈现可视化界面
        • 实时数据推送:基于 WebSocket 实现双向通信
        • 交互式图表渲染:采用 WebGL 加速的 Canvas 绘图,支持 100 + 数据点的流畅渲染
  5. 原理
    • 数据采集层
      • 数据采集:主要通过对接 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的模型资源监控插件
  1. 资源监测特性
    • 是一个基础特性,所以不区分训练或者推理场景
    • 也不区分使用Volcano调度器或者使用其他调度器场景。
  2. 图形化方式
    • Prometheus:
      • 需要在部署Prometheus后通过调用NPU Exporter相关接口,实现资源监测
      • 开源的完整监测解决方案,具有易管理、高效、可扩展、可视化等特点,搭配NPU Exporter组件使用,可实现对昇腾AI处理器利用率、温度、电压、内存,以及昇腾AI处理器在容器中的分配状况等信息的实时监测。
      • 支持对Atlas 推理系列产品的虚拟NPU(vNPU)的AI Core利用率、vNPU总内存和vNPU使用中内存进行监测。
    • Telegraf:
      • 则需要部署和运行Telegraf,实现资源监测。
      • Telegraf用于收集系统和服务的统计数据,具有内存占用小和支持其他服务的扩展等功能。
      • 搭配NPU Exporter组件使用,可以在环境上通过回显查看上报的昇腾AI处理器的相关信息。
  3. 资源检测
  4. 资源监控原理
    • NPU Exporter组件通过gRPC服务调用K8s中的标准化接口CRI,获取容器相关信息
    • 通过exec调用hccn_tool工具,获取芯片的网络信息
    • 通过dlopen/dlsym调用DCMI接口,获取芯片信息,并上报给Prometheus
  5. 底层接口库
  6. 获取npu的利用率
bash 复制代码
typedef struct aclrtUtilizationInfo {
    int32_t cubeUtilization;   // Cube利用率
    int32_t vectorUtilization; // Vector利用率
    int32_t aicpuUtilization;  // AI CPU利用率
    int32_t memoryUtilization; // Device内存利用率
    aclrtUtilizationExtendInfo *utilizationExtend; // 预留参数,当前设置为null
} aclrtUtilizationInfo;
  1. 代码(有一些接口函数名称不正确,需要确认依赖库的版本)
python 复制代码
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, 0
    
    print(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 None
    return 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 None
    return 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 None
    return 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, None
    
    ret = acl_lib.aclrtGetDeviceUsedMemSize(device_id, ctypes.byref(used_mem))
    if ret != 0:
        print(f"获取已使用内存失败,错误码: {ret}")
        return None, None
    
    return 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()

🚩点此跳转到首行↩︎

参考博客

  1. NV方案Jupyter 实验室中的 GPU 仪表板
  2. 昇腾社区GPU资源监控插件
  3. 待定引用
  4. 待定引用
  5. 待定引用
  6. 待定引用
  7. 待定引用
  8. 待定引用
相关推荐
丘山子4 分钟前
判断 Python 代码是否由 LLM 生成的几个小技巧
后端·python·面试
舒一笑4 分钟前
基础RAG实现,最佳入门选择(七)
人工智能
豌豆花下猫9 分钟前
Python 潮流周刊#107:无 GIL Python 被正式批准(摘要)
后端·python·ai
椒哥21 分钟前
爬虫框架playwright使用小技巧
后端·爬虫·python
boooo_hhh28 分钟前
第32周———Tensorflow|LSTM-火灾温度预测
人工智能·tensorflow·lstm
Takina~34 分钟前
python打卡day54
python·深度学习·机器学习
广州山泉婚姻35 分钟前
Python函数编写指南
人工智能·python·深度学习
张晓丽-1 小时前
ReAct
人工智能
非优秀程序员1 小时前
知识库切片模型架构设计:提升AI问答准确率的创新方法
人工智能
沛沛老爹1 小时前
NumPy玩转数据科学
人工智能·python·机器学习·numpy·数据科学·多维数组·python库