Skip to content

Refactor: confine host_build_graph orchestration to the host - #2094

Open
poursoul wants to merge 1 commit into
hw-native-sys:mainfrom
poursoul:refactor/confine-host-build-graph-orchestration-to
Open

Refactor: confine host_build_graph orchestration to the host#2094
poursoul wants to merge 1 commit into
hw-native-sys:mainfrom
poursoul:refactor/confine-host-build-graph-orchestration-to

Conversation

@poursoul

@poursoul poursoul commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

What

host_build_graph builds its graph on the host — the orchestration .so is dlopened by the host runtime, and the AICPU only ever runs schedulers. But the sources implementing that orchestration sat under shared/, so the aicpu target compiled all of them: the ops table, the whole submit path, TensorMap, and Graph recording.

The AICPU device image drops from 4.8 MB to 3.1 MB — 1.6 MB (33%) of code no device code could reach.

Why it is safe

Nothing under aicpu/, runtime/ or device/ names OrchestratorState or ChipTensorMap, and the graph_* free functions they define reach no device caller.

The load-bearing check is on symbols, not on the build succeeding: a shared library links cleanly with unresolved symbols and only fails at dlopen. So the undefined-symbol table of each AICPU .so was captured before the move and compared after — zero new undefined symbols on all four variants (a2a3/a5 × sim/onboard).

The three pieces

1. The ops table is host-only. The AICPU no longer rebinds it at boot, and the host now clears rt->ops alongside rt->orchestrator before the copied zone is uploaded, so the device never receives a host address in that field.

2. runtime_core.cpp, orchestrator.cpp, tensormap.cpp move under host/ — which the build config already excludes from the aicpu target, so no build file changes. OrchestratorState::init goes with them: it calls ChipTensorMap::init_default, and left in shared/runtime_init.cpp it would have handed the AICPU an unresolved reference.

3. Weak markers become link seams. With one target compiling these files, weak selects nothing — it only hid which definition wins behind link order, where nothing checks it, and a missing sink linked cleanly and silently did nothing. get_sys_cnt_aicpu and get_reg_ptr become ordinary definitions in host/aicpu_shims.cpp (on the host neither is a fallback: host orchestration needs a real monotonic clock, and route_ready_once ODR-uses the doorbell inline), collapsing the clock's three copies into one. The dep_gen / host_phase no-ops move to tests/ut/cpp/stubs/, carried by HBG_ORCH_SHARED_SOURCES — which the one test wanting the real capture does not use, so that split is exclusive and needs no weak marker either.

Removing the weak markers immediately surfaced 6 undefined references at UT link time. Under weak those same gaps would have been silent no-ops: host_phase_record recording nothing, dep_gen capturing nothing, tests still green.

Also

RuntimeOps was written out three times — once per arch's orchestration_api.h, once in runtime_core.h — and the copies had to agree field for field, since the .so calls through the table by offset. A field added to one copy alone shifts every later entry and dispatches to the wrong function, with nothing to catch it at compile time. runtime_ops.h now carries the one definition both sides include.

Two comments in graph_recorder_pool explaining why that TU cannot include runtime_core.h named RuntimeOps as the type existing twice. The conflict is RuntimeContext — partial in orchestration_api.h, full in runtime_core.h — and it still stands; the comments now name it.

What did NOT change

The ops table itself stays. ChipWorker dlopens each runtime RTLD_LOCAL so two runtimes' identically-named exports (simpler_init, simpler_run, …) cannot collide and dlclose can actually unload one (#453). A runtime's symbols therefore never reach the global symbol table, and the orchestration .so has no way to bind them by name. The table is not a legacy layer — it is how that boundary is crossed.

Test

  • Build: 8 targets, zero warnings

  • Symbols: 0 new undefined on all four AICPU .sos; both host shims confirmed absent from the host .so's dynamic symbol table (hidden intact)

  • ctest: 128/128

  • Scene tests: a2a3sim 10 passed, a5sim 7 passed

  • pre-commit: clean

  • a2a3 onboard (real hardware): 35 passed / 1 skipped (host_build_graph) + 2 passed (tensormap_and_ringbuffer), task-submit exit=0. No 507018/507014/507899, and the run's own device log carries no FATAL, deadlock or HandleTaskTimeout signature.

a5 hardware is covered by CI (st-onboard-a5), not locally — this box is a2a3.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: c0188b94-eebe-40dc-8df0-1f0eb2ef0bdf

📥 Commits

Reviewing files that changed from the base of the PR and between 15f5cbd and 9054d50.

📒 Files selected for processing (21)
  • .claude/rules/codestyle.md
  • src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp
  • src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp
  • src/a2a3/runtime/host_build_graph/orchestration/orchestration_api.h
  • src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp
  • src/a5/runtime/host_build_graph/host/runtime_maker.cpp
  • src/a5/runtime/host_build_graph/orchestration/orchestration_api.h
  • src/common/host_build_graph/graph_recorder_pool.h
  • src/common/host_build_graph/host/aicpu_shims.cpp
  • src/common/host_build_graph/host/graph_recorder_pool.cpp
  • src/common/host_build_graph/host/orchestrator.cpp
  • src/common/host_build_graph/host/runtime_core.cpp
  • src/common/host_build_graph/host/tensormap.cpp
  • src/common/host_build_graph/host_phase_trace.h
  • src/common/host_build_graph/host_tensor_access.h
  • src/common/host_build_graph/runtime_core.h
  • src/common/host_build_graph/runtime_ops.h
  • src/common/host_build_graph/shared/runtime_init.cpp
  • src/common/platform/include/common/host_phase_kind.h
  • tests/ut/cpp/CMakeLists.txt
  • tests/ut/cpp/stubs/hbg_orch_stubs.cpp
