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

发布于:2025-06-24 ⋅ 阅读:(18) ⋅ 点赞:(0)


😊点此到文末惊喜↩︎


监控集成项目概述

方案调研

实现流程
  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. 资源检测
    • 安装NPU Exporter:https://www.hiascend.com/document/detail/zh/mindcluster/70rc1/clustersched/dlug/dlug_installation_018.html
      在这里插入图片描述
  4. 资源监控原理
    • NPU Exporter组件通过gRPC服务调用K8s中的标准化接口CRI,获取容器相关信息
    • 通过exec调用hccn_tool工具,获取芯片的网络信息
    • 通过dlopen/dlsym调用DCMI接口,获取芯片信息,并上报给Prometheus
      在这里插入图片描述
  5. 底层接口库
  6. 获取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, 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. 待定引用

网站公告

今日签到

点亮在社区的每一天
去签到