You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix: runtime isolation in pytest and unified DevicePool
CANN AICPU framework caches user .so per device context (firstCreatSo_
flag in BackendServerHandleManager). Switching runtimes on the same
device within one process causes hangs.
Changes:
- conftest.py: pytest_runtestloop auto-detects multiple runtimes and
spawns one subprocess per runtime for isolation. --runtime filter
option for single-runtime runs. L3 tests ordered before L2.
- conftest.py: unified DevicePool (no sim/onboard branching), --device
is the single source of truth. CI passes --device 0-15 for sim,
--device ${DEVICE_RANGE} for onboard.
- host_build_graph paged_attention case2: mark manual (precision issue,
was not run by ci.py DEFAULT_CASE either).
- docs: document runtime isolation constraint and root cause in
testing.md and distributed_level_runtime.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: docs/distributed_level_runtime.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -339,6 +339,12 @@ Python Application
339
339
└── forked child process ← mailbox state machine
340
340
```
341
341
342
+
## Runtime Isolation (Onboard Hardware)
343
+
344
+
A single device can only run **one runtime** per CANN process context. CANN's AICPU framework (`libaicpu_extend_kernels.so`) caches the user AICPU .so on first load and skips reloading on subsequent launches. If a different runtime's AICPU .so is launched on the same device, the cached (stale) function pointers are used, causing hangs.
345
+
346
+
This means: **do not reuse a device across different runtimes within a single process.** Either use separate processes (one per runtime), or partition devices so each runtime gets exclusive devices. See [testing.md](testing.md#runtime-isolation-constraint-onboard) for details and the pytest device allocation algorithm.
Copy file name to clipboardExpand all lines: docs/testing.md
+65Lines changed: 65 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -331,6 +331,71 @@ The test will be automatically picked up by `ci.py`. New tests should prefer the
331
331
332
332
See [ci.md](ci.md) for the full CI pipeline documentation, including the job matrix, runner constraints, marker scheme, and `ci.sh` internals.
333
333
334
+
## Runtime Isolation Constraint (Onboard)
335
+
336
+
**One device can only run one runtime per process.** Switching runtimes on the same device within a single process causes AICPU kernel hangs.
337
+
338
+
### Root Cause
339
+
340
+
CANN's AICPU dispatch uses a framework SO (`libaicpu_extend_kernels.so`) with a global singleton `BackendServerHandleManager` that:
341
+
342
+
1.**`SaveSoFile`**: Writes the user AICPU .so to disk on first call, then sets `firstCreatSo_ = true` to skip all subsequent writes.
343
+
2.**`SetTileFwkKernelMap`**: `dlopen`s the .so and caches function pointers on first call, then sets `firstLoadSo_ = true` to skip all subsequent loads.
344
+
345
+
When a second runtime launches on the same device (same CANN process context), the Init kernel call hits the cached flags — the new AICPU .so is never written or loaded. The Exec kernel then calls function pointers from the first runtime's .so, which operates on incompatible data structures and hangs.
346
+
347
+
### Impact
348
+
349
+
| Scenario | Result |
350
+
| -------- | ------ |
351
+
| Same runtime, same device, sequential | Works (same .so, cached pointers valid) |
352
+
| Different runtime, same device, sequential |**Hangs** (stale .so, wrong function pointers) |
353
+
| Different runtime, different device | Works (separate CANN context per device) |
354
+
| Different runtime, different process, same device | Works (`rtDeviceReset` between processes clears context) |
355
+
356
+
### Mitigation in pytest
357
+
358
+
The `conftest.py` device allocator groups tests by runtime and assigns each runtime group to exclusive devices. See "Device Allocation Algorithm" below.
359
+
360
+
## Device Allocation Algorithm (Onboard pytest)
361
+
362
+
When running `pytest --platform a2a3 --device 8-11`, the fixture must allocate devices to tests such that:
363
+
364
+
1.**Runtime isolation**: A device used by runtime A must not be reused by runtime B in the same process.
365
+
2.**L3 multi-device**: L3 tests may need 2+ contiguous devices.
366
+
3.**Efficiency**: Devices freed by one test of the same runtime can be reused by the next.
tensormap_and_ringbuffer (6 tests, needs max 2 for L3 group): devices [8, 9]
379
+
aicpu_build_graph (1 test, needs 1): devices [10]
380
+
host_build_graph (1 test, needs 1): devices [11]
381
+
382
+
Phase 3: Within each group, allocate from group's device pool
383
+
TestVectorExample: dev 8 → run → release → dev 8 available again
384
+
TestScalarData: dev 8 → run → release → OK (same runtime)
385
+
TestL3Dependency: dev 8 → run → release
386
+
TestL3Group: dev [8, 9] → run → release
387
+
TestPagedAttentionAicpuBuildGraph: dev 10 → run → release
388
+
TestPagedAttentionHostBuildGraph: dev 11 → run → release
389
+
```
390
+
391
+
### Implementation
392
+
393
+
The `DevicePool` in `conftest.py` is extended with runtime-aware partitioning. The `st_worker` fixture checks the test class's `_st_runtime` and allocates from the corresponding partition.
394
+
395
+
### Sim platforms
396
+
397
+
On sim (`a2a3sim`, `a5sim`), device IDs are virtual — no hardware state, no isolation constraint. All tests share a single virtual pool with auto-incrementing IDs.
398
+
334
399
## Per-Case Device Filtering
335
400
336
401
The `@scene_test(platforms=[...])` decorator provides per-case platform filtering. A single test class declares which platforms it supports:
0 commit comments