💤 Files with no reviewable changes (2)
  • src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp
  • src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change moves RuntimeOps into a shared header, separates host orchestration implementations from shared runtime code, adds host initialization and support shims, clears host-only runtime pointers before image upload, and updates AICPU boot and test wiring.

Changes

Host orchestration runtime split

Layer / File(s) Summary
Runtime operations boundary
src/common/host_build_graph/runtime_ops.h, src/common/host_build_graph/runtime_core.h, src/common/host_build_graph/host/runtime_core.cpp, src/common/host_build_graph/orchestration/orchestration_api.h, src/common/host_build_graph/shared/runtime_init.cpp, src/common/host_build_graph/graph_recorder_pool.*, src/common/host_build_graph/host_tensor_access.h
RuntimeOps is defined in runtime_ops.h and included by runtime and orchestration headers. Host-only fallback implementations and shared orchestrator initialization are removed.
Host orchestration implementation
src/common/host_build_graph/host/orchestrator.cpp, src/common/host_build_graph/host/tensormap.cpp, src/common/host_build_graph/host/aicpu_shims.cpp, src/common/host_build_graph/host_phase_trace.h, src/common/platform/include/common/host_phase_kind.h, .claude/rules/codestyle.md
Host orchestration state initialization, tensor-map management, profiling counters, AICPU shims, and host source references are added or updated.
Runtime boot and image safety
src/a2a3/runtime/host_build_graph/{aicpu,host}/*, src/a5/runtime/host_build_graph/{aicpu,host}/*
AICPU boot uses sched_ctx_.bind_runtime(rt) as the runtime-binding operation. Image preparation clears both rt->orchestrator and rt->ops.
Host build graph test wiring
tests/ut/cpp/CMakeLists.txt, tests/ut/cpp/stubs/hbg_orch_stubs.cpp
Tests compile host orchestration sources and provide capture-sink stubs for orchestrator tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 9054d

The refactor removes host orchestration from the device image and clears its callback pointers, but a host-only tensor_access address is still copied to the device. No current device use is identified, so the risk is bounded and mergeable with explicit owner awareness or follow-up to clear that field as well.

Poem

A rabbit checks the runtime gate,
Host pointers vanish before freight.
Ops hop into a shared new nest,
Tensor maps settle into rest.
Shims tick softly; tests grow bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 17 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarizes the main change: restricting host_build_graph orchestration to the host.
Description check ✅ Passed The description directly explains the orchestration relocation, host-only runtime changes, weak-marker replacement, and validation results.
Full details: Docstring Coverage

Explanation

Docstring coverage is 28.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 25 functions across 17 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@poursoul
poursoul force-pushed the refactor/confine-host-build-graph-orchestration-to branch from 9054d50 to a881547 Compare September 2, 2026 04:10
host_build_graph builds its graph on the host: the orchestration .so that drives
it is dlopened by the host runtime, and the AICPU only ever runs schedulers. The
sources implementing that orchestration nonetheless sat under shared/, so the
aicpu target compiled all of them -- the ops table, the whole submit path,
TensorMap, and Graph recording -- 1.6 MB of a 4.8 MB device image no device code
can reach. Nothing under aicpu/, runtime/ or device/ names OrchestratorState or
ChipTensorMap, and the AICPU .so gains no undefined symbol on any of the four
variants once they are gone, which is what pins that claim.

runtime_core.cpp, orchestrator.cpp and tensormap.cpp move under host/, which the
build config already excludes from the aicpu target, so no build file changes.
OrchestratorState::init goes with them: it calls ChipTensorMap::init_default, and
left in shared/runtime_init.cpp it would have given the AICPU an unresolved
reference -- which a shared library reports at load time rather than at link
time. The AICPU no longer rebinds the ops table at boot, and the host clears
rt->ops alongside rt->orchestrator before the copied zone is uploaded, so the
device never receives a host address in that field.

With one target compiling them, the weak markers those files carried select
nothing; they only hid which definition wins behind link order, where nothing
checks it, and a missing sink linked cleanly and silently did nothing.
get_sys_cnt_aicpu and get_reg_ptr become ordinary definitions in
host/aicpu_shims.cpp -- on the host neither is a fallback, since host
orchestration needs a real monotonic clock and route_ready_once ODR-uses the
doorbell inline -- and the clock's three copies collapse into one. The dep_gen
and host_phase no-ops move to tests/ut/cpp/stubs/, carried by
HBG_ORCH_SHARED_SOURCES, which the one test that wants the real capture does not
use; that split is exclusive, so those need no weak marker either.

RuntimeOps was written out three times, once per arch's orchestration_api.h and
once in runtime_core.h, and the copies had to agree field for field since the .so
calls through the table by offset. runtime_ops.h carries the definition and both
sides include it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant