【NPU】Ascend Docker Runtime v26.0.1 之三 runtime/dcmi/ — 超深度逐行分析

runtime/dcmi/ --- 超深度逐行分析

三个文件:dcmi.go (360行) + dcmi_api.go (101行) + dcManager.go (294行) = 755行

核心职责:NPU设备管理接口封装,通过CGO调用libdcmi.so


一、模块定位

1.1 业务职责

runtime/dcmi/ 是设备管理抽象层,负责:

  1. 驱动版本自适应 --- 自动检测V1/V2驱动,选择匹配的Worker
  2. 设备查询 --- 获取卡列表、设备列表、芯片信息、产品类型
  3. 虚拟设备管理 --- 创建/销毁vNPU(虚拟NPU切分)
  4. 物理ID↔逻辑ID转换 --- 将用户指定的物理设备ID转换为驱动内部逻辑ID
  5. CGO桥接 --- 封装所有对libdcmi.so的C语言调用

1.2 在系统中的位置

#mermaid-svg-MA5V9njIHI1zHJ0f{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MA5V9njIHI1zHJ0f .error-icon{fill:#552222;}#mermaid-svg-MA5V9njIHI1zHJ0f .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MA5V9njIHI1zHJ0f .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MA5V9njIHI1zHJ0f .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MA5V9njIHI1zHJ0f .marker.cross{stroke:#333333;}#mermaid-svg-MA5V9njIHI1zHJ0f svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MA5V9njIHI1zHJ0f p{margin:0;}#mermaid-svg-MA5V9njIHI1zHJ0f .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f .cluster-label text{fill:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f .cluster-label span{color:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f .cluster-label span p{background-color:transparent;}#mermaid-svg-MA5V9njIHI1zHJ0f .label text,#mermaid-svg-MA5V9njIHI1zHJ0f span{fill:#333;color:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f .node rect,#mermaid-svg-MA5V9njIHI1zHJ0f .node circle,#mermaid-svg-MA5V9njIHI1zHJ0f .node ellipse,#mermaid-svg-MA5V9njIHI1zHJ0f .node polygon,#mermaid-svg-MA5V9njIHI1zHJ0f .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MA5V9njIHI1zHJ0f .rough-node .label text,#mermaid-svg-MA5V9njIHI1zHJ0f .node .label text,#mermaid-svg-MA5V9njIHI1zHJ0f .image-shape .label,#mermaid-svg-MA5V9njIHI1zHJ0f .icon-shape .label{text-anchor:middle;}#mermaid-svg-MA5V9njIHI1zHJ0f .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MA5V9njIHI1zHJ0f .rough-node .label,#mermaid-svg-MA5V9njIHI1zHJ0f .node .label,#mermaid-svg-MA5V9njIHI1zHJ0f .image-shape .label,#mermaid-svg-MA5V9njIHI1zHJ0f .icon-shape .label{text-align:center;}#mermaid-svg-MA5V9njIHI1zHJ0f .node.clickable{cursor:pointer;}#mermaid-svg-MA5V9njIHI1zHJ0f .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MA5V9njIHI1zHJ0f .arrowheadPath{fill:#333333;}#mermaid-svg-MA5V9njIHI1zHJ0f .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MA5V9njIHI1zHJ0f .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MA5V9njIHI1zHJ0f .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MA5V9njIHI1zHJ0f .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MA5V9njIHI1zHJ0f .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MA5V9njIHI1zHJ0f .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MA5V9njIHI1zHJ0f .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MA5V9njIHI1zHJ0f .cluster text{fill:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f .cluster span{color:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MA5V9njIHI1zHJ0f .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MA5V9njIHI1zHJ0f rect.text{fill:none;stroke-width:0;}#mermaid-svg-MA5V9njIHI1zHJ0f .icon-shape,#mermaid-svg-MA5V9njIHI1zHJ0f .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MA5V9njIHI1zHJ0f .icon-shape p,#mermaid-svg-MA5V9njIHI1zHJ0f .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MA5V9njIHI1zHJ0f .icon-shape .label rect,#mermaid-svg-MA5V9njIHI1zHJ0f .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MA5V9njIHI1zHJ0f .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MA5V9njIHI1zHJ0f .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MA5V9njIHI1zHJ0f :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 外部
dcmi模块
调用方
GetMatchingNpuWorker
CreateVDevice
GetChipName/GetProductType
CGO C.DcmiXXX
runtime/process/process.go
dcmi_api.go

顶层API

CreateVDevice
dcmi.go

Worker接口+V1/V2实现

设备查询/虚拟设备
dcManager.go

CGO封装

直接调用libdcmi.so
libdcmi.so

NPU驱动C库
NPU硬件


二、dcmi_api.go 逐行解析(101行)

2.1 数据结构

go 复制代码
type VDeviceInfo struct {
    CardID    int32
    DeviceID  int32
    VdeviceID int32
}
字段 含义 示例
CardID NPU卡ID(物理插槽) 0
DeviceID 卡内设备ID 1
VdeviceID 虚拟设备ID(切分后生成) 42

#mermaid-svg-Cxk2dFq8FtryuRbp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Cxk2dFq8FtryuRbp .error-icon{fill:#552222;}#mermaid-svg-Cxk2dFq8FtryuRbp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Cxk2dFq8FtryuRbp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Cxk2dFq8FtryuRbp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Cxk2dFq8FtryuRbp .marker.cross{stroke:#333333;}#mermaid-svg-Cxk2dFq8FtryuRbp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Cxk2dFq8FtryuRbp p{margin:0;}#mermaid-svg-Cxk2dFq8FtryuRbp g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-Cxk2dFq8FtryuRbp g.classGroup text .title{font-weight:bolder;}#mermaid-svg-Cxk2dFq8FtryuRbp .cluster-label text{fill:#333;}#mermaid-svg-Cxk2dFq8FtryuRbp .cluster-label span{color:#333;}#mermaid-svg-Cxk2dFq8FtryuRbp .cluster-label span p{background-color:transparent;}#mermaid-svg-Cxk2dFq8FtryuRbp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Cxk2dFq8FtryuRbp .cluster text{fill:#333;}#mermaid-svg-Cxk2dFq8FtryuRbp .cluster span{color:#333;}#mermaid-svg-Cxk2dFq8FtryuRbp .nodeLabel,#mermaid-svg-Cxk2dFq8FtryuRbp .edgeLabel{color:#131300;}#mermaid-svg-Cxk2dFq8FtryuRbp .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-Cxk2dFq8FtryuRbp .label text{fill:#131300;}#mermaid-svg-Cxk2dFq8FtryuRbp .labelBkg{background:#ECECFF;}#mermaid-svg-Cxk2dFq8FtryuRbp .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-Cxk2dFq8FtryuRbp .classTitle{font-weight:bolder;}#mermaid-svg-Cxk2dFq8FtryuRbp .node rect,#mermaid-svg-Cxk2dFq8FtryuRbp .node circle,#mermaid-svg-Cxk2dFq8FtryuRbp .node ellipse,#mermaid-svg-Cxk2dFq8FtryuRbp .node polygon,#mermaid-svg-Cxk2dFq8FtryuRbp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Cxk2dFq8FtryuRbp .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp g.clickable{cursor:pointer;}#mermaid-svg-Cxk2dFq8FtryuRbp g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-Cxk2dFq8FtryuRbp g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-Cxk2dFq8FtryuRbp .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-Cxk2dFq8FtryuRbp .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-Cxk2dFq8FtryuRbp .dashed-line{stroke-dasharray:3;}#mermaid-svg-Cxk2dFq8FtryuRbp .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-Cxk2dFq8FtryuRbp #compositionStart,#mermaid-svg-Cxk2dFq8FtryuRbp .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #compositionEnd,#mermaid-svg-Cxk2dFq8FtryuRbp .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #dependencyStart,#mermaid-svg-Cxk2dFq8FtryuRbp .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #dependencyStart,#mermaid-svg-Cxk2dFq8FtryuRbp .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #extensionStart,#mermaid-svg-Cxk2dFq8FtryuRbp .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #extensionEnd,#mermaid-svg-Cxk2dFq8FtryuRbp .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #aggregationStart,#mermaid-svg-Cxk2dFq8FtryuRbp .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #aggregationEnd,#mermaid-svg-Cxk2dFq8FtryuRbp .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #lollipopStart,#mermaid-svg-Cxk2dFq8FtryuRbp .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp #lollipopEnd,#mermaid-svg-Cxk2dFq8FtryuRbp .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Cxk2dFq8FtryuRbp .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-Cxk2dFq8FtryuRbp .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Cxk2dFq8FtryuRbp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Cxk2dFq8FtryuRbp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Cxk2dFq8FtryuRbp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} VDeviceInfo
+int32 CardID
+int32 DeviceID
+int32 VdeviceID
<<interface>>
WorkerInterface
+Initialize() : error
+ShutDown()
+CreateVDevice(uniqueID, coreNum)(VDeviceInfo, error)
+DestroyVDevice(uniqueID, vDevID) : error
+GetProductType()(string, error)
+GetChipName()(string, error)

2.2 WorkerInterface 接口

go 复制代码
type WorkerInterface interface {
    Initialize() error
    ShutDown()
    CreateVDevice(uniqueID int32, coreNum string) (VDeviceInfo, error)
    DestroyVDevice(uniqueID int32, vDevID int32) error
    GetProductType() (string, error)
    GetChipName() (string, error)
}

6个方法的职责

方法 输入 输出 用途
Initialize error 初始化dcmi库连接
ShutDown 关闭dcmi库连接
CreateVDevice uniqueID(物理设备ID), coreNum(切分模板) VDeviceInfo, error 创建虚拟NPU
DestroyVDevice uniqueID, vDevID(虚拟设备ID) error 销毁虚拟NPU
GetProductType string, error 获取产品型号
GetChipName string, error 获取芯片名称

设计意图:策略模式接口,V1和V2驱动各自实现此接口,调用方无需关心驱动版本。

2.3 CreateVDevice 顶层API

go 复制代码
func CreateVDevice(w WorkerInterface, spec *specs.Spec, devices []int) (VDeviceInfo, error) {
    invalidVDevice := VDeviceInfo{CardID: -1, DeviceID: -1, VdeviceID: -1}
    if spec == nil {
        return invalidVDevice, fmt.Errorf("spec is nil")
    }
    splitDevice, err := extractVpuParam(spec)
    if err != nil {
        return invalidVDevice, err
    }
    if splitDevice == "" {
        return invalidVDevice, nil
    }
    if len(devices) != 1 || devices[0] < 0 || devices[0] >= hiAIMaxCardNum*hiAIMaxDeviceNum {
        hwlog.RunLog.Errorf("invalid devices: %v", devices)
        return invalidVDevice, fmt.Errorf("invalid devices: %v", devices)
    }

    if err := w.Initialize(); err != nil {
        return invalidVDevice, fmt.Errorf("cannot init dcmi : %v", err)
    }
    defer w.ShutDown()

    vDeviceInfo, err := w.CreateVDevice(int32(devices[0]), splitDevice)
    if err != nil || vDeviceInfo.VdeviceID < 0 {
        hwlog.RunLog.Errorf("cannot create vd or vdevice is wrong: %v %v", vDeviceInfo.VdeviceID, err)
        return invalidVDevice, err
    }
    return vDeviceInfo, nil
}

逐行解析

  1. 定义无效返回值 invalidVDevice(所有ID为-1)
  2. nil检查保护
  3. extractVpuParam --- 从OCI Spec环境变量中提取vNPU切分模板
  4. 如果splitDevice为空 → 不是虚拟模式,返回无效值但无错误
  5. 设备数校验 :vNPU切分只允许1个物理设备(len(devices) != 1),且ID在有效范围内
  6. 初始化Worker → 创建虚拟设备 → defer关闭
  7. 如果创建失败或VdeviceID<0 → 返回错误

设计意图:此函数是对Worker.CreateVDevice的包装,增加了Spec解析和参数校验。

2.4 extractVpuParam --- vNPU切分模板解析

go 复制代码
func extractVpuParam(spec *specs.Spec) (string, error) {
    allowSplit := map[string]string{
        "vir01": "vir01", "vir02": "vir02", "vir04": "vir04", "vir08": "vir08", "vir16": "vir16",
        "vir02_1c": "vir02_1c", "vir03_1c_8g": "vir03_1c_8g", "vir04_3c": "vir04_3c",
        "vir04_4c_dvpp": "vir04_4c_dvpp", "vir04_3c_ndvpp": "vir04_3c_ndvpp",
        "vir05_1c_8g": "vir05_1c_8g", "vir05_1c_16g": "vir05_1c_16g",
        "vir06_1c_16g": "vir06_1c_16g", "vir10_3c_16g": "vir10_3c_16g",
        "vir10_3c_16g_nm": "vir10_3c_16g_nm", "vir10_3c_32g": "vir10_3c_32g",
        "vir10_4c_16g_m": "vir10_4c_16g_m", "vir12_3c_32g": "vir12_3c_32g",
    }

    for _, line := range spec.Process.Env {
        words := strings.Split(line, "=")
        const LENGTH int = 2
        if len(words) != LENGTH {
            continue
        }
        if strings.TrimSpace(words[0]) == api.AscendVnpuSpescEnv {
            if split, ok := allowSplit[words[1]]; ok && split != "" {
                return split, nil
            }
            return "", fmt.Errorf("cannot parse param : %v", words[1])
        }
    }
    return "", nil
}

