HAMi 2.10 Deep Dive (Part 2): One Ascend Card, Two Pods — Testing Volcano + HAMi-core vNPU Soft Slicing

GPUs have HAMi for hard memory isolation — but what about Ascend NPUs? In the second article of our HAMi 2.10 deep-dive series, we validate Volcano scheduling + HAMi-core soft slicing on a real Ascend 310P3: the container sees only its 8192 MiB slice, two Pods binpack onto the same physical card, and monitoring metrics report faithfully.

In Part 1 we tested KAI Scheduler + HAMi-core hard memory isolation on NVIDIA GPUs: two Pods sharing one T4, and neither could grab a single extra MiB. Readers immediately asked: what about Ascend NPUs?

Ascend is the workhorse of domestic AI inference in China. A 310P3 carries 21.5 GiB of memory; wasting an entire card per inference service is just as painful there. But sharing an NPU is even easier to get wrong than sharing a GPU — vNPU, hard slicing, soft slicing, Volcano modes: a pile of concepts tangled together, and just sorting out "who is slicing the card and what comes out" can cost you half a day.

This is the second article in our HAMi 2.10 deep-dive series, focused on a major Ascend management upgrade in HAMi v2.10: running hami-vnpu-core soft-sliced vNPUs with the Volcano scheduler, so that batch scheduling semantics (queues, gangs, binpack) work together with container-level isolation (memory and compute caps enforced at the Ascend API layer).

The short answer: on a single-node Kubernetes cluster on an Ascend 310P3 aarch64 server, we ran the full chain end to end — a container requesting an 8192 MiB slice sees exactly 8192 MiB inside npu-smi; a second Pod lands binpacked on the same physical card with an independent slice; and the plugin's Prometheus endpoint faithfully reports both containers' quotas.

Background: the Volcano–Ascend–HAMi Triangle

Three roles, each in place:

Volcano is the Kubernetes-native batch and AI workload scheduler, a CNCF incubating project providing queues, gang scheduling, binpack/spread, and friends — the scheduler of choice for many AI clusters.

Ascend NPUs are Huawei's AI accelerators. A logical device carved out of a physical NPU and handed to a container is called a vNPU — a 21.5 GiB card can be split into an 8 GiB plus an 8 GiB slice, leaving about 5.5 GiB spare.

HAMi plays the enforcer: its Ascend runtime isolation component is hami-vnpu-core (injecting libvnpu.so), which enforces memory and compute quotas at the Ascend API layer.

HAMi v2.10 gave Ascend management an overall upgrade: the new Volcano integration, heterogeneous management that lets template-based vNPUs and HAMi-core nodes coexist in one cluster, and vNPU HAMi-core monitoring. This article covers the "Volcano + soft slicing" path.

First, Untangle: NPU, vNPU, Hard Slicing, Soft Slicing

This is where most confusion lives, so let's separate the layers:

LayerQuestion it answers
NPU / vNPUWhat device you get: a vNPU is a logical device carved from a physical NPU for a container
Hard / soft slicingHow that virtual device is isolated
HAMi-coreWho enforces the soft-slicing quota inside the container
HAMi / VolcanoWho decides which card and how much a Pod gets

Hard slicing is done by the Ascend driver/firmware virtualization capabilities; users can only pick from predefined templates: vir05_1c_16g means a fixed number of AI Cores, AI CPUs, and 16 GiB of memory. After creation, a real vNPU instance appears at the device layer (query supported templates with npu-smi info -t template-info).

Soft slicing does not create a real vNPU in hardware. Instead, multiple containers share the same physical NPU; libvnpu.so is injected into the container to intercept the application's Ascend runtime API calls and account for them:

Soft slicing: the application container calls Ascend APIs; libvnpu.so intercepts and accounts, letting only quota-compliant memory and compute through; containers share the physical NPU
Figure 1: Soft slicing: the application container calls Ascend APIs; libvnpu.so intercepts and accounts, letting only quota-compliant memory and compute through; containers share the physical NPU

Take an 8192 MiB quota: the application sees exactly 8192 MiB when querying the device, memory allocations are accounted by libvnpu.so, and requests beyond the quota are blocked by the runtime interception layer. Comparing the two:

Hard slicingSoft slicing
Isolation boundaryEnforced at device virtualization layer, strongerSoftware runtime interception, not an SR-IOV-class hardware boundary
SizesVendor templates only, e.g. 8 GiB / 16 GiB tiersAny MiB, any compute ratio
Slicing unitsAI Core, AI CPU, memory, DVPPMemory and compute quotas
PrerequisitesChip/driver must support the templateRequires libvnpu.so injection and driver compatibility; ARM only for now

A useful mental model: hard slicing builds real walls inside the house; soft slicing means everyone shares the house, but there's a strict accounting and rate-limiting steward at every door.

Note that the "soft-sliced vNPU" in this article is a logical slice from the Kubernetes/HAMi perspective — not an Ascend hardware vNPU created via npu-smi ... create-vnpu.

