From 588ec4b3355e9a9721f116d3d0bea72380a3eb47 Mon Sep 17 00:00:00 2001 From: Chao Wang <26245345+ChaoWao@users.noreply.github.com> Date: Mon, 9 Nov 2026 19:02:46 -0800 Subject: [PATCH 1/2] Fix: align Torch-NPU CI and onboard host namespaces Name the dedicated scene job by its Torch-NPU dependency. Eager and cold capture share the same declared environment. Default cases stay in the onboard job. Use simpler namespaces for the onboard context and topology helpers and their in-tree callers. --- .../actions/setup-framework-eager/action.yml | 2 +- .github/workflows/_st-npu-a2a3.yml | 2 +- ...-framework-eager.yml => _st-torch-npu.yml} | 10 ++-- .github/workflows/ci-a5-comment.yml | 8 +-- .github/workflows/ci-self.yml | 8 +-- .github/workflows/ci.yml | 4 +- .github/workflows/daily.yml | 8 +-- docs/ci.md | 41 ++++++------- examples/workers/l2/framework_eager/README.md | 6 +- .../onboard/host/aicpu_affinity_select.cpp | 4 +- .../onboard/host/aicpu_topology_probe.cpp | 4 +- .../onboard/host/aicpu_topology_probe.h | 4 +- .../onboard/host/context_preparation.cpp | 4 +- .../onboard/host/context_preparation.h | 4 +- .../platform/onboard/host/device_runner.cpp | 11 ++-- .../platform/onboard/host/device_runner.h | 2 +- .../onboard/host/aicpu_affinity_select.cpp | 4 +- .../onboard/host/aicpu_topology_probe.cpp | 4 +- .../onboard/host/aicpu_topology_probe.h | 4 +- .../onboard/host/context_preparation.cpp | 4 +- .../onboard/host/context_preparation.h | 4 +- .../platform/onboard/host/device_runner.cpp | 36 ++++++------ src/a5/platform/onboard/host/device_runner.h | 8 +-- .../runtime/runtime.h | 2 +- .../platform/test_aicpu_affinity_select.cpp | 6 +- .../platform/test_aicpu_topology_fallback.cpp | 58 +++++++++---------- .../common/platform/test_native_admission.cpp | 28 ++++----- tests/ut/py/test_a5_comment_ci.py | 6 +- .../py/test_aicpu_topology_driver_headers.py | 8 +-- .../ut/py/test_framework_eager_ci_platform.py | 13 +++-- tests/ut/py/test_framework_eager_contract.py | 4 +- .../host/query_device_hal.cpp | 20 +++---- 32 files changed, 167 insertions(+), 164 deletions(-) rename .github/workflows/{_st-framework-eager.yml => _st-torch-npu.yml} (92%) diff --git a/.github/actions/setup-framework-eager/action.yml b/.github/actions/setup-framework-eager/action.yml index c230fc1eba..9ccd61c687 100644 --- a/.github/actions/setup-framework-eager/action.yml +++ b/.github/actions/setup-framework-eager/action.yml @@ -1,4 +1,4 @@ -name: Set up framework eager environment +name: Set up Torch-NPU test environment description: Install the CANN 9.0+ framework consumer in its own virtual environment. inputs: diff --git a/.github/workflows/_st-npu-a2a3.yml b/.github/workflows/_st-npu-a2a3.yml index 40ea43b54a..8acb143ef6 100644 --- a/.github/workflows/_st-npu-a2a3.yml +++ b/.github/workflows/_st-npu-a2a3.yml @@ -96,7 +96,7 @@ jobs: --platform a2a3 --compile-only --compile-workers 32 done - # Framework eager has its own dependency-isolated job. The remaining + # Torch-NPU cases have their own dependency-isolated job. The remaining # three selections are disjoint and exhaustive over this corpus: a test with # neither marker lands here, `sdma` alone in the demo task, and # `sdma_fault` in the isolated one whether or not it also carries `sdma`. diff --git a/.github/workflows/_st-framework-eager.yml b/.github/workflows/_st-torch-npu.yml similarity index 92% rename from .github/workflows/_st-framework-eager.yml rename to .github/workflows/_st-torch-npu.yml index 6b89cb9ba1..69ef6b9d7a 100644 --- a/.github/workflows/_st-framework-eager.yml +++ b/.github/workflows/_st-torch-npu.yml @@ -1,4 +1,4 @@ -name: Framework Eager Scene Tests +name: Torch-NPU Scene Tests permissions: contents: read @@ -25,7 +25,7 @@ on: jobs: run: - name: st-framework-eager-${{ inputs.platform }} + name: st-torch-npu-${{ inputs.platform }} runs-on: ${{ fromJSON(inputs.runs_on) }} timeout-minutes: 45 env: @@ -41,13 +41,13 @@ jobs: ref: ${{ inputs.ref || github.ref }} persist-credentials: false - - name: Set up framework environment + - name: Set up Torch-NPU environment id: framework uses: ./.github/actions/setup-framework-eager with: platform: ${{ inputs.platform }} - - name: Run the declared framework environment exclusively + - name: Run Torch-NPU scene tests exclusively env: CANN_ENV: ${{ steps.framework.outputs.cann_env }} MANUAL_MODE: ${{ inputs.manual_mode }} @@ -76,7 +76,7 @@ jobs: --basetemp outputs/framework-eager-ci/pytest --junitxml outputs/framework-eager-ci/results.xml" .venv-framework/bin/python -m simpler_setup.test_environments verify outputs/framework-eager-ci/results.plan.json outputs/framework-eager-ci/results.xml - - name: Retain framework eager identities and logs + - name: Retain Torch-NPU identities and logs if: always() # The test result is already checked above; artifact service failures only lose diagnostics. continue-on-error: true diff --git a/.github/workflows/ci-a5-comment.yml b/.github/workflows/ci-a5-comment.yml index fd78734097..7ccde45450 100644 --- a/.github/workflows/ci-a5-comment.yml +++ b/.github/workflows/ci-a5-comment.yml @@ -91,13 +91,13 @@ jobs: runs_on: '["self-hosted","a5"]' include_dfx_smokes: true - st-framework-eager-a5: + st-torch-npu-a5: needs: [gate-and-resolve] if: needs.gate-and-resolve.outputs.ready == 'true' concurrency: group: ci-a5-framework-${{ needs.gate-and-resolve.outputs.pr_number }} cancel-in-progress: true - uses: ./.github/workflows/_st-framework-eager.yml + uses: ./.github/workflows/_st-torch-npu.yml with: platform: a5 repository: ${{ needs.gate-and-resolve.outputs.repository }} @@ -105,7 +105,7 @@ jobs: runs_on: '["self-hosted","a5"]' report: - needs: [gate-and-resolve, ut-a5, st-onboard-a5, st-framework-eager-a5] + needs: [gate-and-resolve, ut-a5, st-onboard-a5, st-torch-npu-a5] if: always() && needs.gate-and-resolve.result == 'success' && needs.gate-and-resolve.outputs.ready == 'true' runs-on: ubuntu-24.04 permissions: @@ -122,7 +122,7 @@ jobs: const gate = needs['gate-and-resolve']; if (gate.result !== 'success' || gate.outputs.ready !== 'true') return; const { repository, ref, pr_number: number } = gate.outputs; - const suites = ['ut-a5', 'st-onboard-a5', 'st-framework-eager-a5']; + const suites = ['ut-a5', 'st-onboard-a5', 'st-torch-npu-a5']; const results = suites.map(name => ({ name, result: needs[name]?.result || 'unknown' })); const passed = results.every(job => job.result === 'success'); const url = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; diff --git a/.github/workflows/ci-self.yml b/.github/workflows/ci-self.yml index 5569f41abb..e88c820bf8 100644 --- a/.github/workflows/ci-self.yml +++ b/.github/workflows/ci-self.yml @@ -140,20 +140,20 @@ jobs: runs_on: '["self-hosted","a2a3"]' include_cann_examples: false - st-framework-eager-a2a3: + st-torch-npu-a2a3: needs: [detect-changes, pre-commit] if: needs.detect-changes.outputs.a2a3_changed == 'true' && needs.detect-changes.outputs.st_affected == 'true' - uses: ./.github/workflows/_st-framework-eager.yml + uses: ./.github/workflows/_st-torch-npu.yml with: platform: a2a3 repository: ${{ inputs.repository || github.repository }} ref: ${{ inputs.ref || github.sha }} runs_on: '["self-hosted","a2a3"]' - st-framework-eager-a5: + st-torch-npu-a5: needs: [detect-changes, pre-commit] if: needs.detect-changes.outputs.a5_changed == 'true' && needs.detect-changes.outputs.st_affected == 'true' - uses: ./.github/workflows/_st-framework-eager.yml + uses: ./.github/workflows/_st-torch-npu.yml with: platform: a5 repository: ${{ inputs.repository || github.repository }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6aa9bf5c22..c24333b193 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,10 +103,10 @@ jobs: runs_on: '["self-hosted","a2a3"]' include_cann_examples: true - st-framework-eager-a2a3: + st-torch-npu-a2a3: needs: [detect-changes, pre-commit] if: needs.detect-changes.outputs.a2a3_changed == 'true' && needs.detect-changes.outputs.st_affected == 'true' - uses: ./.github/workflows/_st-framework-eager.yml + uses: ./.github/workflows/_st-torch-npu.yml with: platform: a2a3 runs_on: '["self-hosted","a2a3"]' diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 17c8bb0765..940e08badf 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -56,15 +56,15 @@ jobs: session_timeout_seconds: 1800 job_timeout_minutes: 60 - st-framework-eager-a2a3: - uses: ./.github/workflows/_st-framework-eager.yml + st-torch-npu-a2a3: + uses: ./.github/workflows/_st-torch-npu.yml with: platform: a2a3 runs_on: '["self-hosted","a2a3"]' manual_mode: include - st-framework-eager-a5: - uses: ./.github/workflows/_st-framework-eager.yml + st-torch-npu-a5: + uses: ./.github/workflows/_st-torch-npu.yml with: platform: a5 runs_on: '["self-hosted","a5"]' diff --git a/docs/ci.md b/docs/ci.md index 01341bf19e..2fe10bf8f5 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -24,7 +24,7 @@ The complete test-type × hardware-tier matrix across automatic CI, the A5 comme | Category | github-hosted (no hardware) | a2a3 runner | a5 runner | | -------- | --------------------------- | ----------- | --------- | | **ut** | `ut` (py + cpp) | `ut-a2a3` (py + cpp) | `ut-a5` (py) | -| **st** | `st-sim-a2a3`, `st-sim-a5` | `st-onboard-a2a3`, `st-network1-onboard-a2a3`, `st-deepseek-onboard-a2a3`, `st-framework-eager-a2a3` | `st-onboard-a5`, `st-framework-eager-a5` | +| **st** | `st-sim-a2a3`, `st-sim-a5` | `st-onboard-a2a3`, `st-network1-onboard-a2a3`, `st-deepseek-onboard-a2a3`, `st-torch-npu-a2a3` | `st-onboard-a5`, `st-torch-npu-a5` | ## GitHub Actions Jobs @@ -35,9 +35,9 @@ shape. The executable job bodies live in reusable workflows: `_packaging.yml`, `_profiling-flags-smoke.yml`, `_st-sim-a2a3.yml`, `_st-sim-a5.yml`, `_ut-npu-a2a3.yml`, `_ut-npu-a5.yml`, `_st-npu-a2a3.yml`, `_st-npu-a5.yml`, `_st-network1.yml`, -`_st-deepseek-a2a3.yml`, and `_st-framework-eager.yml`. The simulation, +`_st-deepseek-a2a3.yml`, and `_st-torch-npu.yml`. The simulation, ordinary onboard, and NPU unit-test bodies are split by architecture so each -job renders only its own steps. Framework eager shares `_st-framework-eager.yml`; +job renders only its own steps. Torch-NPU scene tests share `_st-torch-npu.yml`; callers supply matching `platform` and `runs_on` inputs. Shared step scaffolding that is safe to run after checkout lives in composite actions under `.github/actions/` (`apt-install`, `cache-pip`, `cache-ccache`, `setup-gcc-15`, `setup-venv`, and the three `network1-*` actions). @@ -79,7 +79,7 @@ PullRequest ├── st-sim-a5 (ubuntu-24.04) — a5_changed && st_affected ├── ut-a2a3 (a2a3 self-hosted) — Python + C++ UT, a2a3 hardware [needs ut_affected] ├── st-onboard-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected - ├── st-framework-eager-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected + ├── st-torch-npu-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected ├── st-network1-onboard-a2a3 (a2a3pod pair) — a2a3_changed && st_affected └── st-deepseek-onboard-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected @@ -87,7 +87,7 @@ Admin PR comment /run-a5 └── gate-and-resolve (ubuntu-24.04) — open PR to this repo main; pinned head ├── ut-a5 (a5 self-hosted) — Python UT and CANN examples ├── st-onboard-a5 (a5 self-hosted) — onboard ST and DFX smokes - └── st-framework-eager-a5 (a5 self-hosted) — framework eager ST + └── st-torch-npu-a5 (a5 self-hosted) — Torch-NPU ST ``` | Job | Runner | What it runs | @@ -97,10 +97,10 @@ Admin PR comment /run-a5 | `st-sim-a5` | `ubuntu-24.04` | `pytest examples tests/st --platform a5sim` | | `ut-a2a3` | a2a3 self-hosted | Hardware Python UT: `device_count` cases use resource scheduling, RuntimeBuilder integration runs before the xdist fanout, and remaining cases use one worker per allocated device. Then `ctest -L "^requires_hardware(_a2a3)?$" --resource-spec-file ...` and CANN example smokes. | | `st-onboard-a2a3` | a2a3 self-hosted | `pytest examples tests/st -m "not sdma and not sdma_fault" --platform a2a3 --exclude-level 4 --device ...`, then separate SDMA-demo and `sdma_fault` device tasks, then adaptive-parallel DFX feature smokes | -| `st-framework-eager-a2a3` | a2a3 self-hosted | `pytest examples tests/st --platform a2a3 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | +| `st-torch-npu-a2a3` | a2a3 self-hosted | `pytest examples tests/st --platform a2a3 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | | `ut-a5` | a5 self-hosted | Hardware Python UT: `device_count` cases use resource scheduling, RuntimeBuilder integration runs before the xdist fanout, and remaining cases use one worker per allocated device. Then CANN example smokes. | | `st-onboard-a5` | a5 self-hosted | Default SDMA+URMA / RDMA=OFF build and `pytest examples tests/st --platform a5 --exclude-level 4 --device ...`, including SDMA, the active URMA regressions and mixed SDMA/URMA cases, then adaptive-parallel DFX feature smokes | -| `st-framework-eager-a5` | a5 self-hosted | `pytest examples tests/st --platform a5 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | +| `st-torch-npu-a5` | a5 self-hosted | `pytest examples tests/st --platform a5 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | | `st-network1-onboard-a2a3` | a pair of `a2a3pod` machines | `pytest examples tests/st --level 4 --platform a2a3 --device ... --max-parallel 1`, one L3 daemon on the peer | | `st-deepseek-onboard-a2a3` | a2a3 self-hosted | `pytest --platform a2a3 --manual only --device ...`, both 2-device cases concurrently, in parallel with `st-onboard-a2a3` | @@ -350,22 +350,23 @@ not need `--max-parallel` manually. - **SDMA tests run in isolated tasks inside `st-onboard-a2a3`.** Within the default test environment, three selections partition the corpus (`examples tests/st`): the ordinary sweep takes `-m "not sdma and not sdma_fault"` with `--exclude-level 4`, one queued task runs `-m "sdma and not sdma_fault"` for the demos, and a separate one-device task runs `-m sdma_fault` for the AICore fault-injection case. The three are disjoint and exhaustive over both markers, and all three name the same paths, so a case cannot land in two tasks or in none. Provisioning the SDMA workspace creates 48 device-only STARS streams that live in the device fault domain, and tearing them down once any AICore task has poisoned that card blocks minutes rather than milliseconds — whether the teardown is a device reset or an explicit stream destroy ([#1425](https://github.com/hw-native-sys/simpler/issues/1425)). The cost therefore falls on whichever process still holds those streams when the fault happens, which is why the fault-injection case gets a task containing nothing else. Separate `task-submit` tasks preserve that on every onboard runner, independent of pytest ordering. Network1 tests are selected by `--level 4` in `st-network1-onboard-a2a3` and explicitly excluded from ordinary onboard ST lanes. -### Framework eager qualification (a2a3 and a5) +### Torch-NPU qualification (a2a3 and a5) -`st-framework-eager-a2a3` runs automatically on affected PRs. A5 framework -eager validation for ordinary PRs is part of `/run-a5`. Both run in the emergency +`st-torch-npu-a2a3` runs automatically on affected PRs. Torch-NPU +validation on A5 for ordinary PRs is part of `/run-a5`. Both run in the emergency lane and Daily. Automatic and emergency callers use the corresponding `a2a3_changed && st_affected` or `a5_changed && st_affected` gate; the explicit A5 command runs without a change gate. Each uses its architecture runner pool. -All callers reuse `_st-framework-eager.yml` with an explicit platform. Setup validates `a2a3|a5`, builds `build_package_`, +All callers reuse `_st-torch-npu.yml` with an explicit platform. Setup validates `a2a3|a5`, builds `build_package_`, and records the matching onboard runtime roots. The exclusive task checks actual silicon before backend import and passes the same platform to identity recording and pytest. Artifacts are named separately by platform; a green A3 job does not qualify A5. -Tests declare `@pytest.mark.test_environment("torch_npu")`. The job discovers -them across `examples tests/st` with `--test-environment torch_npu`; it does -not enumerate directories or cases. Ordinary sweeps and compile warm-up select -the implicit `default` environment, including in Daily. Framework dependencies +Eager submission and cold capture tests declare +`@pytest.mark.test_environment("torch_npu")`. The job discovers cases across +`examples tests/st` with `--test-environment torch_npu`. Ordinary onboard +sweeps and compile warm-up select the implicit `default` environment, including +in Daily. Torch-NPU dependencies live only in `.venv-framework`, separate from the Program/fork sweep's `.venv`. Environment selection is independent of `manual`. The reusable job accepts the same `manual_mode` contract as other scene-test jobs: Per-PR and emergency @@ -463,14 +464,14 @@ source/native build identities, runtime and framework module hashes, compiled bridge identity and consumer results; when artifact upload succeeds, `framework-eager--*` retains JUnit and per-case logs even on test failure. Artifact upload is best-effort and does not override the verified test result. -This qualifies the reference -consumers' same-stream and cross-stream eager ordering, caller-owned lifetimes, +The eager cases qualify the reference consumers' same-stream and cross-stream eager ordering, caller-owned lifetimes, bounded aliased INOUT assertions, ordinary callback-error recovery and per-call value semantics and bounded DEVICE-controlled persistent cache state. It does not qualify native failed-drain recovery, pending framework-callback close or early HOST-backing release. It does not establish -overlap, arbitrary strides/cross-tile aliasing, PyPTO dispatch or capture/replay. -Qualification is limited to the actual platform and environment in each receipt. +overlap, arbitrary strides/cross-tile aliasing or PyPTO dispatch. The cold +capture cases separately check replay values and graph resource lifetime. +Qualification is limited to the cases, platform and environment in each receipt. ### A5 hardware validation (`/run-a5`) @@ -482,7 +483,7 @@ and full commit SHA, including fork PRs. Non-PR comments and unverified or non-admin requests cannot schedule hardware work. Every admitted request runs `ut-a5` with CANN examples, `st-onboard-a5` with DFX -smokes, and `st-framework-eager-a5` through the existing reusable workflows. +smokes, and `st-torch-npu-a5` through the existing reusable workflows. No change detector filters an explicit request, including a documentation-only PR. A new admitted request cancels the previous same-PR job for each suite; unmatched and denied comments cannot cancel admitted jobs. Pushes do not diff --git a/examples/workers/l2/framework_eager/README.md b/examples/workers/l2/framework_eager/README.md index d800bb74be..6cab19228d 100644 --- a/examples/workers/l2/framework_eager/README.md +++ b/examples/workers/l2/framework_eager/README.md @@ -157,9 +157,9 @@ CLIs load the unique existing artifact, building only when it is absent; the original same-stream CLI still checks its incremental build cache. All use the original `build_bridge` / `_load_bridge` helpers. The `test_environment("torch_npu")` marker selects an isolated framework venv in the -dedicated `st-framework-eager-a2a3` and `st-framework-eager-a5` PR and Daily jobs. The default environment -automatically deselects these tests; no directory exclusion is needed. -Selecting the suite without its dependencies fails. See [CI qualification](../../../../docs/ci.md#framework-eager-qualification-a2a3-and-a5) for the pinned compatibility contract. Run this suite +dedicated `st-torch-npu-a2a3` and `st-torch-npu-a5` jobs, shared by eager and +cold capture cases. Ordinary onboard sweeps select the default environment. +Selecting the suite without its dependencies fails. See [CI qualification](../../../../docs/ci.md#torch-npu-qualification-a2a3-and-a5) for the pinned compatibility contract. Run this suite serially inside one exclusive `task-submit` allocation of one device, as below; resource-parallel dispatch and xdist are not qualified by this example: diff --git a/src/a2a3/platform/onboard/host/aicpu_affinity_select.cpp b/src/a2a3/platform/onboard/host/aicpu_affinity_select.cpp index 235df1017e..8ba882ede8 100644 --- a/src/a2a3/platform/onboard/host/aicpu_affinity_select.cpp +++ b/src/a2a3/platform/onboard/host/aicpu_affinity_select.cpp @@ -15,7 +15,7 @@ #include "common/unified_log.h" -namespace pto::a2a3 { +namespace simpler::a2a3 { bool resolve_aicpu_cpu_id_base(int64_t phy_die_id, int32_t &out_cpu_id_base) { out_cpu_id_base = 0; @@ -87,4 +87,4 @@ bool compute_allowed_cpus( return true; } -} // namespace pto::a2a3 +} // namespace simpler::a2a3 diff --git a/src/a2a3/platform/onboard/host/aicpu_topology_probe.cpp b/src/a2a3/platform/onboard/host/aicpu_topology_probe.cpp index 8f08d21e1c..9097a1229e 100644 --- a/src/a2a3/platform/onboard/host/aicpu_topology_probe.cpp +++ b/src/a2a3/platform/onboard/host/aicpu_topology_probe.cpp @@ -19,7 +19,7 @@ #include "common/unified_log.h" #include "common/acl_hal_device.h" -namespace pto::a2a3 { +namespace simpler::a2a3 { namespace { @@ -130,4 +130,4 @@ bool probe_aicpu_topology(uint32_t device_id, std::vector &out_ return true; } -} // namespace pto::a2a3 +} // namespace simpler::a2a3 diff --git a/src/a2a3/platform/onboard/host/aicpu_topology_probe.h b/src/a2a3/platform/onboard/host/aicpu_topology_probe.h index 89143eea18..6436efa507 100644 --- a/src/a2a3/platform/onboard/host/aicpu_topology_probe.h +++ b/src/a2a3/platform/onboard/host/aicpu_topology_probe.h @@ -14,7 +14,7 @@ #include #include -namespace pto::a2a3 { +namespace simpler::a2a3 { // Two translation units implement this header. aicpu_topology_probe.cpp owns // probe_aicpu_topology and includes the CANN driver header for it; @@ -49,4 +49,4 @@ bool compute_allowed_cpus( const std::vector &user_cpus, int32_t active_count, std::vector &out_allowed_cpus ); -} // namespace pto::a2a3 +} // namespace simpler::a2a3 diff --git a/src/a2a3/platform/onboard/host/context_preparation.cpp b/src/a2a3/platform/onboard/host/context_preparation.cpp index 95e1afc032..98b839122a 100644 --- a/src/a2a3/platform/onboard/host/context_preparation.cpp +++ b/src/a2a3/platform/onboard/host/context_preparation.cpp @@ -16,7 +16,7 @@ #include "runtime/rt.h" -namespace pto::a2a3 { +namespace simpler::a2a3 { int ensure_ctrl_table(MemoryAllocator &allocator, int device_id, uint64_t &table, bool &committed) { if (committed) return 0; const int rc = @@ -35,4 +35,4 @@ int ensure_c2c_ctrl_address(uint64_t &address, bool &valid) { valid = true; return 0; } -} // namespace pto::a2a3 +} // namespace simpler::a2a3 diff --git a/src/a2a3/platform/onboard/host/context_preparation.h b/src/a2a3/platform/onboard/host/context_preparation.h index acc64f6f7a..2e8f2e03dd 100644 --- a/src/a2a3/platform/onboard/host/context_preparation.h +++ b/src/a2a3/platform/onboard/host/context_preparation.h @@ -15,8 +15,8 @@ class MemoryAllocator; -namespace pto::a2a3 { +namespace simpler::a2a3 { int ensure_ctrl_table(MemoryAllocator &allocator, int device_id, uint64_t &table, bool &committed); // A successful zero address is still a completed query. The caller owns the snapshot. int ensure_c2c_ctrl_address(uint64_t &address, bool &valid); -} // namespace pto::a2a3 +} // namespace simpler::a2a3 diff --git a/src/a2a3/platform/onboard/host/device_runner.cpp b/src/a2a3/platform/onboard/host/device_runner.cpp index bd6e24da27..d67df3058f 100644 --- a/src/a2a3/platform/onboard/host/device_runner.cpp +++ b/src/a2a3/platform/onboard/host/device_runner.cpp @@ -197,8 +197,9 @@ int DeviceRunner::fill_persistent_arch_fields(KernelArgs *args, uint64_t device_ int DeviceRunner::ensure_aicpu_topology() { if (!aicpu_topology_.empty()) return 0; - std::vector topology; - if (!pto::a2a3::probe_aicpu_topology(static_cast(device_id_), topology)) return PTO_RUNTIME_ERR_INTERNAL; + std::vector topology; + if (!simpler::a2a3::probe_aicpu_topology(static_cast(device_id_), topology)) + return PTO_RUNTIME_ERR_INTERNAL; aicpu_topology_ = std::move(topology); return 0; } @@ -206,7 +207,7 @@ int DeviceRunner::ensure_aicpu_topology() { int DeviceRunner::prepare_kernel_arch_context(rtStream_t /*control_stream*/) { int rc = ensure_aicore_reg_table(AicoreRegKind::Ctrl); if (rc != 0) return rc; - rc = pto::a2a3::ensure_c2c_ctrl_address(c2c_ctrl_address_, c2c_ctrl_address_valid_); + rc = simpler::a2a3::ensure_c2c_ctrl_address(c2c_ctrl_address_, c2c_ctrl_address_valid_); if (rc != 0) return rc; return ensure_aicpu_topology(); } @@ -486,7 +487,7 @@ int DeviceRunner::prepare_execution( runtime.get_aicpu_thread_num(), static_cast(user_cpus.size()), PLATFORM_DEFAULT_AICPU_THREAD_NUM ); if (resolved_aicpu < 0) return PTO_RUNTIME_ERR_INTERNAL; - if (!pto::a2a3::compute_allowed_cpus(user_cpus, resolved_aicpu, allowed)) { + if (!simpler::a2a3::compute_allowed_cpus(user_cpus, resolved_aicpu, allowed)) { LOG_ERROR( "A2A3 AICPU topology has %zu user cpus, cannot fit %d active threads", user_cpus.size(), resolved_aicpu ); @@ -738,7 +739,7 @@ int DeviceRunner::ensure_run_streams() { // mid-worker is not something a per-run PMU re-query could have made safe. int DeviceRunner::ensure_aicore_reg_table(AicoreRegKind kind) { if (kind == AicoreRegKind::Ctrl) - return pto::a2a3::ensure_ctrl_table( + return simpler::a2a3::ensure_ctrl_table( mem_alloc_, device_id_, aicore_ctrl_reg_table_dev_, aicore_ctrl_reg_table_committed_ ); const bool is_pmu = kind == AicoreRegKind::Pmu; diff --git a/src/a2a3/platform/onboard/host/device_runner.h b/src/a2a3/platform/onboard/host/device_runner.h index afd4e659e9..73305685e4 100644 --- a/src/a2a3/platform/onboard/host/device_runner.h +++ b/src/a2a3/platform/onboard/host/device_runner.h @@ -327,7 +327,7 @@ class DeviceRunner : public DeviceRunnerBase { int ensure_aicpu_topology(); uint64_t c2c_ctrl_address_{0}; bool c2c_ctrl_address_valid_{false}; - std::vector aicpu_topology_; + std::vector aicpu_topology_; // Release the resources this run owns, in runtime-argument, register-buffer, // then stream order. Collectors are not among them: their device resources diff --git a/src/a5/platform/onboard/host/aicpu_affinity_select.cpp b/src/a5/platform/onboard/host/aicpu_affinity_select.cpp index f7c7c11435..61a150de23 100644 --- a/src/a5/platform/onboard/host/aicpu_affinity_select.cpp +++ b/src/a5/platform/onboard/host/aicpu_affinity_select.cpp @@ -28,7 +28,7 @@ #include "common/platform_config.h" #include "common/unified_log.h" -namespace pto::a5 { +namespace simpler::a5 { using detail::CpuTopologyData; using detail::CpuTopologyEntry; @@ -1125,4 +1125,4 @@ std::string format_aicpu_topology_json( return out.str(); } -} // namespace pto::a5 +} // namespace simpler::a5 diff --git a/src/a5/platform/onboard/host/aicpu_topology_probe.cpp b/src/a5/platform/onboard/host/aicpu_topology_probe.cpp index 80f922eee7..1853b8f9ac 100644 --- a/src/a5/platform/onboard/host/aicpu_topology_probe.cpp +++ b/src/a5/platform/onboard/host/aicpu_topology_probe.cpp @@ -18,7 +18,7 @@ #include "common/acl_hal_device.h" #include "common/unified_log.h" -namespace pto::a5 { +namespace simpler::a5 { namespace { using pto::driver::CpuTopology; @@ -107,4 +107,4 @@ bool probe_aicpu_topology( return detail::build_aicpu_topology(device_occupancy, soc_name, available, topo, out_topology); } -} // namespace pto::a5 +} // namespace simpler::a5 diff --git a/src/a5/platform/onboard/host/aicpu_topology_probe.h b/src/a5/platform/onboard/host/aicpu_topology_probe.h index b9c77c1b21..206b96134e 100644 --- a/src/a5/platform/onboard/host/aicpu_topology_probe.h +++ b/src/a5/platform/onboard/host/aicpu_topology_probe.h @@ -16,7 +16,7 @@ #include #include -namespace pto::a5 { +namespace simpler::a5 { // aicpu_topology_probe.cpp owns driver queries. aicpu_affinity_select.cpp // owns topology assembly, fallback and CPU selection without CANN dependencies. @@ -210,4 +210,4 @@ bool build_aicpu_topology( } // namespace detail -} // namespace pto::a5 +} // namespace simpler::a5 diff --git a/src/a5/platform/onboard/host/context_preparation.cpp b/src/a5/platform/onboard/host/context_preparation.cpp index 3ca4d183e5..d4d7e3c95a 100644 --- a/src/a5/platform/onboard/host/context_preparation.cpp +++ b/src/a5/platform/onboard/host/context_preparation.cpp @@ -20,7 +20,7 @@ #include "common/platform_config.h" #include "runtime_c_api.h" -namespace pto::a5 { +namespace simpler::a5 { int ensure_ctrl_table(MemoryAllocator &allocator, int device_id, uint64_t &table, bool &committed) { if (committed) return 0; const int rc = init_aicore_register_addresses(&table, static_cast(device_id), allocator); @@ -74,4 +74,4 @@ int query_device_aicpu_occupancy( out.os_sched_valid = result.os_sched_rc == 0; return 0; } -} // namespace pto::a5 +} // namespace simpler::a5 diff --git a/src/a5/platform/onboard/host/context_preparation.h b/src/a5/platform/onboard/host/context_preparation.h index 0f286864a9..60bca7de8b 100644 --- a/src/a5/platform/onboard/host/context_preparation.h +++ b/src/a5/platform/onboard/host/context_preparation.h @@ -19,7 +19,7 @@ namespace host { class LoadAicpuOp; } -namespace pto::a5 { +namespace simpler::a5 { int ensure_ctrl_table(MemoryAllocator &allocator, int device_id, uint64_t &table, bool &committed); // Scratch and pending-write state belong to the calling DeviceRunner. int query_device_aicpu_occupancy( @@ -27,4 +27,4 @@ int query_device_aicpu_occupancy( AicpuDeviceOccupancy &out ); int release_aicpu_query_result(MemoryAllocator &allocator, rtStream_t stream, void *&scratch, bool &pending); -} // namespace pto::a5 +} // namespace simpler::a5 diff --git a/src/a5/platform/onboard/host/device_runner.cpp b/src/a5/platform/onboard/host/device_runner.cpp index 441f4d90ec..86219bf1da 100644 --- a/src/a5/platform/onboard/host/device_runner.cpp +++ b/src/a5/platform/onboard/host/device_runner.cpp @@ -201,7 +201,7 @@ int DeviceRunner::destroy_comm_stream(void *stream) { int DeviceRunner::prepare_kernel_arch_context(rtStream_t control_stream) { const int rc = ensure_aicore_reg_table(); if (rc != 0) return rc; - pto::a5::AicpuTopology topology; + simpler::a5::AicpuTopology topology; return query_aicpu_topology(topology, control_stream); } @@ -212,21 +212,21 @@ int DeviceRunner::release_arch_context_resources(bool abandon_device_resources) aicpu_topology_query_stream_ = nullptr; return 0; } - const int rc = pto::a5::release_aicpu_query_result( + const int rc = simpler::a5::release_aicpu_query_result( mem_alloc_, aicpu_topology_query_stream_, aicpu_topology_query_result_, aicpu_topology_query_pending_ ); if (rc == 0) aicpu_topology_query_stream_ = nullptr; return rc; } -int DeviceRunner::query_aicpu_device_occupancy(pto::a5::AicpuDeviceOccupancy &out, rtStream_t control_stream) { +int DeviceRunner::query_aicpu_device_occupancy(simpler::a5::AicpuDeviceOccupancy &out, rtStream_t control_stream) { if (aicpu_device_occupancy_cached_) { out = aicpu_device_occupancy_; return 0; } if (!aicpu_topology_query_pending_) aicpu_topology_query_stream_ = control_stream; - pto::a5::AicpuDeviceOccupancy occupancy; - const int rc = pto::a5::query_device_aicpu_occupancy( + simpler::a5::AicpuDeviceOccupancy occupancy; + const int rc = simpler::a5::query_device_aicpu_occupancy( mem_alloc_, load_aicpu_op_, control_stream, aicpu_topology_query_result_, aicpu_topology_query_pending_, occupancy ); @@ -243,18 +243,18 @@ int DeviceRunner::query_aicpu_device_occupancy(pto::a5::AicpuDeviceOccupancy &ou return 0; } -int DeviceRunner::query_aicpu_topology(pto::a5::AicpuTopology &out, rtStream_t control_stream) { +int DeviceRunner::query_aicpu_topology(simpler::a5::AicpuTopology &out, rtStream_t control_stream) { if (aicpu_topology_cached_) { out = aicpu_topology_; return 0; } - pto::a5::AicpuDeviceOccupancy occupancy; + simpler::a5::AicpuDeviceOccupancy occupancy; int rc = query_aicpu_device_occupancy(occupancy, control_stream); if (rc != 0) return rc; - pto::a5::AicpuTopology topology; - if (!pto::a5::probe_aicpu_topology(static_cast(device_id_), occupancy, topology)) + simpler::a5::AicpuTopology topology; + if (!simpler::a5::probe_aicpu_topology(static_cast(device_id_), occupancy, topology)) return PTO_RUNTIME_ERR_INTERNAL; aicpu_topology_ = std::move(topology); @@ -429,7 +429,7 @@ int DeviceRunner::prepare_execution( // active count to the available pool, but execution keeps at least one of // each role. { - pto::a5::AicpuTopology topology; + simpler::a5::AicpuTopology topology; runtime.set_aicpu_allowed_cpu_count(0); const rtStream_t control_stream = execution_mode_latch().is_kernel() ? @@ -439,13 +439,13 @@ int DeviceRunner::prepare_execution( LOG_ERROR("AICPU topology probe failed; affinity gate will not launch"); return PTO_RUNTIME_ERR_INTERNAL; } - pto::a5::AicpuLaunchPlan launch_plan; + simpler::a5::AicpuLaunchPlan launch_plan; std::string plan_error; - if (!pto::a5::build_aicpu_launch_plan(topology, requested_aicpu_num, launch_plan, plan_error)) { + if (!simpler::a5::build_aicpu_launch_plan(topology, requested_aicpu_num, launch_plan, plan_error)) { LOG_ERROR( "cannot build AICPU launch plan: soc=%s scenario=%s occupy=0x%llx reason=%s", topology.soc_name.empty() ? "(unknown)" : topology.soc_name.c_str(), - pto::a5::aicpu_scenario_name(topology.scenario_type), + simpler::a5::aicpu_scenario_name(topology.scenario_type), static_cast(topology.device_occupancy.occupy), plan_error.c_str() ); return PTO_RUNTIME_ERR_INTERNAL; @@ -474,11 +474,11 @@ int DeviceRunner::prepare_execution( LOG_WARN( "AICPU CPU_TOPO unavailable; using %s: soc=%s occupy=0x%llx " "stable_reachable=%d requested=%d effective=%d affinity=[%s]%s", - pto::a5::aicpu_topology_source_name(topology.source), + simpler::a5::aicpu_topology_source_name(topology.source), topology.soc_name.empty() ? "(unknown)" : topology.soc_name.c_str(), static_cast(topology.device_occupancy.occupy), launch_plan.stable_reachable_count, requested_aicpu_num, active_aicpu_num, dump.c_str(), - topology.source == pto::a5::AicpuTopologySource::kOccupyFallback ? + topology.source == simpler::a5::AicpuTopologySource::kOccupyFallback ? "; physical/SMT/cluster/die placement is unknown" : "" ); @@ -488,7 +488,7 @@ int DeviceRunner::prepare_execution( "AICPU stable reachable CPUs below active capacity: soc=%s scenario=%s occupy=0x%llx " "stable_reachable=%d capacity=%d requested=%d effective=%d affinity=[%s]", topology.soc_name.empty() ? "(unknown)" : topology.soc_name.c_str(), - pto::a5::aicpu_scenario_name(topology.scenario_type), + simpler::a5::aicpu_scenario_name(topology.scenario_type), static_cast(topology.device_occupancy.occupy), launch_plan.stable_reachable_count, PLATFORM_DEFAULT_AICPU_THREAD_NUM, requested_aicpu_num, active_aicpu_num, dump.c_str() @@ -496,7 +496,7 @@ int DeviceRunner::prepare_execution( } LOG_INFO( "AICPU ALLOWED_CPUS = [%s] (scenario=%s active=%d launch=%d user_cpus=%zu)", dump.c_str(), - pto::a5::aicpu_scenario_name(topology.scenario_type), active_aicpu_num, launch_plan.launch_count, + simpler::a5::aicpu_scenario_name(topology.scenario_type), active_aicpu_num, launch_plan.launch_count, topology.os_schedulable_cpus.size() ); } @@ -1445,7 +1445,7 @@ int DeviceRunner::finalize_collectors(bool abandon_device_resources) { // halves the per-core halResMap loop and the live driver-side mappings a worker // holds. int DeviceRunner::ensure_aicore_reg_table() { - return pto::a5::ensure_ctrl_table( + return simpler::a5::ensure_ctrl_table( mem_alloc_, device_id_, aicore_ctrl_reg_table_dev_, aicore_ctrl_reg_table_committed_ ); } diff --git a/src/a5/platform/onboard/host/device_runner.h b/src/a5/platform/onboard/host/device_runner.h index dfc88aaad9..a53cd96b11 100644 --- a/src/a5/platform/onboard/host/device_runner.h +++ b/src/a5/platform/onboard/host/device_runner.h @@ -365,8 +365,8 @@ class DeviceRunner : public DeviceRunnerBase { // // dep_gen enablement is a5-specific (a2a3 carries its own copy). - int query_aicpu_device_occupancy(pto::a5::AicpuDeviceOccupancy &out, rtStream_t control_stream); - int query_aicpu_topology(pto::a5::AicpuTopology &out, rtStream_t control_stream); + int query_aicpu_device_occupancy(simpler::a5::AicpuDeviceOccupancy &out, rtStream_t control_stream); + int query_aicpu_topology(simpler::a5::AicpuTopology &out, rtStream_t control_stream); void *aicpu_topology_query_result_{nullptr}; bool aicpu_topology_query_pending_{false}; rtStream_t aicpu_topology_query_stream_{nullptr}; @@ -376,9 +376,9 @@ class DeviceRunner : public DeviceRunnerBase { // allowed CPU selection still runs per call because the requested active // count may change. Recovery, reset, and finalize clear both values. bool aicpu_device_occupancy_cached_{false}; - pto::a5::AicpuDeviceOccupancy aicpu_device_occupancy_{}; + simpler::a5::AicpuDeviceOccupancy aicpu_device_occupancy_{}; bool aicpu_topology_cached_{false}; - pto::a5::AicpuTopology aicpu_topology_{}; + simpler::a5::AicpuTopology aicpu_topology_{}; int init_pmu(int num_cores, int num_threads, int device_id, KernelArgsHelper &kernel_args); int init_scope_stats(int num_threads, int device_id, KernelArgsHelper &kernel_args); diff --git a/src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime.h b/src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime.h index 7576b761fb..b2461cccca 100644 --- a/src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime.h +++ b/src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime.h @@ -184,7 +184,7 @@ struct alignas(64) DeviceRuntimeLaunchDesc { // Filter-style affinity gate input (a5 onboard). Host fills before // launch from device-side OCCUPY + DSMI CPU_TOPO via - // pto::a5::compute_allowed_cpus. The on-device gate keeps threads whose + // simpler::a5::compute_allowed_cpus. The on-device gate keeps threads whose // sched_getcpu() lands on one of these cpu_ids; exec_idx = position in // this array drives sched/orch role assignment. Indices 0..count-2 are // scheduler slots, index count-1 is the orchestrator slot. Sized to diff --git a/tests/ut/cpp/a2a3/platform/test_aicpu_affinity_select.cpp b/tests/ut/cpp/a2a3/platform/test_aicpu_affinity_select.cpp index a14cb4d903..7f30e50acb 100644 --- a/tests/ut/cpp/a2a3/platform/test_aicpu_affinity_select.cpp +++ b/tests/ut/cpp/a2a3/platform/test_aicpu_affinity_select.cpp @@ -43,9 +43,9 @@ void unified_log_info(const char *, const char *, ...) {} void unified_log_debug(const char *, const char *, ...) {} } -using pto::a2a3::AicpuLogicalCpu; -using pto::a2a3::compute_allowed_cpus; -using pto::a2a3::resolve_aicpu_cpu_id_base; +using simpler::a2a3::AicpuLogicalCpu; +using simpler::a2a3::compute_allowed_cpus; +using simpler::a2a3::resolve_aicpu_cpu_id_base; namespace { diff --git a/tests/ut/cpp/a5/platform/test_aicpu_topology_fallback.cpp b/tests/ut/cpp/a5/platform/test_aicpu_topology_fallback.cpp index 06f9eadb4b..97082fcb4a 100644 --- a/tests/ut/cpp/a5/platform/test_aicpu_topology_fallback.cpp +++ b/tests/ut/cpp/a5/platform/test_aicpu_topology_fallback.cpp @@ -28,21 +28,21 @@ void unified_log_debug(const char *, const char *, ...) {} namespace { -using pto::a5::AicpuLaunchPlan; -using pto::a5::AicpuLogicalCpu; -using pto::a5::AicpuScenarioType; -using pto::a5::AicpuSelectionPolicy; -using pto::a5::AicpuTopology; -using pto::a5::AicpuTopologySource; -using pto::a5::build_aicpu_launch_plan; -using pto::a5::classify_aicpu_scenario; -using pto::a5::compute_allowed_cpus; -using pto::a5::compute_scenario_allowed_cpus; -using pto::a5::compute_unknown_allowed_cpus; -using pto::a5::derive_topology_from_occupy; -using pto::a5::enumerate_cpus_from_occupy; -using pto::a5::format_aicpu_topology_json; -using pto::a5::load_cpu_topo_from_json; +using simpler::a5::AicpuLaunchPlan; +using simpler::a5::AicpuLogicalCpu; +using simpler::a5::AicpuScenarioType; +using simpler::a5::AicpuSelectionPolicy; +using simpler::a5::AicpuTopology; +using simpler::a5::AicpuTopologySource; +using simpler::a5::build_aicpu_launch_plan; +using simpler::a5::classify_aicpu_scenario; +using simpler::a5::compute_allowed_cpus; +using simpler::a5::compute_scenario_allowed_cpus; +using simpler::a5::compute_unknown_allowed_cpus; +using simpler::a5::derive_topology_from_occupy; +using simpler::a5::enumerate_cpus_from_occupy; +using simpler::a5::format_aicpu_topology_json; +using simpler::a5::load_cpu_topo_from_json; std::vector make_physical_range(int32_t first_phy, int32_t last_phy) { std::vector cpus; @@ -66,7 +66,7 @@ void set_device_occupy(AicpuTopology &topology, uint64_t occupy) { } TEST(A5AicpuTopologyFallback, BuildsDriverTopologyWithOccupancyFiltering) { - pto::a5::detail::CpuTopologyData raw{}; + simpler::a5::detail::CpuTopologyData raw{}; raw.total_nums = 8; for (uint32_t i = 0; i < raw.total_nums; ++i) { const uint8_t id = static_cast(raw.total_nums - 1 - i); @@ -74,11 +74,11 @@ TEST(A5AicpuTopologyFallback, BuildsDriverTopologyWithOccupancyFiltering) { raw.cpus[i].phy_cpu_id = id / 2; raw.cpus[i].hyperthread_id = id % 2; } - pto::a5::AicpuDeviceOccupancy occupancy{}; + simpler::a5::AicpuDeviceOccupancy occupancy{}; occupancy.occupy_valid = true; occupancy.occupy = (1ULL << 3) | (1ULL << 4) | (1ULL << 5); AicpuTopology topology; - ASSERT_TRUE(pto::a5::detail::build_aicpu_topology(occupancy, "test-soc", true, raw, topology)); + ASSERT_TRUE(simpler::a5::detail::build_aicpu_topology(occupancy, "test-soc", true, raw, topology)); EXPECT_EQ(topology.source, AicpuTopologySource::kDriver); EXPECT_EQ(topology.soc_name, "test-soc"); EXPECT_EQ(topology.logical_cpu_count, 8U); @@ -91,12 +91,12 @@ TEST(A5AicpuTopologyFallback, BuildsDriverTopologyWithOccupancyFiltering) { } TEST(A5AicpuTopologyFallback, BuildsOccupancyFallbackWithoutDriverMetadata) { - pto::a5::detail::CpuTopologyData raw{}; - pto::a5::AicpuDeviceOccupancy occupancy{}; + simpler::a5::detail::CpuTopologyData raw{}; + simpler::a5::AicpuDeviceOccupancy occupancy{}; occupancy.occupy_valid = true; occupancy.occupy = (1ULL << 2) | (1ULL << 63); AicpuTopology topology; - ASSERT_TRUE(pto::a5::detail::build_aicpu_topology(occupancy, nullptr, false, raw, topology)); + ASSERT_TRUE(simpler::a5::detail::build_aicpu_topology(occupancy, nullptr, false, raw, topology)); EXPECT_EQ(topology.source, AicpuTopologySource::kOccupyFallback); EXPECT_EQ(topology.logical_cpu_count, 2U); EXPECT_EQ(topology.scenario_type, AicpuScenarioType::kUnknown); @@ -109,30 +109,30 @@ TEST(A5AicpuTopologyFallback, BuildsOccupancyFallbackWithoutDriverMetadata) { } TEST(A5AicpuTopologyFallback, RejectsDuplicateDriverCpuIdsAndClearsTopology) { - pto::a5::detail::CpuTopologyData raw{}; + simpler::a5::detail::CpuTopologyData raw{}; raw.total_nums = 2; raw.cpus[0].cpu_id = 2; raw.cpus[0].phy_cpu_id = 1; raw.cpus[1] = raw.cpus[0]; - pto::a5::AicpuDeviceOccupancy occupancy{}; + simpler::a5::AicpuDeviceOccupancy occupancy{}; occupancy.occupy_valid = true; occupancy.occupy = 1ULL << 2; AicpuTopology topology; - EXPECT_FALSE(pto::a5::detail::build_aicpu_topology(occupancy, "test-soc", true, raw, topology)); + EXPECT_FALSE(simpler::a5::detail::build_aicpu_topology(occupancy, "test-soc", true, raw, topology)); EXPECT_TRUE(topology.soc_name.empty()); EXPECT_TRUE(topology.os_schedulable_cpus.empty()); EXPECT_EQ(topology.logical_cpu_count, 0U); } TEST(A5AicpuTopologyFallback, RejectsDriverCountsOutsideBufferCapacity) { - pto::a5::detail::CpuTopologyData raw{}; - pto::a5::AicpuDeviceOccupancy occupancy{}; + simpler::a5::detail::CpuTopologyData raw{}; + simpler::a5::AicpuDeviceOccupancy occupancy{}; occupancy.occupy_valid = true; occupancy.occupy = 1ULL << 2; AicpuTopology topology; - EXPECT_FALSE(pto::a5::detail::build_aicpu_topology(occupancy, nullptr, true, raw, topology)); - raw.total_nums = pto::a5::detail::kCpuOccupancyBits + 1; - EXPECT_FALSE(pto::a5::detail::build_aicpu_topology(occupancy, nullptr, true, raw, topology)); + EXPECT_FALSE(simpler::a5::detail::build_aicpu_topology(occupancy, nullptr, true, raw, topology)); + raw.total_nums = simpler::a5::detail::kCpuOccupancyBits + 1; + EXPECT_FALSE(simpler::a5::detail::build_aicpu_topology(occupancy, nullptr, true, raw, topology)); } TEST(A5AicpuTopologyFallback, EnumeratesBoundaryCpuIdsAndRejectsEmptyMask) { diff --git a/tests/ut/cpp/common/platform/test_native_admission.cpp b/tests/ut/cpp/common/platform/test_native_admission.cpp index 2fb98c8425..9164b128e9 100644 --- a/tests/ut/cpp/common/platform/test_native_admission.cpp +++ b/tests/ut/cpp/common/platform/test_native_admission.cpp @@ -5005,21 +5005,21 @@ class ContextControlRunner : public ColdKernelRunner { #ifdef CONTEXT_ARCH_A5 void *scratch{nullptr}; bool pending{false}; - pto::a5::AicpuDeviceOccupancy occupancy{}; - pto::a5::AicpuTopology topology{}; + simpler::a5::AicpuDeviceOccupancy occupancy{}; + simpler::a5::AicpuTopology topology{}; bool selected(int threads, std::vector &allowed) { - pto::a5::AicpuLaunchPlan plan; + simpler::a5::AicpuLaunchPlan plan; std::string error; - if (!pto::a5::build_aicpu_launch_plan(topology, threads, plan, error)) return false; + if (!simpler::a5::build_aicpu_launch_plan(topology, threads, plan, error)) return false; allowed = plan.allowed_cpus; return true; } #else uint64_t c2c_address{0}; bool c2c_valid{false}; - std::vector topology; + std::vector topology; bool selected(int threads, std::vector &allowed) { - return pto::a2a3::compute_allowed_cpus(topology, threads, allowed); + return simpler::a2a3::compute_allowed_cpus(topology, threads, allowed); } #endif protected: @@ -5027,24 +5027,24 @@ class ContextControlRunner : public ColdKernelRunner { ++prepare_arch_calls; observed_control_stream = stream; #ifdef CONTEXT_ARCH_A5 - int rc = pto::a5::ensure_ctrl_table( + int rc = simpler::a5::ensure_ctrl_table( mem_alloc_, device_id_, aicore_ctrl_reg_table_dev_, aicore_ctrl_reg_table_committed_ ); if (rc != 0 || occupancy.occupy_valid) return rc; - rc = pto::a5::query_device_aicpu_occupancy(mem_alloc_, load_aicpu_op_, stream, scratch, pending, occupancy); + rc = simpler::a5::query_device_aicpu_occupancy(mem_alloc_, load_aicpu_op_, stream, scratch, pending, occupancy); if (rc != 0) return rc; - pto::a5::detail::CpuTopologyData driver{}; - return pto::a5::detail::build_aicpu_topology(occupancy, "CPU-control-fixture", false, driver, topology) ? + simpler::a5::detail::CpuTopologyData driver{}; + return simpler::a5::detail::build_aicpu_topology(occupancy, "CPU-control-fixture", false, driver, topology) ? 0 : PTO_RUNTIME_ERR_INTERNAL; #else - int rc = pto::a2a3::ensure_ctrl_table( + int rc = simpler::a2a3::ensure_ctrl_table( mem_alloc_, device_id_, aicore_ctrl_reg_table_dev_, aicore_ctrl_reg_table_committed_ ); if (rc != 0) return rc; - rc = pto::a2a3::ensure_c2c_ctrl_address(c2c_address, c2c_valid); + rc = simpler::a2a3::ensure_c2c_ctrl_address(c2c_address, c2c_valid); if (rc != 0) return rc; - if (topology.empty() && !pto::a2a3::probe_aicpu_topology(static_cast(device_id_), topology)) + if (topology.empty() && !simpler::a2a3::probe_aicpu_topology(static_cast(device_id_), topology)) return PTO_RUNTIME_ERR_INTERNAL; return 0; #endif @@ -5056,7 +5056,7 @@ class ContextControlRunner : public ColdKernelRunner { pending = false; return 0; } - return pto::a5::release_aicpu_query_result(mem_alloc_, observed_control_stream, scratch, pending); + return simpler::a5::release_aicpu_query_result(mem_alloc_, observed_control_stream, scratch, pending); #else (void)abandon; return 0; diff --git a/tests/ut/py/test_a5_comment_ci.py b/tests/ut/py/test_a5_comment_ci.py index 26ac36e379..d61941ea09 100644 --- a/tests/ut/py/test_a5_comment_ci.py +++ b/tests/ut/py/test_a5_comment_ci.py @@ -21,7 +21,7 @@ _SUITES = { "ut-a5": "_ut-npu-a5.yml", "st-onboard-a5": "_st-npu-a5.yml", - "st-framework-eager-a5": "_st-framework-eager.yml", + "st-torch-npu-a5": "_st-torch-npu.yml", } _SHA = "1234567890abcdef" * 2 + "12345678" _NODE = r""" @@ -106,7 +106,7 @@ def test_only_three_hardware_suites_move_from_automatic_ci(): assert all(name in _workflow("ci-self")["jobs"] for name in _SUITES) daily = _workflow("daily")["jobs"] assert "ut-a5" not in daily - assert "st-onboard-a5" in daily and "st-framework-eager-a5" in daily + assert "st-onboard-a5" in daily and "st-torch-npu-a5" in daily def test_authorized_topology_pins_all_suites_and_keeps_reporting_permission_separate(): @@ -148,7 +148,7 @@ def test_authorized_topology_pins_all_suites_and_keeps_reporting_permission_sepa assert step["with"]["ref"] == "${{ inputs.ref || github.ref }}" assert jobs["ut-a5"]["with"]["include_cann_examples"] == "true" assert jobs["st-onboard-a5"]["with"]["include_dfx_smokes"] == "true" - assert jobs["st-framework-eager-a5"]["with"]["platform"] == "a5" + assert jobs["st-torch-npu-a5"]["with"]["platform"] == "a5" report = jobs["report"] assert set(report["needs"]) == {"gate-and-resolve", *_SUITES} assert report["if"].startswith("always() &&") diff --git a/tests/ut/py/test_aicpu_topology_driver_headers.py b/tests/ut/py/test_aicpu_topology_driver_headers.py index e0e81e3535..3fb64c8678 100644 --- a/tests/ut/py/test_aicpu_topology_driver_headers.py +++ b/tests/ut/py/test_aicpu_topology_driver_headers.py @@ -193,11 +193,11 @@ def test_oversized_driver_topology_falls_back(tmp_path: Path) -> None: " static_cast(buffer)->total_nums = 65;\n" " return 0;\n}\n" "int main() {\n" - " pto::a5::AicpuDeviceOccupancy occupancy{};\n" + " simpler::a5::AicpuDeviceOccupancy occupancy{};\n" " occupancy.occupy = 2; occupancy.occupy_valid = true;\n" - " pto::a5::AicpuTopology topology;\n" - " if (!pto::a5::probe_aicpu_topology(0, occupancy, topology)) return 1;\n" - " return topology.source != pto::a5::AicpuTopologySource::kOccupyFallback ||\n" + " simpler::a5::AicpuTopology topology;\n" + " if (!simpler::a5::probe_aicpu_topology(0, occupancy, topology)) return 1;\n" + " return topology.source != simpler::a5::AicpuTopologySource::kOccupyFallback ||\n" " topology.os_schedulable_cpus.size() != 1 ||\n" " topology.os_schedulable_cpus[0].cpu_id != 1;\n}\n" ) diff --git a/tests/ut/py/test_framework_eager_ci_platform.py b/tests/ut/py/test_framework_eager_ci_platform.py index 1594c37e82..0020a05408 100644 --- a/tests/ut/py/test_framework_eager_ci_platform.py +++ b/tests/ut/py/test_framework_eager_ci_platform.py @@ -21,7 +21,7 @@ _ROOT = Path(__file__).resolve().parents[3] _ACTION = _ROOT / ".github/actions/setup-framework-eager" -_WORKFLOW = _ROOT / ".github/workflows/_st-framework-eager.yml" +_WORKFLOW = _ROOT / ".github/workflows/_st-torch-npu.yml" def _yaml(path): @@ -292,15 +292,15 @@ def test_each_caller_routes_both_platforms_to_the_same_reusable_workflow(caller) jobs = _yaml(_ROOT / f".github/workflows/{caller}.yml")["jobs"] for platform_name in ("a2a3", "a5"): if caller == "ci" and platform_name == "a5": - assert "st-framework-eager-a5" not in jobs - job = _yaml(_ROOT / ".github/workflows/ci-a5-comment.yml")["jobs"]["st-framework-eager-a5"] - assert job["uses"] == "./.github/workflows/_st-framework-eager.yml" + assert "st-torch-npu-a5" not in jobs + job = _yaml(_ROOT / ".github/workflows/ci-a5-comment.yml")["jobs"]["st-torch-npu-a5"] + assert job["uses"] == "./.github/workflows/_st-torch-npu.yml" assert job["with"]["platform"] == "a5" assert json.loads(job["with"]["runs_on"]) == ["self-hosted", "a5"] assert job["needs"] == ["gate-and-resolve"] continue - job = jobs[f"st-framework-eager-{platform_name}"] - assert job["uses"] == "./.github/workflows/_st-framework-eager.yml" + job = jobs[f"st-torch-npu-{platform_name}"] + assert job["uses"] == "./.github/workflows/_st-torch-npu.yml" assert job["with"]["platform"] == platform_name assert json.loads(job["with"]["runs_on"]) == ["self-hosted", platform_name] if caller == "daily": @@ -310,6 +310,7 @@ def test_each_caller_routes_both_platforms_to_the_same_reusable_workflow(caller) assert "outputs.st_affected == 'true'" in job["if"] assert job["needs"] == ["detect-changes", "pre-commit"] workflow = _yaml(_WORKFLOW) + assert workflow["jobs"]["run"]["name"] == "st-torch-npu-${{ inputs.platform }}" assert workflow["jobs"]["run"]["timeout-minutes"] == "45" assert workflow["jobs"]["run"]["steps"][-1]["with"]["name"] == ( "framework-eager-${{ inputs.platform }}-${{ github.run_id }}-${{ github.run_attempt }}" diff --git a/tests/ut/py/test_framework_eager_contract.py b/tests/ut/py/test_framework_eager_contract.py index d2aa803d03..a51a70b337 100644 --- a/tests/ut/py/test_framework_eager_contract.py +++ b/tests/ut/py/test_framework_eager_contract.py @@ -236,10 +236,10 @@ def test_framework_setup_preserves_the_callers_installed_toolchain(tmp_path, ver @pytest.mark.parametrize("platform", ["a2a3", "a5"]) @pytest.mark.parametrize("mode", ["exclude", "include", "only", "invalid"]) def test_framework_workflow_propagates_manual_selection(tmp_path, mode, platform): - workflow = yaml.load((_ROOT / ".github/workflows/_st-framework-eager.yml").read_text(), Loader=yaml.BaseLoader) + workflow = yaml.load((_ROOT / ".github/workflows/_st-torch-npu.yml").read_text(), Loader=yaml.BaseLoader) assert workflow["on"]["workflow_call"]["inputs"]["manual_mode"]["default"] == "exclude" daily = yaml.load((_ROOT / ".github/workflows/daily.yml").read_text(), Loader=yaml.BaseLoader) - assert daily["jobs"][f"st-framework-eager-{platform}"]["with"]["manual_mode"] == "include" + assert daily["jobs"][f"st-torch-npu-{platform}"]["with"]["manual_mode"] == "include" step = next(step for step in workflow["jobs"]["run"]["steps"] if "run" in step) assert step["env"]["MANUAL_MODE"] == "${{ inputs.manual_mode }}" assert step["env"]["PLATFORM"] == "${{ inputs.platform }}" diff --git a/tools/cann-examples/aicpu-device-query/host/query_device_hal.cpp b/tools/cann-examples/aicpu-device-query/host/query_device_hal.cpp index 291101e00f..b0357a965b 100644 --- a/tools/cann-examples/aicpu-device-query/host/query_device_hal.cpp +++ b/tools/cann-examples/aicpu-device-query/host/query_device_hal.cpp @@ -498,7 +498,7 @@ int main(int argc, char **argv) { ); if (json_output) { - pto::a5::AicpuDeviceOccupancy occupancy; + simpler::a5::AicpuDeviceOccupancy occupancy; occupancy.os_sched = static_cast(results[kOsSchedRequestIndex].value); occupancy.os_sched_valid = results[kOsSchedRequestIndex].rc == 0; occupancy.occupy = static_cast(results[kOccupyRequestIndex].value); @@ -506,8 +506,8 @@ int main(int argc, char **argv) { occupancy.pf_occupy = static_cast(results[kPfOccupyRequestIndex].value); occupancy.pf_occupy_valid = results[kPfOccupyRequestIndex].rc == 0; - pto::a5::AicpuTopology topology; - if (!pto::a5::probe_aicpu_topology(static_cast(device_id), occupancy, topology)) { + simpler::a5::AicpuTopology topology; + if (!simpler::a5::probe_aicpu_topology(static_cast(device_id), occupancy, topology)) { std::fprintf(stderr, "A5 AICPU topology probe failed for device %d\n", device_id); return 1; } @@ -516,25 +516,25 @@ int main(int argc, char **argv) { return 1; } - pto::a5::AicpuLaunchPlan launch_plan; + simpler::a5::AicpuLaunchPlan launch_plan; std::string plan_error; - if (!pto::a5::build_aicpu_launch_plan(topology, 0, launch_plan, plan_error)) { + if (!simpler::a5::build_aicpu_launch_plan(topology, 0, launch_plan, plan_error)) { std::fprintf(stderr, "A5 AICPU launch planning failed: %s\n", plan_error.c_str()); return 1; } - pto::a5::AicpuSelectionPolicy policy = pto::a5::AicpuSelectionPolicy::kScenario; + simpler::a5::AicpuSelectionPolicy policy = simpler::a5::AicpuSelectionPolicy::kScenario; if (topology.generic_selection_only) { - policy = pto::a5::AicpuSelectionPolicy::kGeneric; - } else if (topology.scenario_type == pto::a5::AicpuScenarioType::kUnknown) { - policy = pto::a5::AicpuSelectionPolicy::kSequentialFallback; + policy = simpler::a5::AicpuSelectionPolicy::kGeneric; + } else if (topology.scenario_type == simpler::a5::AicpuScenarioType::kUnknown) { + policy = simpler::a5::AicpuSelectionPolicy::kSequentialFallback; std::fprintf( stderr, "WARNING: AICPU topology UNKNOWN; selected %d active roles from %d stable CPUs; launch count=%d\n", launch_plan.effective_active_count, launch_plan.stable_reachable_count, launch_plan.launch_count ); } - std::fputs(pto::a5::format_aicpu_topology_json(topology, policy, launch_plan).c_str(), stdout); + std::fputs(simpler::a5::format_aicpu_topology_json(topology, policy, launch_plan).c_str(), stdout); } else { // ---- Pretty-print ---- std::printf("\n=== device=%d device-side HAL view (via dispatcher + inner SO) ===\n", device_id); From 9acb4e5c2c728215d22dd02f066bd43b8105aa68 Mon Sep 17 00:00:00 2001 From: Chao Wang <26245345+ChaoWao@users.noreply.github.com> Date: Mon, 9 Nov 2026 19:48:44 -0800 Subject: [PATCH 2/2] CI: leave framework naming to the coverage migration --- .../actions/setup-framework-eager/action.yml | 2 +- ...-torch-npu.yml => _st-framework-eager.yml} | 10 ++--- .github/workflows/_st-npu-a2a3.yml | 2 +- .github/workflows/ci-a5-comment.yml | 8 ++-- .github/workflows/ci-self.yml | 8 ++-- .github/workflows/ci.yml | 4 +- .github/workflows/daily.yml | 8 ++-- docs/ci.md | 41 +++++++++---------- examples/workers/l2/framework_eager/README.md | 6 +-- tests/ut/py/test_a5_comment_ci.py | 6 +-- .../ut/py/test_framework_eager_ci_platform.py | 13 +++--- tests/ut/py/test_framework_eager_contract.py | 4 +- 12 files changed, 55 insertions(+), 57 deletions(-) rename .github/workflows/{_st-torch-npu.yml => _st-framework-eager.yml} (92%) diff --git a/.github/actions/setup-framework-eager/action.yml b/.github/actions/setup-framework-eager/action.yml index 9ccd61c687..c230fc1eba 100644 --- a/.github/actions/setup-framework-eager/action.yml +++ b/.github/actions/setup-framework-eager/action.yml @@ -1,4 +1,4 @@ -name: Set up Torch-NPU test environment +name: Set up framework eager environment description: Install the CANN 9.0+ framework consumer in its own virtual environment. inputs: diff --git a/.github/workflows/_st-torch-npu.yml b/.github/workflows/_st-framework-eager.yml similarity index 92% rename from .github/workflows/_st-torch-npu.yml rename to .github/workflows/_st-framework-eager.yml index 69ef6b9d7a..6b89cb9ba1 100644 --- a/.github/workflows/_st-torch-npu.yml +++ b/.github/workflows/_st-framework-eager.yml @@ -1,4 +1,4 @@ -name: Torch-NPU Scene Tests +name: Framework Eager Scene Tests permissions: contents: read @@ -25,7 +25,7 @@ on: jobs: run: - name: st-torch-npu-${{ inputs.platform }} + name: st-framework-eager-${{ inputs.platform }} runs-on: ${{ fromJSON(inputs.runs_on) }} timeout-minutes: 45 env: @@ -41,13 +41,13 @@ jobs: ref: ${{ inputs.ref || github.ref }} persist-credentials: false - - name: Set up Torch-NPU environment + - name: Set up framework environment id: framework uses: ./.github/actions/setup-framework-eager with: platform: ${{ inputs.platform }} - - name: Run Torch-NPU scene tests exclusively + - name: Run the declared framework environment exclusively env: CANN_ENV: ${{ steps.framework.outputs.cann_env }} MANUAL_MODE: ${{ inputs.manual_mode }} @@ -76,7 +76,7 @@ jobs: --basetemp outputs/framework-eager-ci/pytest --junitxml outputs/framework-eager-ci/results.xml" .venv-framework/bin/python -m simpler_setup.test_environments verify outputs/framework-eager-ci/results.plan.json outputs/framework-eager-ci/results.xml - - name: Retain Torch-NPU identities and logs + - name: Retain framework eager identities and logs if: always() # The test result is already checked above; artifact service failures only lose diagnostics. continue-on-error: true diff --git a/.github/workflows/_st-npu-a2a3.yml b/.github/workflows/_st-npu-a2a3.yml index 8acb143ef6..40ea43b54a 100644 --- a/.github/workflows/_st-npu-a2a3.yml +++ b/.github/workflows/_st-npu-a2a3.yml @@ -96,7 +96,7 @@ jobs: --platform a2a3 --compile-only --compile-workers 32 done - # Torch-NPU cases have their own dependency-isolated job. The remaining + # Framework eager has its own dependency-isolated job. The remaining # three selections are disjoint and exhaustive over this corpus: a test with # neither marker lands here, `sdma` alone in the demo task, and # `sdma_fault` in the isolated one whether or not it also carries `sdma`. diff --git a/.github/workflows/ci-a5-comment.yml b/.github/workflows/ci-a5-comment.yml index 7ccde45450..fd78734097 100644 --- a/.github/workflows/ci-a5-comment.yml +++ b/.github/workflows/ci-a5-comment.yml @@ -91,13 +91,13 @@ jobs: runs_on: '["self-hosted","a5"]' include_dfx_smokes: true - st-torch-npu-a5: + st-framework-eager-a5: needs: [gate-and-resolve] if: needs.gate-and-resolve.outputs.ready == 'true' concurrency: group: ci-a5-framework-${{ needs.gate-and-resolve.outputs.pr_number }} cancel-in-progress: true - uses: ./.github/workflows/_st-torch-npu.yml + uses: ./.github/workflows/_st-framework-eager.yml with: platform: a5 repository: ${{ needs.gate-and-resolve.outputs.repository }} @@ -105,7 +105,7 @@ jobs: runs_on: '["self-hosted","a5"]' report: - needs: [gate-and-resolve, ut-a5, st-onboard-a5, st-torch-npu-a5] + needs: [gate-and-resolve, ut-a5, st-onboard-a5, st-framework-eager-a5] if: always() && needs.gate-and-resolve.result == 'success' && needs.gate-and-resolve.outputs.ready == 'true' runs-on: ubuntu-24.04 permissions: @@ -122,7 +122,7 @@ jobs: const gate = needs['gate-and-resolve']; if (gate.result !== 'success' || gate.outputs.ready !== 'true') return; const { repository, ref, pr_number: number } = gate.outputs; - const suites = ['ut-a5', 'st-onboard-a5', 'st-torch-npu-a5']; + const suites = ['ut-a5', 'st-onboard-a5', 'st-framework-eager-a5']; const results = suites.map(name => ({ name, result: needs[name]?.result || 'unknown' })); const passed = results.every(job => job.result === 'success'); const url = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; diff --git a/.github/workflows/ci-self.yml b/.github/workflows/ci-self.yml index e88c820bf8..5569f41abb 100644 --- a/.github/workflows/ci-self.yml +++ b/.github/workflows/ci-self.yml @@ -140,20 +140,20 @@ jobs: runs_on: '["self-hosted","a2a3"]' include_cann_examples: false - st-torch-npu-a2a3: + st-framework-eager-a2a3: needs: [detect-changes, pre-commit] if: needs.detect-changes.outputs.a2a3_changed == 'true' && needs.detect-changes.outputs.st_affected == 'true' - uses: ./.github/workflows/_st-torch-npu.yml + uses: ./.github/workflows/_st-framework-eager.yml with: platform: a2a3 repository: ${{ inputs.repository || github.repository }} ref: ${{ inputs.ref || github.sha }} runs_on: '["self-hosted","a2a3"]' - st-torch-npu-a5: + st-framework-eager-a5: needs: [detect-changes, pre-commit] if: needs.detect-changes.outputs.a5_changed == 'true' && needs.detect-changes.outputs.st_affected == 'true' - uses: ./.github/workflows/_st-torch-npu.yml + uses: ./.github/workflows/_st-framework-eager.yml with: platform: a5 repository: ${{ inputs.repository || github.repository }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c24333b193..6aa9bf5c22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,10 +103,10 @@ jobs: runs_on: '["self-hosted","a2a3"]' include_cann_examples: true - st-torch-npu-a2a3: + st-framework-eager-a2a3: needs: [detect-changes, pre-commit] if: needs.detect-changes.outputs.a2a3_changed == 'true' && needs.detect-changes.outputs.st_affected == 'true' - uses: ./.github/workflows/_st-torch-npu.yml + uses: ./.github/workflows/_st-framework-eager.yml with: platform: a2a3 runs_on: '["self-hosted","a2a3"]' diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 940e08badf..17c8bb0765 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -56,15 +56,15 @@ jobs: session_timeout_seconds: 1800 job_timeout_minutes: 60 - st-torch-npu-a2a3: - uses: ./.github/workflows/_st-torch-npu.yml + st-framework-eager-a2a3: + uses: ./.github/workflows/_st-framework-eager.yml with: platform: a2a3 runs_on: '["self-hosted","a2a3"]' manual_mode: include - st-torch-npu-a5: - uses: ./.github/workflows/_st-torch-npu.yml + st-framework-eager-a5: + uses: ./.github/workflows/_st-framework-eager.yml with: platform: a5 runs_on: '["self-hosted","a5"]' diff --git a/docs/ci.md b/docs/ci.md index 2fe10bf8f5..01341bf19e 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -24,7 +24,7 @@ The complete test-type × hardware-tier matrix across automatic CI, the A5 comme | Category | github-hosted (no hardware) | a2a3 runner | a5 runner | | -------- | --------------------------- | ----------- | --------- | | **ut** | `ut` (py + cpp) | `ut-a2a3` (py + cpp) | `ut-a5` (py) | -| **st** | `st-sim-a2a3`, `st-sim-a5` | `st-onboard-a2a3`, `st-network1-onboard-a2a3`, `st-deepseek-onboard-a2a3`, `st-torch-npu-a2a3` | `st-onboard-a5`, `st-torch-npu-a5` | +| **st** | `st-sim-a2a3`, `st-sim-a5` | `st-onboard-a2a3`, `st-network1-onboard-a2a3`, `st-deepseek-onboard-a2a3`, `st-framework-eager-a2a3` | `st-onboard-a5`, `st-framework-eager-a5` | ## GitHub Actions Jobs @@ -35,9 +35,9 @@ shape. The executable job bodies live in reusable workflows: `_packaging.yml`, `_profiling-flags-smoke.yml`, `_st-sim-a2a3.yml`, `_st-sim-a5.yml`, `_ut-npu-a2a3.yml`, `_ut-npu-a5.yml`, `_st-npu-a2a3.yml`, `_st-npu-a5.yml`, `_st-network1.yml`, -`_st-deepseek-a2a3.yml`, and `_st-torch-npu.yml`. The simulation, +`_st-deepseek-a2a3.yml`, and `_st-framework-eager.yml`. The simulation, ordinary onboard, and NPU unit-test bodies are split by architecture so each -job renders only its own steps. Torch-NPU scene tests share `_st-torch-npu.yml`; +job renders only its own steps. Framework eager shares `_st-framework-eager.yml`; callers supply matching `platform` and `runs_on` inputs. Shared step scaffolding that is safe to run after checkout lives in composite actions under `.github/actions/` (`apt-install`, `cache-pip`, `cache-ccache`, `setup-gcc-15`, `setup-venv`, and the three `network1-*` actions). @@ -79,7 +79,7 @@ PullRequest ├── st-sim-a5 (ubuntu-24.04) — a5_changed && st_affected ├── ut-a2a3 (a2a3 self-hosted) — Python + C++ UT, a2a3 hardware [needs ut_affected] ├── st-onboard-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected - ├── st-torch-npu-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected + ├── st-framework-eager-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected ├── st-network1-onboard-a2a3 (a2a3pod pair) — a2a3_changed && st_affected └── st-deepseek-onboard-a2a3 (a2a3 self-hosted) — a2a3_changed && st_affected @@ -87,7 +87,7 @@ Admin PR comment /run-a5 └── gate-and-resolve (ubuntu-24.04) — open PR to this repo main; pinned head ├── ut-a5 (a5 self-hosted) — Python UT and CANN examples ├── st-onboard-a5 (a5 self-hosted) — onboard ST and DFX smokes - └── st-torch-npu-a5 (a5 self-hosted) — Torch-NPU ST + └── st-framework-eager-a5 (a5 self-hosted) — framework eager ST ``` | Job | Runner | What it runs | @@ -97,10 +97,10 @@ Admin PR comment /run-a5 | `st-sim-a5` | `ubuntu-24.04` | `pytest examples tests/st --platform a5sim` | | `ut-a2a3` | a2a3 self-hosted | Hardware Python UT: `device_count` cases use resource scheduling, RuntimeBuilder integration runs before the xdist fanout, and remaining cases use one worker per allocated device. Then `ctest -L "^requires_hardware(_a2a3)?$" --resource-spec-file ...` and CANN example smokes. | | `st-onboard-a2a3` | a2a3 self-hosted | `pytest examples tests/st -m "not sdma and not sdma_fault" --platform a2a3 --exclude-level 4 --device ...`, then separate SDMA-demo and `sdma_fault` device tasks, then adaptive-parallel DFX feature smokes | -| `st-torch-npu-a2a3` | a2a3 self-hosted | `pytest examples tests/st --platform a2a3 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | +| `st-framework-eager-a2a3` | a2a3 self-hosted | `pytest examples tests/st --platform a2a3 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | | `ut-a5` | a5 self-hosted | Hardware Python UT: `device_count` cases use resource scheduling, RuntimeBuilder integration runs before the xdist fanout, and remaining cases use one worker per allocated device. Then CANN example smokes. | | `st-onboard-a5` | a5 self-hosted | Default SDMA+URMA / RDMA=OFF build and `pytest examples tests/st --platform a5 --exclude-level 4 --device ...`, including SDMA, the active URMA regressions and mixed SDMA/URMA cases, then adaptive-parallel DFX feature smokes | -| `st-torch-npu-a5` | a5 self-hosted | `pytest examples tests/st --platform a5 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | +| `st-framework-eager-a5` | a5 self-hosted | `pytest examples tests/st --platform a5 --test-environment torch_npu --manual exclude --require-pto-isa --device ... --max-parallel 1 -p no:xdist` in one exclusive task, then verify plan/JUnit | | `st-network1-onboard-a2a3` | a pair of `a2a3pod` machines | `pytest examples tests/st --level 4 --platform a2a3 --device ... --max-parallel 1`, one L3 daemon on the peer | | `st-deepseek-onboard-a2a3` | a2a3 self-hosted | `pytest --platform a2a3 --manual only --device ...`, both 2-device cases concurrently, in parallel with `st-onboard-a2a3` | @@ -350,23 +350,22 @@ not need `--max-parallel` manually. - **SDMA tests run in isolated tasks inside `st-onboard-a2a3`.** Within the default test environment, three selections partition the corpus (`examples tests/st`): the ordinary sweep takes `-m "not sdma and not sdma_fault"` with `--exclude-level 4`, one queued task runs `-m "sdma and not sdma_fault"` for the demos, and a separate one-device task runs `-m sdma_fault` for the AICore fault-injection case. The three are disjoint and exhaustive over both markers, and all three name the same paths, so a case cannot land in two tasks or in none. Provisioning the SDMA workspace creates 48 device-only STARS streams that live in the device fault domain, and tearing them down once any AICore task has poisoned that card blocks minutes rather than milliseconds — whether the teardown is a device reset or an explicit stream destroy ([#1425](https://github.com/hw-native-sys/simpler/issues/1425)). The cost therefore falls on whichever process still holds those streams when the fault happens, which is why the fault-injection case gets a task containing nothing else. Separate `task-submit` tasks preserve that on every onboard runner, independent of pytest ordering. Network1 tests are selected by `--level 4` in `st-network1-onboard-a2a3` and explicitly excluded from ordinary onboard ST lanes. -### Torch-NPU qualification (a2a3 and a5) +### Framework eager qualification (a2a3 and a5) -`st-torch-npu-a2a3` runs automatically on affected PRs. Torch-NPU -validation on A5 for ordinary PRs is part of `/run-a5`. Both run in the emergency +`st-framework-eager-a2a3` runs automatically on affected PRs. A5 framework +eager validation for ordinary PRs is part of `/run-a5`. Both run in the emergency lane and Daily. Automatic and emergency callers use the corresponding `a2a3_changed && st_affected` or `a5_changed && st_affected` gate; the explicit A5 command runs without a change gate. Each uses its architecture runner pool. -All callers reuse `_st-torch-npu.yml` with an explicit platform. Setup validates `a2a3|a5`, builds `build_package_`, +All callers reuse `_st-framework-eager.yml` with an explicit platform. Setup validates `a2a3|a5`, builds `build_package_`, and records the matching onboard runtime roots. The exclusive task checks actual silicon before backend import and passes the same platform to identity recording and pytest. Artifacts are named separately by platform; a green A3 job does not qualify A5. -Eager submission and cold capture tests declare -`@pytest.mark.test_environment("torch_npu")`. The job discovers cases across -`examples tests/st` with `--test-environment torch_npu`. Ordinary onboard -sweeps and compile warm-up select the implicit `default` environment, including -in Daily. Torch-NPU dependencies +Tests declare `@pytest.mark.test_environment("torch_npu")`. The job discovers +them across `examples tests/st` with `--test-environment torch_npu`; it does +not enumerate directories or cases. Ordinary sweeps and compile warm-up select +the implicit `default` environment, including in Daily. Framework dependencies live only in `.venv-framework`, separate from the Program/fork sweep's `.venv`. Environment selection is independent of `manual`. The reusable job accepts the same `manual_mode` contract as other scene-test jobs: Per-PR and emergency @@ -464,14 +463,14 @@ source/native build identities, runtime and framework module hashes, compiled bridge identity and consumer results; when artifact upload succeeds, `framework-eager--*` retains JUnit and per-case logs even on test failure. Artifact upload is best-effort and does not override the verified test result. -The eager cases qualify the reference consumers' same-stream and cross-stream eager ordering, caller-owned lifetimes, +This qualifies the reference +consumers' same-stream and cross-stream eager ordering, caller-owned lifetimes, bounded aliased INOUT assertions, ordinary callback-error recovery and per-call value semantics and bounded DEVICE-controlled persistent cache state. It does not qualify native failed-drain recovery, pending framework-callback close or early HOST-backing release. It does not establish -overlap, arbitrary strides/cross-tile aliasing or PyPTO dispatch. The cold -capture cases separately check replay values and graph resource lifetime. -Qualification is limited to the cases, platform and environment in each receipt. +overlap, arbitrary strides/cross-tile aliasing, PyPTO dispatch or capture/replay. +Qualification is limited to the actual platform and environment in each receipt. ### A5 hardware validation (`/run-a5`) @@ -483,7 +482,7 @@ and full commit SHA, including fork PRs. Non-PR comments and unverified or non-admin requests cannot schedule hardware work. Every admitted request runs `ut-a5` with CANN examples, `st-onboard-a5` with DFX -smokes, and `st-torch-npu-a5` through the existing reusable workflows. +smokes, and `st-framework-eager-a5` through the existing reusable workflows. No change detector filters an explicit request, including a documentation-only PR. A new admitted request cancels the previous same-PR job for each suite; unmatched and denied comments cannot cancel admitted jobs. Pushes do not diff --git a/examples/workers/l2/framework_eager/README.md b/examples/workers/l2/framework_eager/README.md index 6cab19228d..d800bb74be 100644 --- a/examples/workers/l2/framework_eager/README.md +++ b/examples/workers/l2/framework_eager/README.md @@ -157,9 +157,9 @@ CLIs load the unique existing artifact, building only when it is absent; the original same-stream CLI still checks its incremental build cache. All use the original `build_bridge` / `_load_bridge` helpers. The `test_environment("torch_npu")` marker selects an isolated framework venv in the -dedicated `st-torch-npu-a2a3` and `st-torch-npu-a5` jobs, shared by eager and -cold capture cases. Ordinary onboard sweeps select the default environment. -Selecting the suite without its dependencies fails. See [CI qualification](../../../../docs/ci.md#torch-npu-qualification-a2a3-and-a5) for the pinned compatibility contract. Run this suite +dedicated `st-framework-eager-a2a3` and `st-framework-eager-a5` PR and Daily jobs. The default environment +automatically deselects these tests; no directory exclusion is needed. +Selecting the suite without its dependencies fails. See [CI qualification](../../../../docs/ci.md#framework-eager-qualification-a2a3-and-a5) for the pinned compatibility contract. Run this suite serially inside one exclusive `task-submit` allocation of one device, as below; resource-parallel dispatch and xdist are not qualified by this example: diff --git a/tests/ut/py/test_a5_comment_ci.py b/tests/ut/py/test_a5_comment_ci.py index d61941ea09..26ac36e379 100644 --- a/tests/ut/py/test_a5_comment_ci.py +++ b/tests/ut/py/test_a5_comment_ci.py @@ -21,7 +21,7 @@ _SUITES = { "ut-a5": "_ut-npu-a5.yml", "st-onboard-a5": "_st-npu-a5.yml", - "st-torch-npu-a5": "_st-torch-npu.yml", + "st-framework-eager-a5": "_st-framework-eager.yml", } _SHA = "1234567890abcdef" * 2 + "12345678" _NODE = r""" @@ -106,7 +106,7 @@ def test_only_three_hardware_suites_move_from_automatic_ci(): assert all(name in _workflow("ci-self")["jobs"] for name in _SUITES) daily = _workflow("daily")["jobs"] assert "ut-a5" not in daily - assert "st-onboard-a5" in daily and "st-torch-npu-a5" in daily + assert "st-onboard-a5" in daily and "st-framework-eager-a5" in daily def test_authorized_topology_pins_all_suites_and_keeps_reporting_permission_separate(): @@ -148,7 +148,7 @@ def test_authorized_topology_pins_all_suites_and_keeps_reporting_permission_sepa assert step["with"]["ref"] == "${{ inputs.ref || github.ref }}" assert jobs["ut-a5"]["with"]["include_cann_examples"] == "true" assert jobs["st-onboard-a5"]["with"]["include_dfx_smokes"] == "true" - assert jobs["st-torch-npu-a5"]["with"]["platform"] == "a5" + assert jobs["st-framework-eager-a5"]["with"]["platform"] == "a5" report = jobs["report"] assert set(report["needs"]) == {"gate-and-resolve", *_SUITES} assert report["if"].startswith("always() &&") diff --git a/tests/ut/py/test_framework_eager_ci_platform.py b/tests/ut/py/test_framework_eager_ci_platform.py index 0020a05408..1594c37e82 100644 --- a/tests/ut/py/test_framework_eager_ci_platform.py +++ b/tests/ut/py/test_framework_eager_ci_platform.py @@ -21,7 +21,7 @@ _ROOT = Path(__file__).resolve().parents[3] _ACTION = _ROOT / ".github/actions/setup-framework-eager" -_WORKFLOW = _ROOT / ".github/workflows/_st-torch-npu.yml" +_WORKFLOW = _ROOT / ".github/workflows/_st-framework-eager.yml" def _yaml(path): @@ -292,15 +292,15 @@ def test_each_caller_routes_both_platforms_to_the_same_reusable_workflow(caller) jobs = _yaml(_ROOT / f".github/workflows/{caller}.yml")["jobs"] for platform_name in ("a2a3", "a5"): if caller == "ci" and platform_name == "a5": - assert "st-torch-npu-a5" not in jobs - job = _yaml(_ROOT / ".github/workflows/ci-a5-comment.yml")["jobs"]["st-torch-npu-a5"] - assert job["uses"] == "./.github/workflows/_st-torch-npu.yml" + assert "st-framework-eager-a5" not in jobs + job = _yaml(_ROOT / ".github/workflows/ci-a5-comment.yml")["jobs"]["st-framework-eager-a5"] + assert job["uses"] == "./.github/workflows/_st-framework-eager.yml" assert job["with"]["platform"] == "a5" assert json.loads(job["with"]["runs_on"]) == ["self-hosted", "a5"] assert job["needs"] == ["gate-and-resolve"] continue - job = jobs[f"st-torch-npu-{platform_name}"] - assert job["uses"] == "./.github/workflows/_st-torch-npu.yml" + job = jobs[f"st-framework-eager-{platform_name}"] + assert job["uses"] == "./.github/workflows/_st-framework-eager.yml" assert job["with"]["platform"] == platform_name assert json.loads(job["with"]["runs_on"]) == ["self-hosted", platform_name] if caller == "daily": @@ -310,7 +310,6 @@ def test_each_caller_routes_both_platforms_to_the_same_reusable_workflow(caller) assert "outputs.st_affected == 'true'" in job["if"] assert job["needs"] == ["detect-changes", "pre-commit"] workflow = _yaml(_WORKFLOW) - assert workflow["jobs"]["run"]["name"] == "st-torch-npu-${{ inputs.platform }}" assert workflow["jobs"]["run"]["timeout-minutes"] == "45" assert workflow["jobs"]["run"]["steps"][-1]["with"]["name"] == ( "framework-eager-${{ inputs.platform }}-${{ github.run_id }}-${{ github.run_attempt }}" diff --git a/tests/ut/py/test_framework_eager_contract.py b/tests/ut/py/test_framework_eager_contract.py index a51a70b337..d2aa803d03 100644 --- a/tests/ut/py/test_framework_eager_contract.py +++ b/tests/ut/py/test_framework_eager_contract.py @@ -236,10 +236,10 @@ def test_framework_setup_preserves_the_callers_installed_toolchain(tmp_path, ver @pytest.mark.parametrize("platform", ["a2a3", "a5"]) @pytest.mark.parametrize("mode", ["exclude", "include", "only", "invalid"]) def test_framework_workflow_propagates_manual_selection(tmp_path, mode, platform): - workflow = yaml.load((_ROOT / ".github/workflows/_st-torch-npu.yml").read_text(), Loader=yaml.BaseLoader) + workflow = yaml.load((_ROOT / ".github/workflows/_st-framework-eager.yml").read_text(), Loader=yaml.BaseLoader) assert workflow["on"]["workflow_call"]["inputs"]["manual_mode"]["default"] == "exclude" daily = yaml.load((_ROOT / ".github/workflows/daily.yml").read_text(), Loader=yaml.BaseLoader) - assert daily["jobs"][f"st-torch-npu-{platform}"]["with"]["manual_mode"] == "include" + assert daily["jobs"][f"st-framework-eager-{platform}"]["with"]["manual_mode"] == "include" step = next(step for step in workflow["jobs"]["run"]["steps"] if "run" in step) assert step["env"]["MANUAL_MODE"] == "${{ inputs.manual_mode }}" assert step["env"]["PLATFORM"] == "${{ inputs.platform }}"