vNPU切分模板说明

模板名 含义
vir01 1/16切分(最小)
vir02 1/8切分
vir04 1/4切分
vir08 1/2切分
vir16 不切分(全卡)
vir02_1c 1/8切分+1核
vir04_3c 1/4切分+3核
vir04_4c_dvpp 1/4切分+4核+DVPP
vir04_3c_ndvpp 1/4切分+3核+无DVPP
vir05_1c_8g 1/3.2切分+1核+8GB
vir10_3c_16g 1/1.6切分+3核+16GB
vir10_4c_16g_m 1/1.6切分+4核+16GB+内存增强
vir12_3c_32g 1/1.3切分+3核+32GB

逐行解析

  1. 定义允许的切分模板白名单(map)
  2. 遍历容器环境变量
  3. 找到 ASCEND_VNPU_SPECS 环境变量
  4. 如果值在白名单中 → 返回切分模板
  5. 如果值不在白名单 → 返回错误(防止非法切分参数)
  6. 如果环境变量不存在 → 返回空字符串(非虚拟模式)

设计意图:严格的白名单校验,防止用户传入非法切分参数导致驱动异常。


三、dcmi.go 逐行解析(360行)

3.1 常量定义

go 复制代码
const (
    retError           = -1
    hiAIMaxCardNum     = 64           // 最大卡数
    hiAIMaxCardID      = math.MaxInt32 // 卡ID上限
    hiAIMaxDeviceID    = math.MaxInt32 // 设备ID上限
    hiAIMaxDeviceNum   = 4             // 每卡最大设备数
    maxChipNameLen     = 32            // 芯片名最大长度
    productTypeLen     = 64            // 产品类型最大长度
    notSupportCode     = -8255         // "不支持"错误码
    coreNumLen         = 32            // 切分模板名最大长度
    vfgID              = 4294967295    // 虚拟组ID默认值(0xFFFFFFFF)
    notSupportString   = "[not support]"
)
常量 用途
hiAIMaxCardNum 64 系统最多支持64张NPU卡
hiAIMaxDeviceNum 4 每张卡最多4个芯片
maxChipNameLen 32 C结构体中芯片名字段长度
vfgID 0xFFFFFFFF 虚拟功能组ID,默认自动分配
notSupportCode -8255 DCMI库返回的"不支持"错误码

3.2 managerList --- Worker注册表

go 复制代码
var managerList = []WorkerInterface{
    &NpuV1Worker{DcMgr: &DcV1Manager{}},
    &NpuV2Worker{DcMgr: &DcV2Manager{}},
}

设计意图 :全局Worker列表,V1在前V2在后。GetMatchingNpuWorker 按顺序尝试初始化,第一个成功的即为匹配的驱动版本。

3.3 ChipInfo 结构体

go 复制代码
type ChipInfo struct {
    Type    string `json:"chip_type"`
    Name    string `json:"chip_name"`
    Version string `json:"chip_version"`
}
  • 从C结构体 DcmiChipInfo 转换而来
  • Name 用于判断芯片类型(如"Ascend910A"→Ascend910)

3.4 驱动接口定义

go 复制代码
type DcDriverV1Interface interface {
    DcInitialize() error
    DcShutDown()
    DcGetCardList() (int32, []int32, error)
    DcGetDeviceNumInCard(cardID int32) (int32, error)
    DcGetDeviceLogicID(cardID, deviceID int32) (int32, error)
    DcGetProductType(cardID, deviceID int32) (string, error)
    DcCreateVDevice(cardID, deviceID int32, coreNum string) (int32, error)
    DcDestroyVDevice(cardID, deviceID int32, vDevID int32) error
    DcGetChipInfo(cardID, deviceID int32) (*ChipInfo, error)
    DcGetDeviceLogicidFromPhyid(phyID int32) (int32, error)
}

type DcDriverV2Interface interface {
    DcInitialize() error
    DcShutDown()
    DcCreateVDevice(deviceID int32, coreNum string) (int32, error)
    DcDestroyVDevice(deviceID int32, vDevID int32) error
    DcGetChipInfo(deviceID int32) (*ChipInfo, error)
    DcGetDeviceList() (int32, []int32, error)
}

V1 vs V2 接口差异

差异点 V1 V2
设备寻址 cardID + deviceID 二级寻址 deviceID 一级寻址
卡列表 DcGetCardList → 每卡DcGetDeviceNumInCard DcGetDeviceList 直接获取所有设备
产品类型 支持 DcGetProductType 不支持(返回"not support")
物理ID转换 DcGetDeviceLogicidFromPhyid 不需要(直接用deviceID)
虚拟设备 支持 不支持(返回错误)

3.5 GetMatchingNpuWorker --- 工厂函数

go 复制代码
func GetMatchingNpuWorker() (WorkerInterface, error) {
    for _, manager := range managerList {
        err := manager.Initialize()
        if err == nil {
            manager.ShutDown()
            hwlog.RunLog.Infof("worker type: %T", manager)
            return manager, nil
        }
    }
    return nil, fmt.Errorf("failed to find a valid manager")
}

逐行解析

  1. 遍历managerList:先尝试V1,再尝试V2
  2. 调用 Initialize() 尝试初始化dcmi库
  3. 如果成功 → 立即 ShutDown()(因为只是探测,实际使用时会重新初始化)
  4. 返回匹配的Worker
  5. 如果都失败 → 返回错误

设计意图 :V1调用 DcmiInit(),V2调用 DcmiV2Init()。在新版硬件上调用V1初始化会失败,反之亦然。利用这个特性来自动检测驱动版本。
#mermaid-svg-VYcE0T9MJNGyD0Jd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VYcE0T9MJNGyD0Jd .error-icon{fill:#552222;}#mermaid-svg-VYcE0T9MJNGyD0Jd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VYcE0T9MJNGyD0Jd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .marker.cross{stroke:#333333;}#mermaid-svg-VYcE0T9MJNGyD0Jd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VYcE0T9MJNGyD0Jd p{margin:0;}#mermaid-svg-VYcE0T9MJNGyD0Jd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .cluster-label text{fill:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .cluster-label span{color:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .cluster-label span p{background-color:transparent;}#mermaid-svg-VYcE0T9MJNGyD0Jd .label text,#mermaid-svg-VYcE0T9MJNGyD0Jd span{fill:#333;color:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .node rect,#mermaid-svg-VYcE0T9MJNGyD0Jd .node circle,#mermaid-svg-VYcE0T9MJNGyD0Jd .node ellipse,#mermaid-svg-VYcE0T9MJNGyD0Jd .node polygon,#mermaid-svg-VYcE0T9MJNGyD0Jd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .rough-node .label text,#mermaid-svg-VYcE0T9MJNGyD0Jd .node .label text,#mermaid-svg-VYcE0T9MJNGyD0Jd .image-shape .label,#mermaid-svg-VYcE0T9MJNGyD0Jd .icon-shape .label{text-anchor:middle;}#mermaid-svg-VYcE0T9MJNGyD0Jd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .rough-node .label,#mermaid-svg-VYcE0T9MJNGyD0Jd .node .label,#mermaid-svg-VYcE0T9MJNGyD0Jd .image-shape .label,#mermaid-svg-VYcE0T9MJNGyD0Jd .icon-shape .label{text-align:center;}#mermaid-svg-VYcE0T9MJNGyD0Jd .node.clickable{cursor:pointer;}#mermaid-svg-VYcE0T9MJNGyD0Jd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .arrowheadPath{fill:#333333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VYcE0T9MJNGyD0Jd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VYcE0T9MJNGyD0Jd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VYcE0T9MJNGyD0Jd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VYcE0T9MJNGyD0Jd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .cluster text{fill:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd .cluster span{color:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VYcE0T9MJNGyD0Jd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VYcE0T9MJNGyD0Jd rect.text{fill:none;stroke-width:0;}#mermaid-svg-VYcE0T9MJNGyD0Jd .icon-shape,#mermaid-svg-VYcE0T9MJNGyD0Jd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VYcE0T9MJNGyD0Jd .icon-shape p,#mermaid-svg-VYcE0T9MJNGyD0Jd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VYcE0T9MJNGyD0Jd .icon-shape .label rect,#mermaid-svg-VYcE0T9MJNGyD0Jd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VYcE0T9MJNGyD0Jd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VYcE0T9MJNGyD0Jd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VYcE0T9MJNGyD0Jd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是



GetMatchingNpuWorker
尝试NpuV1Worker.Initialize
DcmiInit成功?
ShutDown

关闭探测连接
返回NpuV1Worker
尝试NpuV2Worker.Initialize
DcmiV2Init成功?
ShutDown
返回NpuV2Worker
返回错误

failed to find valid manager

3.6 NpuV1Worker.FindDevice --- 物理ID到卡/设备映射

go 复制代码
func (w *NpuV1Worker) FindDevice(visibleDevice int32) (int32, int32, error) {
    targetLogicID, err := w.DcMgr.DcGetDeviceLogicidFromPhyid(visibleDevice)
    if err != nil {
        return 0, 0, fmt.Errorf("cannot convert phy id to logic id, err: %v", err)
    }
    _, cardList, err := w.DcMgr.DcGetCardList()
    if err != nil {
        return 0, 0, fmt.Errorf("get card list err : %v", err)
    }
    targetDeviceID, targetCardID := int32(math.MaxInt32), int32(math.MaxInt32)
    for _, cardID := range cardList {
        deviceCount, err := w.DcMgr.DcGetDeviceNumInCard(cardID)
        if err != nil {
            return 0, 0, fmt.Errorf("cannot get device num in card : %v", err)
        }
        for deviceID := int32(0); deviceID < deviceCount; deviceID++ {
            logicID, err := w.DcMgr.DcGetDeviceLogicID(cardID, deviceID)
            if err != nil {
                return 0, 0, fmt.Errorf("cannot get logic id : %v", err)
            }
            if logicID == targetLogicID {
                targetCardID, targetDeviceID = cardID, deviceID
            }
        }
    }
    return targetDeviceID, targetCardID, nil
}

逐行解析

  1. 将物理ID(用户指定的visibleDevice)转换为逻辑ID
  2. 获取所有卡的列表
  3. 双层遍历:遍历每张卡,遍历卡内每个设备
  4. 对每个设备获取其逻辑ID
  5. 如果逻辑ID匹配目标 → 记录cardID和deviceID
  6. 返回找到的deviceID和cardID

设计意图 :V1驱动使用"物理ID"作为用户接口(如ASCEND_VISIBLE_DEVICES=0),但内部操作需要cardID+deviceID二维坐标。此函数完成这个映射。
#mermaid-svg-OFtCmAwrmgWmqUML{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OFtCmAwrmgWmqUML .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OFtCmAwrmgWmqUML .error-icon{fill:#552222;}#mermaid-svg-OFtCmAwrmgWmqUML .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OFtCmAwrmgWmqUML .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OFtCmAwrmgWmqUML .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OFtCmAwrmgWmqUML .marker.cross{stroke:#333333;}#mermaid-svg-OFtCmAwrmgWmqUML svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OFtCmAwrmgWmqUML p{margin:0;}#mermaid-svg-OFtCmAwrmgWmqUML .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OFtCmAwrmgWmqUML .cluster-label text{fill:#333;}#mermaid-svg-OFtCmAwrmgWmqUML .cluster-label span{color:#333;}#mermaid-svg-OFtCmAwrmgWmqUML .cluster-label span p{background-color:transparent;}#mermaid-svg-OFtCmAwrmgWmqUML .label text,#mermaid-svg-OFtCmAwrmgWmqUML span{fill:#333;color:#333;}#mermaid-svg-OFtCmAwrmgWmqUML .node rect,#mermaid-svg-OFtCmAwrmgWmqUML .node circle,#mermaid-svg-OFtCmAwrmgWmqUML .node ellipse,#mermaid-svg-OFtCmAwrmgWmqUML .node polygon,#mermaid-svg-OFtCmAwrmgWmqUML .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OFtCmAwrmgWmqUML .rough-node .label text,#mermaid-svg-OFtCmAwrmgWmqUML .node .label text,#mermaid-svg-OFtCmAwrmgWmqUML .image-shape .label,#mermaid-svg-OFtCmAwrmgWmqUML .icon-shape .label{text-anchor:middle;}#mermaid-svg-OFtCmAwrmgWmqUML .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OFtCmAwrmgWmqUML .rough-node .label,#mermaid-svg-OFtCmAwrmgWmqUML .node .label,#mermaid-svg-OFtCmAwrmgWmqUML .image-shape .label,#mermaid-svg-OFtCmAwrmgWmqUML .icon-shape .label{text-align:center;}#mermaid-svg-OFtCmAwrmgWmqUML .node.clickable{cursor:pointer;}#mermaid-svg-OFtCmAwrmgWmqUML .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OFtCmAwrmgWmqUML .arrowheadPath{fill:#333333;}#mermaid-svg-OFtCmAwrmgWmqUML .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OFtCmAwrmgWmqUML .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OFtCmAwrmgWmqUML .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OFtCmAwrmgWmqUML .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OFtCmAwrmgWmqUML .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OFtCmAwrmgWmqUML .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OFtCmAwrmgWmqUML .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OFtCmAwrmgWmqUML .cluster text{fill:#333;}#mermaid-svg-OFtCmAwrmgWmqUML .cluster span{color:#333;}#mermaid-svg-OFtCmAwrmgWmqUML div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OFtCmAwrmgWmqUML .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OFtCmAwrmgWmqUML rect.text{fill:none;stroke-width:0;}#mermaid-svg-OFtCmAwrmgWmqUML .icon-shape,#mermaid-svg-OFtCmAwrmgWmqUML .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OFtCmAwrmgWmqUML .icon-shape p,#mermaid-svg-OFtCmAwrmgWmqUML .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OFtCmAwrmgWmqUML .icon-shape .label rect,#mermaid-svg-OFtCmAwrmgWmqUML .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OFtCmAwrmgWmqUML .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OFtCmAwrmgWmqUML .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OFtCmAwrmgWmqUML :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是





FindDevice

visibleDevice=0
DcGetDeviceLogicidFromPhyid

物理ID→逻辑ID
DcGetCardList

获取所有卡ID
遍历每张卡
DcGetDeviceNumInCard

获取卡内设备数
遍历卡内每个设备
DcGetDeviceLogicID

获取设备的逻辑ID
逻辑ID == 目标?
记录cardID和deviceID
还有更多设备?
还有更多卡?
返回deviceID, cardID

3.7 NpuV1Worker.GetChipName

go 复制代码
func (w *NpuV1Worker) GetChipName() (string, error) {
    invalidName := ""

    if err := w.Initialize(); err != nil {
        return invalidName, fmt.Errorf("cannot init dcmi : %v", err)
    }
    defer w.ShutDown()

    cardNum, cardList, err := w.DcMgr.DcGetCardList()
    if err != nil {
        return invalidName, err
    }
    if cardNum == 0 {
        return invalidName, fmt.Errorf("get chip info failed, no card found")
    }

    for _, cardID := range cardList {
        devNum, err := w.DcMgr.DcGetDeviceNumInCard(cardID)
        if err != nil || devNum == 0 {
            continue
        }
        for devID := int32(0); devID < devNum; devID++ {
            chipInfo, err := w.DcMgr.DcGetChipInfo(cardID, devID)
            if err != nil {
                continue
            }
            if !isValidChipInfo(chipInfo) {
                continue
            }
            return (*chipInfo).Name, nil
        }
    }

    return invalidName, fmt.Errorf("cannot get valid chip info")
}

执行流程

  1. 初始化dcmi → 获取卡列表 → 遍历卡 → 遍历设备 → 获取芯片信息 → 返回第一个有效芯片名
  2. 容错策略:任何单步失败都continue跳过,继续尝试下一个设备
  3. defer确保关闭dcmi连接

设计意图:只需要获取任意一个有效芯片的名称即可确定整个系统的芯片类型(假设同一机器上芯片类型一致)。

3.8 NpuV2Worker.GetChipName

go 复制代码
func (a *NpuV2Worker) GetChipName() (string, error) {
    invalidName := ""

    if err := a.Initialize(); err != nil {
        return invalidName, fmt.Errorf("cannot init dcmi : %v", err)
    }
    defer a.ShutDown()

    deviceNum, deviceList, err := a.DcMgr.DcGetDeviceList()
    // ...
    for _, devID := range deviceList {
        chipInfo, err := a.DcMgr.DcGetChipInfo(devID)
        // ...
        return (*chipInfo).Name, nil
    }
    return invalidName, fmt.Errorf("cannot get valid chip info")
}

与V1的区别

  • V1:卡列表→每卡设备数→遍历cardID+deviceID
  • V2:直接获取设备列表→遍历deviceID

3.9 NpuV1Worker.CreateVDevice

go 复制代码
func (w *NpuV1Worker) CreateVDevice(uniqueID int32, coreNum string) (VDeviceInfo, error) {
    deviceID, cardID, err := w.FindDevice(uniqueID)
    if err != nil {
        return VDeviceInfo{CardID: -1, DeviceID: -1, VdeviceID: -1}, err
    }
    vdevId, err := w.DcMgr.DcCreateVDevice(cardID, deviceID, coreNum)
    if err != nil {
        return VDeviceInfo{CardID: -1, DeviceID: -1, VdeviceID: math.MaxInt32}, err
    }
    if vdevId > math.MaxInt32 {
        return VDeviceInfo{CardID: cardID, DeviceID: deviceID, VdeviceID: math.MaxInt32},
            fmt.Errorf("create virtual device failed, vdeviceId too large")
    }
    return VDeviceInfo{CardID: cardID, DeviceID: deviceID, VdeviceID: int32(vdevId)}, nil
}

逐行解析

  1. FindDevice --- 将物理ID转换为cardID+deviceID
  2. DcCreateVDevice --- 调用CGO创建虚拟设备
  3. 溢出检查:vdevId > math.MaxInt32
  4. 返回完整的VDeviceInfo

3.10 NpuV2Worker.CreateVDevice

go 复制代码
func (a *NpuV2Worker) CreateVDevice(uniqueID int32, coreNum string) (VDeviceInfo, error) {
    vdevId, err := a.DcMgr.DcCreateVDevice(uniqueID, coreNum)
    if err != nil {
        return VDeviceInfo{
            CardID:    -1,
            DeviceID:  -1,
            VdeviceID: -1,
        }, err
    }
    return VDeviceInfo{VdeviceID: vdevId}, nil
}

注意 :V2的 DcCreateVDevice 实际返回错误("ascend 950 not support virtual device"),所以这段代码在当前版本实际上不会成功执行。


四、dcManager.go 逐行解析(294行)

4.1 CGO导入

go 复制代码
// #cgo LDFLAGS: -ldl
// #include "dcmi_interface_api.h"
import "C"
  • LDFLAGS: -ldl --- 链接动态加载库(dlopen)
  • #include "dcmi_interface_api.h" --- DCMI C接口头文件
  • import "C" --- Go的CGO机制,允许调用C函数

4.2 DcV1Manager.DcInitialize

go 复制代码
func (d *DcV1Manager) DcInitialize() error {
    cDlPath := C.CString(string(make([]byte, int32(C.PATH_MAX))))
    defer C.free(unsafe.Pointer(cDlPath))
    if err := C.DcmiInitDl(cDlPath); err != C.SUCCESS {
        errInfo := fmt.Errorf("dcmi lib load failed, error code: %d", int32(err))
        return errInfo
    }
    dlPath := C.GoString(cDlPath)
    if _, err := mindxcheckutils.RealFileChecker(dlPath, true, false, mindxcheckutils.DefaultSize); err != nil {
        return err
    }
    if err := C.DcmiInit(); err != C.SUCCESS {
        errInfo := fmt.Errorf("dcmi init failed, error code: %d", int32(err))
        return errInfo
    }
    return nil
}

逐行解析

  1. make([]byte, C.PATH_MAX) --- 创建PATH_MAX长度的空字节切片
  2. C.CString --- 转换为C字符串(用于接收dcmi库路径输出)
  3. C.DcmiInitDl(cDlPath) --- 动态加载libdcmi.so(dlopen方式),路径通过cDlPath返回
  4. defer C.free --- 释放C字符串内存(防内存泄漏)
  5. C.GoString(cDlPath) --- 将C字符串转回Go字符串
  6. RealFileChecker --- 安全校验加载的dcmi库文件
  7. C.DcmiInit() --- 初始化dcmi设备管理连接

设计意图:两步初始化------先加载动态库(dlopen),再初始化设备连接。安全校验确保加载的是合法dcmi库。
#mermaid-svg-tu8zhbbKHxJoZJTO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tu8zhbbKHxJoZJTO .error-icon{fill:#552222;}#mermaid-svg-tu8zhbbKHxJoZJTO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tu8zhbbKHxJoZJTO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tu8zhbbKHxJoZJTO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tu8zhbbKHxJoZJTO .marker.cross{stroke:#333333;}#mermaid-svg-tu8zhbbKHxJoZJTO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tu8zhbbKHxJoZJTO p{margin:0;}#mermaid-svg-tu8zhbbKHxJoZJTO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO .cluster-label text{fill:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO .cluster-label span{color:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO .cluster-label span p{background-color:transparent;}#mermaid-svg-tu8zhbbKHxJoZJTO .label text,#mermaid-svg-tu8zhbbKHxJoZJTO span{fill:#333;color:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO .node rect,#mermaid-svg-tu8zhbbKHxJoZJTO .node circle,#mermaid-svg-tu8zhbbKHxJoZJTO .node ellipse,#mermaid-svg-tu8zhbbKHxJoZJTO .node polygon,#mermaid-svg-tu8zhbbKHxJoZJTO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tu8zhbbKHxJoZJTO .rough-node .label text,#mermaid-svg-tu8zhbbKHxJoZJTO .node .label text,#mermaid-svg-tu8zhbbKHxJoZJTO .image-shape .label,#mermaid-svg-tu8zhbbKHxJoZJTO .icon-shape .label{text-anchor:middle;}#mermaid-svg-tu8zhbbKHxJoZJTO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tu8zhbbKHxJoZJTO .rough-node .label,#mermaid-svg-tu8zhbbKHxJoZJTO .node .label,#mermaid-svg-tu8zhbbKHxJoZJTO .image-shape .label,#mermaid-svg-tu8zhbbKHxJoZJTO .icon-shape .label{text-align:center;}#mermaid-svg-tu8zhbbKHxJoZJTO .node.clickable{cursor:pointer;}#mermaid-svg-tu8zhbbKHxJoZJTO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tu8zhbbKHxJoZJTO .arrowheadPath{fill:#333333;}#mermaid-svg-tu8zhbbKHxJoZJTO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tu8zhbbKHxJoZJTO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tu8zhbbKHxJoZJTO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tu8zhbbKHxJoZJTO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tu8zhbbKHxJoZJTO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tu8zhbbKHxJoZJTO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tu8zhbbKHxJoZJTO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tu8zhbbKHxJoZJTO .cluster text{fill:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO .cluster span{color:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tu8zhbbKHxJoZJTO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tu8zhbbKHxJoZJTO rect.text{fill:none;stroke-width:0;}#mermaid-svg-tu8zhbbKHxJoZJTO .icon-shape,#mermaid-svg-tu8zhbbKHxJoZJTO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tu8zhbbKHxJoZJTO .icon-shape p,#mermaid-svg-tu8zhbbKHxJoZJTO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tu8zhbbKHxJoZJTO .icon-shape .label rect,#mermaid-svg-tu8zhbbKHxJoZJTO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tu8zhbbKHxJoZJTO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tu8zhbbKHxJoZJTO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tu8zhbbKHxJoZJTO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 失败
成功
不通过
通过
失败
成功
DcInitialize
分配C字符串buffer

PATH_MAX长度
DcmiInitDl

dlopen加载libdcmi.so
返回错误

dcmi lib load failed
获取库路径

C.GoString
RealFileChecker

安全校验库文件
返回错误
DcmiInit

初始化设备连接
返回错误

dcmi init failed
返回nil

4.3 DcV1Manager.DcGetCardList

go 复制代码
func (d *DcV1Manager) DcGetCardList() (int32, []int32, error) {
    var ids [hiAIMaxCardNum]C.int
    var cNum C.int
    if err := C.DcmiGetCardNumList(&cNum, &ids[0], hiAIMaxCardNum); err != 0 {
        return retError, nil, fmt.Errorf("get card list failed, error code: %d", int32(err))
    }
    if cNum <= 0 || cNum > hiAIMaxCardNum {
        return retError, nil, fmt.Errorf("get error card quantity: %d", int32(cNum))
    }
    var cardNum = int32(cNum)
    var cardIDList []int32
    for i := int32(0); i < cardNum; i++ {
        cardID := int32(ids[i])
        if cardID < 0 {
            continue
        }
        cardIDList = append(cardIDList, cardID)
    }
    return cardNum, cardIDList, nil
}