Two Ways Volcano Schedules Ascend vNPUs

Volcano can schedule Ascend virtual NPUs in two different ways, which are easy to confuse. Getting this straight up front will save you hours of debugging:

MindCluster modeHAMi mode
Volcano flagdeviceshare.AscendMindClusterVNPUEnabledeviceshare.AscendHAMiVNPUEnable
ProviderVolcano's native Ascend pluginProject-HAMi/ascend-device-plugin
Templatesvir04_3c_ndvpp (with a dvpp dimension)vir05_1c_16g (only memory/aiCore/aiCPU fields)
SlicingDriver templates (hard slicing)Driver templates by default; soft slicing when the Pod sets huawei.com/vnpu-mode: hami-core
Resource nameshuawei.com/npu-corehuawei.com/Ascend310P, -memory

This article is about soft slicing via hami-vnpu-core in HAMi mode. One important caveat: HAMi mode does not equal soft-slicing mode — the same ascend-device-plugin supports both template hard slicing and hami-vnpu-core soft slicing, selected by the Pod's annotation. It is also the only one of the two Volcano modes that does runtime interception: instead of pre-slicing cards into fixed virtualization templates, it intercepts Ascend calls in user space and enforces per-container memory and compute ceilings at runtime. Volcano decides which Pod gets which slice; HAMi-core makes that decision actually stick.

What This Integration Actually Adds

First, a naming correction: HAMi-core is the umbrella term for this class of in-container runtime isolation technologies, originally referring mostly to NVIDIA's libvgpu.so; hami-vnpu-core is the Ascend NPU implementation, injecting libvnpu.so.

Ascend soft slicing itself isn't new: support landed in the code in April 2026 and the chain was already usable in HAMi 2.9. HAMi 2.10's Volcano integration didn't reinvent soft slicing — it swapped the "allocator" from HAMi Scheduler to Volcano, reusing the two lower layers as-is:

HAMi 2.9 used HAMi Scheduler; HAMi 2.10 swaps in Volcano Scheduler while reusing the same ascend-device-plugin and hami-vnpu-core layers
Figure 2: HAMi 2.9 used HAMi Scheduler; HAMi 2.10 swaps in Volcano Scheduler while reusing the same ascend-device-plugin and hami-vnpu-core layers

LayerHAMi 2.9 pathVolcano integration path
SchedulerHAMi SchedulerVolcano Scheduler
Device discovery/mountingascend-device-pluginSame ascend-device-plugin
Soft slicing enforcementhami-vnpu-core (libvnpu.so)Same hami-vnpu-core
Memory/compute isolationSupportedReused as-is
Queues, gang schedulingNot the focusProvided by Volcano
binpack / spreadHAMi policiesVolcano deviceshare policies
Monitoring & mixed managementEarlyFurther completed in 2.10

Volcano can now understand these HAMi Ascend resources and decide: which physical NPU serves which Pod, whether multiple Pods binpack onto one card, whether a training group satisfies gang conditions, which queue, priority, and preemption policy apply. The accurate statement is: this integration delivers "Volcano scheduling of Ascend HAMi-core soft-sliced resources," plus monitoring and mixed hard/soft management; the Ascend soft-slicing capability itself long predates it.

How the Integration Chain Works

Three players divide the work:

  • Volcano's deviceshare plugin reads vNPU geometries from the hami-scheduler-device ConfigMap (with AscendHAMiVNPUEnable: "true") and, per binpack or spread policy, decides which node and which card serves each Pod;
  • The ascend-device-plugin DaemonSet registers huawei.com/Ascend310P (cards) and huawei.com/Ascend310P-memory (MiB) extended resources on the node, and copies HAMi-core assets (libvnpu.so and ld.so.preload) to /usr/local/hami-vnpu-core/ on the host;
  • HAMi-core (libvnpu.so) is injected into workload containers via the Ascend Docker Runtime's preload mechanism, enforcing the slice chosen by the scheduler.

Integration chain: ascend-device-plugin reports capacity; the Volcano deviceshare plugin reads templates and binds slices; libvnpu.so intercepts Ascend calls; per-container limits are enforced and metrics exported on port 9395
Figure 3: Integration chain: ascend-device-plugin reports capacity; the Volcano deviceshare plugin reads templates and binds slices; libvnpu.so intercepts Ascend calls; per-container limits are enforced and metrics exported on port 9395

The Pod-side contract is compact — four things, none optional:

spec:
  schedulerName: volcano        # hand scheduling to Volcano
  runtimeClassName: ascend      # Ascend Docker Runtime
  containers:
    - name: npu
      resources:
        limits:
          huawei.com/Ascend310P: "1"          # 1 vNPU
          huawei.com/Ascend310P-memory: "8192" # 8192 MiB memory slice

Plus the annotation huawei.com/vnpu-mode: hami-core. Without this annotation the Pod falls back to the template path and may stay Pending forever on a pure soft-slicing node — the most common way to trip over this.

Real-Machine Validation: Container Sees Only Its Slice, Two Pods Share a Card

Test environment: Kylin V10 aarch64 single-node Kubernetes 1.28 cluster, 2× Ascend 310P3 (driver/npu-smi 25.5.1), containerd 1.7.1. Volcano was built from source per Lab 13 (at the time of writing, soft slicing requires 1.16 while the stable release was still v1.15.1); the plugin is the official ascend-device-plugin v1.4.0.

After registration, the node reported 14 vNPUs (2 cards × 7, matching vDeviceCount: 7) and 43054 MiB of allocatable memory.

Check 1: the container sees only its slice. npu-smi info inside the first Pod shows a 0 / 8192 MB device, while the host sees 1848 / 21525 MB on the same card:

$ kubectl exec ascend-vnpu-check -- npu-smi info
[INFO limiter::manager] [Manager] Registered as Global Manager #0 (PID: 10).
  Compute limit: 1, Memory limit: 8192, FixedShare: false
| 0  0 | 0000:81:00.0 | 0  0 / 8192 |

The injected environment variables confirm the wiring: NPU_MEM_QUOTA=8192, ASCEND_VISIBLE_DEVICES=0. libvnpu.so has rewritten the device query to the container's quota.

Check 2: binpack puts two Pods on one physical card. A second identically-sized Pod landed on the same Bus-Id 0000:81:00.0, each with an independent 8192 MiB window, registered as Global Manager #1 into the same shared registry as Pod 1's #0. The node's allocated resources tell the same story: huawei.com/Ascend310P 2 (of 14), Ascend310P-memory 16384 (of 43054) — two 8192 MiB slices packed into one 21.5 GiB card rather than spread across two.

Check 3: container-level metrics export works. The plugin (not the workload Pod) serves Prometheus metrics on :9395:

hami_vgpu_memory_limit_bytes{...,pod="ascend-vnpu-check",vdevice_index="0"} 8.589934592e+09
hami_vgpu_memory_limit_bytes{...,pod="ascend-vnpu-check-2",vdevice_index="0"} 8.589934592e+09

8.589934592e+09 bytes is exactly 8192 MiB, matching both Pods' requests. The endpoint also exports live usage and utilization metrics across host/container/vdevice layers.

CheckResultEvidence
Memory slice isolationPassContainer 0 / 8192, host 1848 / 21525
binpack onto one cardPassBoth Pods on Bus-Id 0000:81:00.0, Global Manager #0/#1
Resource accountingPassNode allocated 2 vNPUs, 16384 MiB
MonitoringPass:9395 exports host/container/vdevice metrics

Pitfalls Worth Knowing Before You Try

Nothing teaches like running it on real hardware:

  • libvnpu.so must match the NPU driver. A mismatch doesn't error out; npu-smi inside the container just hangs forever at Initialize SchedulerClient.... Copy assets from the official image version matching your driver and verify md5.
  • Docker and containerd image stores are isolated. Import with ctr -n k8s.io images import, or get ready for ErrImageNeverPull.
  • The Helm key for image pull policy is basic.image_pull_policy (underscore), not scheduler.imagePullPolicy.
  • v1.4.0 does not register -core resources. The Pod spec needs only huawei.com/Ascend310P (cards) and huawei.com/Ascend310P-memory (MiB).
  • Metrics live on the plugin Pod. Curling :9395 in a workload Pod gets nothing; select the DaemonSet Pod by label.
  • After uninstalling Volcano, volcano-system may stick in Terminating (after the webhooks are gone); clearing the namespace's finalizers resolves it.

One last restatement of the boundary: soft slicing here is runtime API-layer enforcement (libvnpu.so software interception), not an SR-IOV-style hardware security boundary — same characterization as HAMi-core on GPUs. It's plenty for trusted intra-team sharing and inference co-location; for untrusted multi-tenancy, evaluate hard slicing instead.

Summary

  • Ascend vNPUs come in two flavors: driver-template hard slicing (building walls) and hami-vnpu-core soft slicing (shared house plus an accounting steward at each door); the latter supports arbitrary MiB and compute ratios;
  • HAMi 2.10's Volcano integration swaps the "allocator" (Volcano Scheduler takes over queues, gangs, binpack) while reusing the device-mounting and runtime-isolation layers, and completes monitoring and mixed hard/soft management;
  • Validated on real hardware: the container sees only its 8192 MiB slice, two Pods binpack onto one physical card, container-level monitoring reports faithfully — on Ascend, too, "we agreed to split it, and nobody grabs more" holds.

With this, the HAMi 2.10 deep-dive series has covered both scheduler-integration paths: NVIDIA GPUs (KAI Scheduler) and Ascend NPUs (Volcano). The shared pattern: the scheduler allocates, HAMi-core makes the allocation stick.

Author: Jimmy Song (宋净超), Dynamia AI.

Series Reading

References

Share this article