逐行解析

  1. 声明C数组 ids[64] 和数量 cNum
  2. C.DcmiGetCardNumList --- C函数填充卡数量和卡ID列表
  3. 校验数量:1 ≤ cNum ≤ 64
  4. 遍历C数组,过滤负值,转为Go的\[\]int32

4.4 DcV1Manager.DcCreateVDevice

go 复制代码
func (d *DcV1Manager) DcCreateVDevice(cardID, deviceID int32, coreNum string) (int32, error) {
    var createInfo C.struct_DcmiCreateVdevOut
    createInfo.vdevId = C.uint(math.MaxUint32)
    var deviceCreateStr C.struct_DcmiCreateVdevResStru
    deviceCreateStr = C.struct_DcmiCreateVdevResStru{
        vdevId: C.uint(vfgID),
        vfgId:  C.uint(vfgID),
    }
    deviceCreateStrArr := [coreNumLen]C.char{0}
    for i := 0; i < len(coreNum); i++ {
        if i >= coreNumLen {
            return math.MaxInt32, fmt.Errorf("wrong template")
        }
        deviceCreateStrArr[i] = C.char(coreNum[i])
    }
    deviceCreateStr.templateName = deviceCreateStrArr
    ret := C.DcmiCreateVdevice(C.int(cardID), C.int(deviceID), &deviceCreateStr, &createInfo)
    if ret != 0 {
        return math.MaxInt32, fmt.Errorf("create virtual device failed, error code: %d", int32(ret))
    }
    return int32(createInfo.vdevId), nil
}

逐行解析

  1. 创建输出结构体 DcmiCreateVdevOut,初始vdevId设为MaxUint32(表示未创建)
  2. 创建输入结构体 DcmiCreateVdevResStru,设置vdevId和vfgId为默认值(0xFFFFFFFF)
  3. 将切分模板名(如"vir04")逐字节复制到C字符数组
  4. 模板名长度校验(≤32)
  5. 调用 C.DcmiCreateVdevice --- CGO调用创建虚拟设备
  6. 返回创建的vdevId

关键数据结构
#mermaid-svg-Ls9qSzt4Ej6fTd78{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .error-icon{fill:#552222;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .marker.cross{stroke:#333333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 p{margin:0;}#mermaid-svg-Ls9qSzt4Ej6fTd78 g.classGroup text{fill:#9370DB;stroke:none;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .cluster-label text{fill:#333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .cluster-label span{color:#333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .cluster-label span p{background-color:transparent;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .cluster text{fill:#333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .cluster span{color:#333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .nodeLabel,#mermaid-svg-Ls9qSzt4Ej6fTd78 .edgeLabel{color:#131300;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .label text{fill:#131300;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .labelBkg{background:#ECECFF;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .classTitle{font-weight:bolder;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .node rect,#mermaid-svg-Ls9qSzt4Ej6fTd78 .node circle,#mermaid-svg-Ls9qSzt4Ej6fTd78 .node ellipse,#mermaid-svg-Ls9qSzt4Ej6fTd78 .node polygon,#mermaid-svg-Ls9qSzt4Ej6fTd78 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 g.clickable{cursor:pointer;}#mermaid-svg-Ls9qSzt4Ej6fTd78 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-Ls9qSzt4Ej6fTd78 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .dashed-line{stroke-dasharray:3;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #compositionStart,#mermaid-svg-Ls9qSzt4Ej6fTd78 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #compositionEnd,#mermaid-svg-Ls9qSzt4Ej6fTd78 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #dependencyStart,#mermaid-svg-Ls9qSzt4Ej6fTd78 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #dependencyStart,#mermaid-svg-Ls9qSzt4Ej6fTd78 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #extensionStart,#mermaid-svg-Ls9qSzt4Ej6fTd78 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #extensionEnd,#mermaid-svg-Ls9qSzt4Ej6fTd78 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #aggregationStart,#mermaid-svg-Ls9qSzt4Ej6fTd78 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #aggregationEnd,#mermaid-svg-Ls9qSzt4Ej6fTd78 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #lollipopStart,#mermaid-svg-Ls9qSzt4Ej6fTd78 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 #lollipopEnd,#mermaid-svg-Ls9qSzt4Ej6fTd78 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ls9qSzt4Ej6fTd78 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ls9qSzt4Ej6fTd78 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 输入→输出
DcmiCreateVdevResStru
+uint vdevId
+uint vfgId
+char32 templateName "切分模板名如vir04"
DcmiCreateVdevOut
+uint vdevId "创建后的虚拟设备ID"

4.5 DcV1Manager.DcGetChipInfo

go 复制代码
func (d *DcV1Manager) DcGetChipInfo(cardID, deviceID int32) (*ChipInfo, error) {
    if !isValidCardIDAndDeviceID(cardID, deviceID) {
        return nil, fmt.Errorf("cardID(%d) or deviceID(%d) is invalid", cardID, deviceID)
    }
    var chipInfo C.struct_DcmiChipInfo
    if rCode := C.DcmiGetDeviceChipInfo(C.int(cardID), C.int(deviceID), &chipInfo); int32(rCode) != 0 {
        return nil, fmt.Errorf("get device ChipInfo information failed, ...")
    }

    name := convertUCharToCharArr(chipInfo.chipName)
    cType := convertUCharToCharArr(chipInfo.chipType)
    ver := convertUCharToCharArr(chipInfo.chipVer)

    chip := &ChipInfo{
        Name:    string(name),
        Type:    string(cType),
        Version: string(ver),
    }
    if !isValidChipInfo(chip) {
        return nil, fmt.Errorf("get device ChipInfo information failed, chip info is empty, ...")
    }

    return chip, nil
}

逐行解析

  1. 参数校验(cardID和deviceID范围检查)
  2. 声明C结构体 DcmiChipInfo
  3. 调用 C.DcmiGetDeviceChipInfo 获取芯片信息
  4. convertUCharToCharArr --- 将C的uchar数组转为Go byte切片(遇0截断)
  5. 构造Go的ChipInfo结构体
  6. 有效性校验

4.6 convertUCharToCharArr --- C数组转Go

go 复制代码
func convertUCharToCharArr(cgoArr [maxChipNameLen]C.uchar) []byte {
    var charArr []byte
    for _, v := range cgoArr {
        if v == 0 {
            break
        }
        charArr = append(charArr, byte(v))
    }
    return charArr
}
  • C字符串以null(0)结尾,遍历到0即停止
  • 将C的[32]uchar转为Go的[]byte,再转为string

4.7 DcV2Manager --- V2 CGO实现

go 复制代码
func (d *DcV2Manager) DcInitialize() error {
    // ...同V1的DcmiInitDl...
    if err := C.DcmiV2Init(); err != C.SUCCESS {
        return fmt.Errorf("dcmi init failed, error code: %d", int32(err))
    }
    return nil
}

关键差异 :V2调用 C.DcmiV2Init() 而非 C.DcmiInit()

go 复制代码
func (d *DcV2Manager) DcCreateVDevice(deviceID int32, coreNum string) (int32, error) {
    return -1, fmt.Errorf("create error, ascend 950 not support virtual device")
}

func (d *DcV2Manager) DcDestroyVDevice(deviceID int32, vDevID int32) error {
    return fmt.Errorf("destroy error, ascend 950 not support virtual device")
}

V2不支持虚拟设备:Ascend 950(910A5)不支持vNPU切分,直接返回错误。

go 复制代码
func (d *DcV2Manager) DcGetDeviceList() (int32, []int32, error) {
    var ids [hiAIMaxCardNum]C.int
    var cNum C.int
    if err := C.DcmiV2GetDeviceList(&ids[0], &cNum, hiAIMaxCardNum); err != 0 {
        return retError, nil, fmt.Errorf("get device list failed, error code: %d", int32(err))
    }
    // ...校验+转换...
    return deviceNum, deviceIDList, nil
}

V2直接获取设备列表,无需先获取卡列表再遍历卡内设备。


五、V1 vs V2 完整对比

#mermaid-svg-7FJDdB1jd6Ui6Vgt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .error-icon{fill:#552222;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .marker.cross{stroke:#333333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt p{margin:0;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .cluster-label text{fill:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .cluster-label span{color:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .cluster-label span p{background-color:transparent;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .label text,#mermaid-svg-7FJDdB1jd6Ui6Vgt span{fill:#333;color:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .node rect,#mermaid-svg-7FJDdB1jd6Ui6Vgt .node circle,#mermaid-svg-7FJDdB1jd6Ui6Vgt .node ellipse,#mermaid-svg-7FJDdB1jd6Ui6Vgt .node polygon,#mermaid-svg-7FJDdB1jd6Ui6Vgt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .rough-node .label text,#mermaid-svg-7FJDdB1jd6Ui6Vgt .node .label text,#mermaid-svg-7FJDdB1jd6Ui6Vgt .image-shape .label,#mermaid-svg-7FJDdB1jd6Ui6Vgt .icon-shape .label{text-anchor:middle;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .rough-node .label,#mermaid-svg-7FJDdB1jd6Ui6Vgt .node .label,#mermaid-svg-7FJDdB1jd6Ui6Vgt .image-shape .label,#mermaid-svg-7FJDdB1jd6Ui6Vgt .icon-shape .label{text-align:center;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .node.clickable{cursor:pointer;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .arrowheadPath{fill:#333333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7FJDdB1jd6Ui6Vgt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7FJDdB1jd6Ui6Vgt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7FJDdB1jd6Ui6Vgt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .cluster text{fill:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .cluster span{color:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7FJDdB1jd6Ui6Vgt rect.text{fill:none;stroke-width:0;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .icon-shape,#mermaid-svg-7FJDdB1jd6Ui6Vgt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .icon-shape p,#mermaid-svg-7FJDdB1jd6Ui6Vgt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .icon-shape .label rect,#mermaid-svg-7FJDdB1jd6Ui6Vgt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7FJDdB1jd6Ui6Vgt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7FJDdB1jd6Ui6Vgt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7FJDdB1jd6Ui6Vgt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} V2 新版驱动 Ascend 910B/A5
DcmiV2Init
DcmiV2GetDeviceList

直接获取设备列表
DcmiV2GetDeviceChipInfo

仅deviceID
不支持vNPU

返回错误
V1 旧版驱动 Ascend 910/310
DcmiInit
DcmiGetCardNumList

获取卡列表
DcmiGetDeviceNumInCard

每卡设备数
DcmiGetDeviceChipInfo

cardID+deviceID
DcmiCreateVdevice

支持vNPU切分
DcmiSetDestroyVdevice

销毁vNPU
DcmiGetDeviceLogicidFromPhyid

物理ID→逻辑ID

对比维度 V1 (DcV1Manager) V2 (DcV2Manager)
初始化 DcmiInitDl + DcmiInit DcmiInitDl + DcmiV2Init
设备寻址 cardID + deviceID 二级 deviceID 一级
获取设备列表 DcmiGetCardNumList → 遍历卡 → DcmiGetDeviceNumInCard DcmiV2GetDeviceList 一步到位
芯片信息 DcmiGetDeviceChipInfo(cardID, deviceID) DcmiV2GetDeviceChipInfo(deviceID)
产品类型 支持 DcmiGetProductType 不支持(返回"not support")
vNPU切分 支持 DcmiCreateVdevice 不支持(返回错误)
物理ID转换 需要 DcmiGetDeviceLogicidFromPhyid 不需要
适用芯片 Ascend 910, 310, 310P, 310B Ascend 910B, A5 (950)
相关推荐
giaming0232 小时前
告别Docker Desktop!一款轻量级原生开发环境管理工具:FlyEnv
运维·docker·容器
沉迷学习 日益消瘦4 小时前
13-Ingress 生产实战
运维·kubernetes
暗影凋落5 小时前
docker-image 工具展示更详细镜像层内容
运维·docker·容器
极客先躯5 小时前
高级java每日一道面试题-2026年05月11日-实战篇[Docker]-如何容器化金融产品推荐系统?
java·运维·docker·容器·金融·高级面试·金融产品推荐系统
江湖有缘7 小时前
Docker实战 : 使用Docker部署Musicn音乐下载工具
docker·容器·eureka
沉迷学习 日益消瘦7 小时前
17-Custom Resource 入门
docker·容器·kubernetes
沉迷学习 日益消瘦8 小时前
14-Pod 安全上下文
安全·kubernetes
腾飞开源10 小时前
01_K8s干货笔记之认识K8s
运维·笔记·云原生·容器·kubernetes·k8s·容器化部署
江湖有缘19 小时前
Docker实战 :使用Docker部署OneTerm堡垒机
运维·docker·容器