diff --git a/src/a2a3/platform/include/aicpu/platform_regs.h b/src/a2a3/platform/include/aicpu/platform_regs.h index b34ba35500..392f0ecc30 100644 --- a/src/a2a3/platform/include/aicpu/platform_regs.h +++ b/src/a2a3/platform/include/aicpu/platform_regs.h @@ -67,10 +67,10 @@ void set_platform_pmu_reg_addrs(uint64_t pmu_regs); uint64_t get_platform_pmu_reg_addrs(); /** - * Set the ACL device ordinal for the current run. Pushed by the platform layer - * (kernel.cpp) before aicpu_execute() from KernelArgs.device_id; the executor - * reads it to make the staged orchestration SO filename unique per device so - * paired dies sharing the preinstall filesystem never collide. + * Set the ACL device ordinal. Latched once per device by simpler_aicpu_init + * (from InitArgs.device_id) into this resident-SO global; the executor reads it + * to make the staged orchestration SO filename unique per device so paired dies + * sharing the preinstall filesystem never collide. */ void set_orch_device_id(int device_id); diff --git a/src/a2a3/platform/include/common/kernel_args.h b/src/a2a3/platform/include/common/kernel_args.h index 0f4046fc8f..2ccd86825d 100644 --- a/src/a2a3/platform/include/common/kernel_args.h +++ b/src/a2a3/platform/include/common/kernel_args.h @@ -86,9 +86,16 @@ extern "C" { * - AICore: receives device KernelArgs* via KERNEL_ENTRY */ struct KernelArgs { + // Offset-locked front: the front-less launch protocol and the device + // entries require runtime_args @ 0 and regs @ 8 (see static_asserts below). __may_used_by_aicore__ Runtime *runtime_args{nullptr}; // Task runtime in device memory uint64_t regs{0}; // Per-core register base address array (platform-specific) - uint64_t ffts_base_addr{0}; // FFTS base address for AICore + // Remaining 64-bit fields. Grouped before the 32-bit tail so the struct + // needs no interior alignment padding — every uint64_t lands on its natural + // 8-byte boundary and the lone trailing uint32_t carries only harmless tail + // padding. Order among these is free (device reads by field name, not + // offset); only runtime_args/regs are offset-locked. + uint64_t ffts_base_addr{0}; // FFTS base address for AICore uint64_t dump_data_base{0}; // Dump shared memory base address; use explicit flags to detect enablement // L2 swimlane shared memory base address; use explicit flags to detect enablement uint64_t l2_swimlane_data_base{0}; @@ -102,9 +109,6 @@ struct KernelArgs { // L2SwimlaneAicoreTaskBuffer address. AICore kernel entry indexes by block_idx // and forwards into platform set/get state. 0 when L2 swimlane is off. uint64_t l2_swimlane_aicore_rotation_table{0}; - uint32_t enable_profiling_flag{0}; // Profiling umbrella bitmask; dump_tensor|l2_swimlane|pmu|dep_gen|scope_stats - uint32_t _pad{0}; // Alignment padding - // Device pointer to the run-wall buffer the platform AICPU entry writes. // Allocated once and kept resident, reset each run. Onboard AICPU receives // KernelArgs as a CANN-private copy (see launch_aicpu_kernel), so an @@ -118,11 +122,8 @@ struct KernelArgs { // single-uint64 wall_ns write-through (sim AICPU and host share memory). // Zero when the buffer was not allocated. uint64_t device_wall_data_base{0}; - // ACL device ordinal. Pushed to the AICPU so the executor can suffix the - // staged orchestration SO name (libdevice_orch___.so): - // paired a2a3 dies share the preinstall filesystem, and a content/pid-only - // name risks a cross-die write/execute collision (see simpler_inner fix). - uint32_t device_id{0}; + // 32-bit tail. + uint32_t enable_profiling_flag{0}; // Profiling umbrella bitmask; dump_tensor|l2_swimlane|pmu|dep_gen|scope_stats }; static_assert(offsetof(KernelArgs, runtime_args) == 0, "KernelArgs::runtime_args offset drift"); diff --git a/src/a2a3/platform/onboard/aicpu/kernel.cpp b/src/a2a3/platform/onboard/aicpu/kernel.cpp index 8a634821a3..3a081299e5 100644 --- a/src/a2a3/platform/onboard/aicpu/kernel.cpp +++ b/src/a2a3/platform/onboard/aicpu/kernel.cpp @@ -35,9 +35,10 @@ // wall = max(end) - min(start). No single-threaded pre-pass is needed to // seed the start. -// Forward declaration of aicpu_execute (implemented in aicpu_executor.cpp) +// Forward declaration of aicpu_execute (implemented in aicpu_executor.cpp). +// simpler_aicpu_register_callable is NOT declared/forwarded here: it is +// exported directly by the TMARB runtime (host_build_graph does not export it). extern "C" int aicpu_execute(Runtime *arg); -extern "C" int aicpu_register_callable(const RegisterCallableArgs *arg); /** * AICPU kernel main execution entry point. @@ -151,21 +152,3 @@ extern "C" __attribute__((visibility("default"))) int simpler_aicpu_init(void *a LOG_INFO_V0("%s", "simpler_aicpu_init: per-device invariants latched"); return 0; } - -extern "C" __attribute__((visibility("default"))) int simpler_aicpu_register_callable(void *arg) { - if (arg == nullptr) { - LOG_ERROR("%s", "Invalid register_callable kernel arguments: null pointer"); - return -1; - } - - RegisterCallableArgs *reg_args = reinterpret_cast(arg); - - LOG_INFO_V0("%s", "simpler_aicpu_register_callable: registering callable"); - int rc = aicpu_register_callable(reg_args); - if (rc != 0) { - LOG_ERROR("simpler_aicpu_register_callable: registration failed with rc=%d", rc); - return rc; - } - LOG_INFO_V0("%s", "simpler_aicpu_register_callable: registration completed"); - return 0; -} diff --git a/src/a2a3/platform/sim/host/device_runner.cpp b/src/a2a3/platform/sim/host/device_runner.cpp index 4e353a2806..d02dc1ad61 100644 --- a/src/a2a3/platform/sim/host/device_runner.cpp +++ b/src/a2a3/platform/sim/host/device_runner.cpp @@ -94,7 +94,7 @@ int DeviceRunner::ensure_binaries_loaded() { }; if (!load_sym("aicpu_execute", reinterpret_cast(&aicpu_execute_func_))) return -1; - load_optional_sym("aicpu_register_callable", reinterpret_cast(&aicpu_register_callable_func_)); + load_optional_sym("simpler_aicpu_register_callable", reinterpret_cast(&aicpu_register_callable_func_)); if (!load_sym("set_platform_regs", reinterpret_cast(&set_platform_regs_func_))) return -1; load_optional_sym("set_orch_device_id", reinterpret_cast(&set_orch_device_id_func_)); if (!load_sym("set_platform_dump_base", reinterpret_cast(&set_platform_dump_base_func_))) return -1; diff --git a/src/a2a3/platform/sim/host/device_runner.h b/src/a2a3/platform/sim/host/device_runner.h index d2c7320ec8..726475406a 100644 --- a/src/a2a3/platform/sim/host/device_runner.h +++ b/src/a2a3/platform/sim/host/device_runner.h @@ -55,7 +55,9 @@ class DeviceRunner : public SimDeviceRunnerBase { // a2a3 sim's dlsym'd function-pointer table. Loaded once via // ensure_binaries_loaded(), nulled on unload_executor_binaries(). int (*aicpu_execute_func_)(Runtime *){nullptr}; - int (*aicpu_register_callable_func_)(const RegisterCallableArgs *){nullptr}; + // The runtime exports simpler_aicpu_register_callable(void*) directly (TMARB + // only; hbg does not export it). Optional dlsym: null on the hbg SO. + int (*aicpu_register_callable_func_)(void *){nullptr}; void (*aicore_execute_func_)(Runtime *, int, CoreType, uint32_t, uint64_t, uint32_t, uint64_t){nullptr}; void (*set_platform_regs_func_)(uint64_t){nullptr}; void (*set_orch_device_id_func_)(int){nullptr}; diff --git a/src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp b/src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp index 428f4b0fc4..acae2775d2 100644 --- a/src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp +++ b/src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp @@ -22,7 +22,6 @@ #include "aicpu/pmu_collector_aicpu.h" #include "aicpu/tensor_dump_aicpu.h" #include "callable.h" -#include "common/kernel_args.h" #include "common/memory_barrier.h" #include "common/l2_swimlane_profiling.h" #include "common/platform_config.h" @@ -1308,12 +1307,10 @@ void AicpuExecutor::diagnose_stuck_state( // ===== Public Entry Point ===== -extern "C" int aicpu_register_callable(const RegisterCallableArgs *args) { - // host_build_graph resolves orchestration on the host during prepare. - // There is no AICPU orch_so_table_ state to register. - (void)args; - return 0; -} +// host_build_graph resolves orchestration on the host during prepare, so it has +// no device-side registration: it deliberately does NOT export +// simpler_aicpu_register_callable (only the TMARB runtime does). The host's +// register launch is gated on the device-orch path and never targets hbg. /** * aicpu_execute - Main AICPU kernel execution entry point diff --git a/src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp b/src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp index 97d74c630e..69b114effa 100644 --- a/src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp +++ b/src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp @@ -504,6 +504,17 @@ int validate_runtime_impl(Runtime *runtime) { return rc; } +// host_build_graph resolves orchestration on the host, so it exports no AICPU +// entries beyond the base {simpler_aicpu_exec, simpler_aicpu_init} — in +// particular it does not export simpler_aicpu_register_callable. Reporting an +// empty extra-symbol set keeps the common AICPU loader from looking for it. +const char *const *runtime_extra_aicpu_symbols(size_t *count) { + if (count != nullptr) { + *count = 0; + } + return nullptr; +} + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/a2a3/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp b/src/a2a3/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp index e189853f10..fa4bcfe257 100644 --- a/src/a2a3/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp +++ b/src/a2a3/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp @@ -820,12 +820,17 @@ void AicpuExecutor::deinit(Runtime *runtime) { // ===== Public Entry Point ===== -extern "C" int32_t aicpu_register_callable(const RegisterCallableArgs *args) { - if (args == nullptr) { - LOG_ERROR("%s", "aicpu_register_callable: null RegisterCallableArgs pointer"); +// Device orchestration SO registration entry. Exported directly by the runtime +// (not via a platform forwarding shell): registration is a TMARB-only ability, +// so the symbol lives where the capability does. host_build_graph does not +// export it at all (host-side orchestration has nothing to register). +extern "C" __attribute__((visibility("default"))) int simpler_aicpu_register_callable(void *arg) { + if (arg == nullptr) { + LOG_ERROR("%s", "simpler_aicpu_register_callable: null RegisterCallableArgs pointer"); return -1; } - // `args` is the launch-arg payload CANN copies into the AICPU arg space + const RegisterCallableArgs *args = reinterpret_cast(arg); + // `arg` is the launch-arg payload CANN copies into the AICPU arg space // (same coherent channel exec reads KernelArgs fields from) — no HBM deref, // so unlike the old prewarm path there is no Runtime to cache-invalidate. int32_t rc = g_aicpu_executor.load_orch_so( @@ -833,10 +838,10 @@ extern "C" int32_t aicpu_register_callable(const RegisterCallableArgs *args) { args->device_orch_config_name, /*thread_idx=*/0 ); if (rc != 0) { - LOG_ERROR("aicpu_register_callable: SO load failed with rc=%d", rc); + LOG_ERROR("simpler_aicpu_register_callable: SO load failed with rc=%d", rc); return rc; } - LOG_INFO_V0("aicpu_register_callable: completed for callable_id=%d", args->active_callable_id); + LOG_INFO_V0("simpler_aicpu_register_callable: completed for callable_id=%d", args->active_callable_id); return 0; } diff --git a/src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp b/src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp index 8fd0f9f234..624060e357 100644 --- a/src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp +++ b/src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp @@ -743,3 +743,15 @@ extern "C" int validate_runtime_impl(Runtime *runtime) { return rc; } + +// Extra AICPU entry symbols this runtime exports beyond the base +// {simpler_aicpu_exec, simpler_aicpu_init}. TMARB resolves orchestration on the +// device, so it exports simpler_aicpu_register_callable; the common AICPU loader +// queries this so it carries no runtime-specific symbol knowledge. +extern "C" const char *const *runtime_extra_aicpu_symbols(size_t *count) { + static const char *const kExtra[] = {"simpler_aicpu_register_callable"}; + if (count != nullptr) { + *count = sizeof(kExtra) / sizeof(kExtra[0]); + } + return kExtra; +} diff --git a/src/a5/platform/include/aicpu/platform_regs.h b/src/a5/platform/include/aicpu/platform_regs.h index 765cee220a..caad59443e 100644 --- a/src/a5/platform/include/aicpu/platform_regs.h +++ b/src/a5/platform/include/aicpu/platform_regs.h @@ -58,10 +58,10 @@ void set_platform_regs(uint64_t regs); uint64_t get_platform_regs(); /** - * Set the ACL device ordinal for the current run. Pushed by the platform layer - * (kernel.cpp) before aicpu_execute() from KernelArgs.device_id; the executor - * reads it to make the staged orchestration SO filename unique per device so - * paired dies sharing the preinstall filesystem never collide. + * Set the ACL device ordinal. Latched once per device by simpler_aicpu_init + * (from InitArgs.device_id) into this resident-SO global; the executor reads it + * to make the staged orchestration SO filename unique per device so paired dies + * sharing the preinstall filesystem never collide. */ void set_orch_device_id(int device_id); diff --git a/src/a5/platform/include/common/kernel_args.h b/src/a5/platform/include/common/kernel_args.h index 09993d1d44..70bb2a842f 100644 --- a/src/a5/platform/include/common/kernel_args.h +++ b/src/a5/platform/include/common/kernel_args.h @@ -75,8 +75,13 @@ extern "C" { * - AICore: receives device KernelArgs* via KERNEL_ENTRY */ struct KernelArgs { + // Offset-locked front: the front-less launch protocol and the device + // entries require runtime_args @ 0 and regs @ 8 (see static_asserts below). __may_used_by_aicore__ Runtime *runtime_args{nullptr}; // Task runtime in device memory uint64_t regs{0}; // Per-core register base address array (platform-specific) + // Remaining 64-bit fields grouped before the 32-bit tail so the struct needs + // no interior alignment padding. Order among these is free (device reads by + // field name, not offset); only runtime_args/regs are offset-locked. uint64_t dump_data_base{0}; // Dump shared memory base address; use explicit flags to detect enablement // L2 swimlane shared memory base address; use explicit flags to detect enablement uint64_t l2_swimlane_data_base{0}; @@ -91,14 +96,13 @@ struct KernelArgs { uint64_t scope_stats_data_base{0}; // ScopeStatsBuffer device pointer; 0 when scope_stats is off. // a5 has no halHostRegister — host keeps a separate shadow and // refreshes it via rtMemcpy DEVICE_TO_HOST at dump time. - uint32_t enable_profiling_flag{0}; // Profiling umbrella bitmask; dump_tensor|l2_swimlane|pmu|dep_gen|scope_stats - uint32_t _pad{0}; // Alignment padding - // Device pointer to an 8-byte buffer that the platform AICPU entry writes // the run-wall (ns) into. Allocated once at simpler_init, kept resident. // See the a2a3 kernel_args.h for the full design rationale (CANN's // AICPU args copy makes inline fields write-only). uint64_t device_wall_data_base{0}; + // 32-bit tail (two adjacent uint32_t — no interior padding). + uint32_t enable_profiling_flag{0}; // Profiling umbrella bitmask; dump_tensor|l2_swimlane|pmu|dep_gen|scope_stats // Opaque always-false guard read by the AICore SIMT meta anchor (AIV // KERNEL_ENTRY). The host never sets it non-zero; its only purpose is to be // a runtime-valued condition the compiler cannot constant-fold, so the diff --git a/src/a5/platform/onboard/aicpu/kernel.cpp b/src/a5/platform/onboard/aicpu/kernel.cpp index 41ccfb7e46..df61cd5451 100644 --- a/src/a5/platform/onboard/aicpu/kernel.cpp +++ b/src/a5/platform/onboard/aicpu/kernel.cpp @@ -35,9 +35,10 @@ // wall = max(end) - min(start). No single-threaded pre-pass is needed to // seed the start. -// Forward declaration of aicpu_execute (implemented in aicpu_executor.cpp) +// Forward declaration of aicpu_execute (implemented in aicpu_executor.cpp). +// simpler_aicpu_register_callable is NOT declared/forwarded here: it is +// exported directly by the TMARB runtime (host_build_graph does not export it). extern "C" int aicpu_execute(Runtime *arg); -extern "C" int aicpu_register_callable(const RegisterCallableArgs *arg); /** * AICPU kernel main execution entry point. @@ -162,21 +163,3 @@ extern "C" __attribute__((visibility("default"))) int simpler_aicpu_init(void *a LOG_INFO_V0("%s", "simpler_aicpu_init: per-device invariants latched"); return 0; } - -extern "C" __attribute__((visibility("default"))) int simpler_aicpu_register_callable(void *arg) { - if (arg == nullptr) { - LOG_ERROR("%s", "Invalid register_callable kernel arguments: null pointer"); - return -1; - } - - RegisterCallableArgs *reg_args = reinterpret_cast(arg); - - LOG_INFO_V0("%s", "simpler_aicpu_register_callable: registering callable"); - int rc = aicpu_register_callable(reg_args); - if (rc != 0) { - LOG_ERROR("simpler_aicpu_register_callable: registration failed with rc=%d", rc); - return rc; - } - LOG_INFO_V0("%s", "simpler_aicpu_register_callable: registration completed"); - return 0; -} diff --git a/src/a5/platform/sim/host/device_runner.cpp b/src/a5/platform/sim/host/device_runner.cpp index e90b296051..0490d04358 100644 --- a/src/a5/platform/sim/host/device_runner.cpp +++ b/src/a5/platform/sim/host/device_runner.cpp @@ -105,7 +105,7 @@ int DeviceRunner::ensure_binaries_loaded() { }; if (!load_sym("aicpu_execute", reinterpret_cast(&aicpu_execute_func_))) return -1; - load_optional_sym("aicpu_register_callable", reinterpret_cast(&aicpu_register_callable_func_)); + load_optional_sym("simpler_aicpu_register_callable", reinterpret_cast(&aicpu_register_callable_func_)); if (!load_sym("set_platform_regs", reinterpret_cast(&set_platform_regs_func_))) return -1; load_optional_sym("set_orch_device_id", reinterpret_cast(&set_orch_device_id_func_)); if (!load_sym("set_platform_dump_base", reinterpret_cast(&set_platform_dump_base_func_))) return -1; diff --git a/src/a5/platform/sim/host/device_runner.h b/src/a5/platform/sim/host/device_runner.h index d74673292d..49b0c26239 100644 --- a/src/a5/platform/sim/host/device_runner.h +++ b/src/a5/platform/sim/host/device_runner.h @@ -57,7 +57,9 @@ class DeviceRunner : public SimDeviceRunnerBase { // a5 sim's dlsym'd function-pointer table. Loaded once via // ensure_binaries_loaded(), nulled on unload_executor_binaries(). int (*aicpu_execute_func_)(Runtime *){nullptr}; - int (*aicpu_register_callable_func_)(const RegisterCallableArgs *){nullptr}; + // The runtime exports simpler_aicpu_register_callable(void*) directly (TMARB + // only; hbg does not export it). Optional dlsym: null on the hbg SO. + int (*aicpu_register_callable_func_)(void *){nullptr}; void (*aicore_execute_func_)(Runtime *, int, CoreType, uint32_t, uint64_t, uint32_t, uint64_t, uint64_t){nullptr}; void (*set_platform_regs_func_)(uint64_t){nullptr}; void (*set_orch_device_id_func_)(int){nullptr}; diff --git a/src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp b/src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp index 91382cf8c4..7ff6ab2341 100644 --- a/src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp +++ b/src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp @@ -22,7 +22,6 @@ #include "aicpu/tensor_dump_aicpu.h" #include "aicpu/platform_regs.h" #include "callable.h" -#include "common/kernel_args.h" #include "common/memory_barrier.h" #include "common/l2_swimlane_profiling.h" #include "common/platform_config.h" @@ -1303,12 +1302,10 @@ void AicpuExecutor::diagnose_stuck_state( // ===== Public Entry Point ===== -extern "C" int aicpu_register_callable(const RegisterCallableArgs *args) { - // host_build_graph resolves orchestration on the host during prepare. - // There is no AICPU orch_so_table_ state to register. - (void)args; - return 0; -} +// host_build_graph resolves orchestration on the host during prepare, so it has +// no device-side registration: it deliberately does NOT export +// simpler_aicpu_register_callable (only the TMARB runtime does). The host's +// register launch is gated on the device-orch path and never targets hbg. /** * aicpu_execute - Main AICPU kernel execution entry point diff --git a/src/a5/runtime/host_build_graph/host/runtime_maker.cpp b/src/a5/runtime/host_build_graph/host/runtime_maker.cpp index 97d74c630e..69b114effa 100644 --- a/src/a5/runtime/host_build_graph/host/runtime_maker.cpp +++ b/src/a5/runtime/host_build_graph/host/runtime_maker.cpp @@ -504,6 +504,17 @@ int validate_runtime_impl(Runtime *runtime) { return rc; } +// host_build_graph resolves orchestration on the host, so it exports no AICPU +// entries beyond the base {simpler_aicpu_exec, simpler_aicpu_init} — in +// particular it does not export simpler_aicpu_register_callable. Reporting an +// empty extra-symbol set keeps the common AICPU loader from looking for it. +const char *const *runtime_extra_aicpu_symbols(size_t *count) { + if (count != nullptr) { + *count = 0; + } + return nullptr; +} + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/a5/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp b/src/a5/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp index 113cbde824..4c2fac6000 100644 --- a/src/a5/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp +++ b/src/a5/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp @@ -815,12 +815,17 @@ void AicpuExecutor::deinit(Runtime *runtime) { // ===== Public Entry Point ===== -extern "C" int32_t aicpu_register_callable(const RegisterCallableArgs *args) { - if (args == nullptr) { - LOG_ERROR("%s", "aicpu_register_callable: null RegisterCallableArgs pointer"); +// Device orchestration SO registration entry. Exported directly by the runtime +// (not via a platform forwarding shell): registration is a TMARB-only ability, +// so the symbol lives where the capability does. host_build_graph does not +// export it at all (host-side orchestration has nothing to register). +extern "C" __attribute__((visibility("default"))) int simpler_aicpu_register_callable(void *arg) { + if (arg == nullptr) { + LOG_ERROR("%s", "simpler_aicpu_register_callable: null RegisterCallableArgs pointer"); return -1; } - // `args` is the launch-arg payload CANN copies into the AICPU arg space + const RegisterCallableArgs *args = reinterpret_cast(arg); + // `arg` is the launch-arg payload CANN copies into the AICPU arg space // (same coherent channel exec reads KernelArgs fields from) — no HBM deref, // so unlike the old prewarm path there is no Runtime to cache-invalidate. int32_t rc = g_aicpu_executor.load_orch_so( @@ -828,10 +833,10 @@ extern "C" int32_t aicpu_register_callable(const RegisterCallableArgs *args) { args->device_orch_config_name, /*thread_idx=*/0 ); if (rc != 0) { - LOG_ERROR("aicpu_register_callable: SO load failed with rc=%d", rc); + LOG_ERROR("simpler_aicpu_register_callable: SO load failed with rc=%d", rc); return rc; } - LOG_INFO_V0("aicpu_register_callable: completed for callable_id=%d", args->active_callable_id); + LOG_INFO_V0("simpler_aicpu_register_callable: completed for callable_id=%d", args->active_callable_id); return 0; } diff --git a/src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp b/src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp index d785cef018..63b55a558b 100644 --- a/src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp +++ b/src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp @@ -734,3 +734,15 @@ extern "C" int validate_runtime_impl(Runtime *runtime) { return rc; } + +// Extra AICPU entry symbols this runtime exports beyond the base +// {simpler_aicpu_exec, simpler_aicpu_init}. TMARB resolves orchestration on the +// device, so it exports simpler_aicpu_register_callable; the common AICPU loader +// queries this so it carries no runtime-specific symbol knowledge. +extern "C" const char *const *runtime_extra_aicpu_symbols(size_t *count) { + static const char *const kExtra[] = {"simpler_aicpu_register_callable"}; + if (count != nullptr) { + *count = sizeof(kExtra) / sizeof(kExtra[0]); + } + return kExtra; +} diff --git a/src/common/aicpu_loader/host/load_aicpu_op.cpp b/src/common/aicpu_loader/host/load_aicpu_op.cpp index 612cf1b57b..e456717d18 100644 --- a/src/common/aicpu_loader/host/load_aicpu_op.cpp +++ b/src/common/aicpu_loader/host/load_aicpu_op.cpp @@ -253,20 +253,20 @@ bool LoadAicpuOp::GenerateAicpuOpJson(const std::string &json_path, const std::s LOG_ERROR("Failed to open JSON file for writing: %s", json_path.c_str()); return false; } - auto make_cfg = [&](const char *symbol_name) { + auto make_cfg = [&](const std::string &symbol_name) { AicpuOpConfig c; - c.opType = MakeUniqueOpType(symbol_name, inner_fp_); + c.opType = MakeUniqueOpType(symbol_name.c_str(), inner_fp_); c.functionName = symbol_name; c.kernelSo = kernel_so; c.opKernelLib = "AICPUKernel"; c.userDefined = "False"; return c; }; - std::vector op_configs = { - make_cfg(KernelNames::RunName), - make_cfg(KernelNames::InitName), - make_cfg(KernelNames::RegisterCallableName), - }; + std::vector op_configs; + op_configs.reserve(kernel_symbols_.size()); + for (const std::string &sym : kernel_symbols_) { + op_configs.push_back(make_cfg(sym)); + } json_file << "{\n"; for (size_t i = 0; i < op_configs.size(); ++i) { const auto &c = op_configs[i]; @@ -287,12 +287,18 @@ bool LoadAicpuOp::GenerateAicpuOpJson(const std::string &json_path, const std::s return true; } -int LoadAicpuOp::Init() { +int LoadAicpuOp::Init(const std::vector &extra_symbols) { if (inner_fp_ == 0) { LOG_ERROR("LoadAicpuOp::Init: BootstrapDispatcher must be called first"); return -1; } + // Base entries are exported by every runtime; the runtime reports any extra + // entries it additionally exports (TMARB: register_callable; hbg: none), so + // this loader carries no runtime-specific symbol knowledge. + kernel_symbols_ = {KernelNames::RunName, KernelNames::InitName}; + kernel_symbols_.insert(kernel_symbols_.end(), extra_symbols.begin(), extra_symbols.end()); + // Per-process JSON path. /tmp is always writable. char json_name_buf[128]; snprintf( @@ -350,9 +356,11 @@ int LoadAicpuOp::Init() { } LOG_INFO_V2("LoadAicpuOp: Loaded inner SO via JSON, handle=%p", binary_handle_); - const char *symbol_names[] = {KernelNames::RunName, KernelNames::InitName, KernelNames::RegisterCallableName}; - for (const char *name : symbol_names) { - std::string lookup_name = MakeUniqueOpType(name, inner_fp_); + // Resolve every registered symbol. The set is exactly what this runtime + // declares it exports (base + runtime-reported extras), so each one must + // resolve — a miss is a real build/registration error, not an optional gap. + for (const std::string &name : kernel_symbols_) { + std::string lookup_name = MakeUniqueOpType(name.c_str(), inner_fp_); rtFuncHandle func_handle = nullptr; rc = rtsFuncGetByName(binary_handle_, lookup_name.c_str(), &func_handle); if (rc != RT_ERROR_NONE) { @@ -363,7 +371,9 @@ int LoadAicpuOp::Init() { return rc; } func_handles_[name] = func_handle; - LOG_INFO_V2("LoadAicpuOp: resolved handle for %s (opType=%s): %p", name, lookup_name.c_str(), func_handle); + LOG_INFO_V2( + "LoadAicpuOp: resolved handle for %s (opType=%s): %p", name.c_str(), lookup_name.c_str(), func_handle + ); } binary_guard.release(); diff --git a/src/common/aicpu_loader/host/load_aicpu_op.h b/src/common/aicpu_loader/host/load_aicpu_op.h index d88f490550..d8de4ce249 100644 --- a/src/common/aicpu_loader/host/load_aicpu_op.h +++ b/src/common/aicpu_loader/host/load_aicpu_op.h @@ -48,6 +48,7 @@ #include #include #include +#include #include "common/kernel_args.h" #include "runtime/runtime/rts/rts_kernel.h" @@ -106,8 +107,17 @@ class LoadAicpuOp { rtStream_t stream, int device_id ); - /** @brief JSON-register the runtime SO and resolve its entry handles. */ - int Init(); + /** + * @brief JSON-register the runtime SO and resolve its entry handles. + * + * @param extra_symbols Runtime-specific AICPU entry symbols beyond the base + * set ({RunName, InitName}, exported by every runtime). + * Each runtime's host part reports what it additionally + * exports — e.g. TMARB adds RegisterCallableName, while + * host_build_graph reports none. This keeps the common + * loader free of any runtime-specific symbol knowledge. + */ + int Init(const std::vector &extra_symbols); /** @brief Release binary handle + function handles + temporary JSON. */ void Finalize(); @@ -132,6 +142,9 @@ class LoadAicpuOp { uint64_t inner_fp_ = 0; int device_id_ = 0; std::string inner_so_basename_; + // Full set of AICPU entry symbols to JSON-register and resolve: the base + // {RunName, InitName} plus the runtime-reported extras passed to Init(). + std::vector kernel_symbols_; bool GenerateAicpuOpJson(const std::string &json_path, const std::string &kernel_so); int AicpuKernelLaunch(rtFuncHandle func_handle, rtStream_t stream, void *args, size_t args_size, int aicpu_num); diff --git a/src/common/log/host_log.cpp b/src/common/log/host_log.cpp index 51d2de29bf..27474583b0 100644 --- a/src/common/log/host_log.cpp +++ b/src/common/log/host_log.cpp @@ -129,8 +129,8 @@ void HostLogger::log_info_v(int v, const char *func, const char *fmt, ...) { // Called once early in ChipWorker::init (before host_runtime.so is even // dlopen'd) to seed the process-wide HostLogger from the user's // `simpler` Python logger snapshot. Consumers that need the current value -// later (host_runtime.so populating KernelArgs.log_level) read it via -// HostLogger::get_instance().level() / .info_v() directly; the value never +// later (host_runtime.so populating InitArgs.log_level at device init) read it +// via HostLogger::get_instance().level() / .info_v() directly; the value never // has to travel through any other SO's C ABI. // // Severity layout matches CANN dlog (0=DEBUG..4=NUL); info_v ∈ [0,9]. diff --git a/src/common/log/include/host_log.h b/src/common/log/include/host_log.h index bb9295b3df..3776a118a9 100644 --- a/src/common/log/include/host_log.h +++ b/src/common/log/include/host_log.h @@ -69,7 +69,7 @@ class HostLogger { void set_info_v(int v); // Raw getters. host_runtime.so reads these via the RTLD_GLOBAL singleton - // when populating KernelArgs.log_level / log_info_v at run time — that + // when populating InitArgs.log_level / log_info_v at device init — that // way the log configuration only lives in this one place (libsimpler_log.so) // and never has to be pushed across the host_runtime.so C ABI separately. int level() const; // returns the underlying LogLevel as int (0..4) diff --git a/src/common/platform/include/aicpu/device_log.h b/src/common/platform/include/aicpu/device_log.h index 4269182d3f..a57f5d9a8a 100644 --- a/src/common/platform/include/aicpu/device_log.h +++ b/src/common/platform/include/aicpu/device_log.h @@ -19,9 +19,9 @@ * onboard fills it from CheckLogLevel(AICPU,...) (CANN-managed), * sim fills it from set_log_level() called by the host (dlsym path). * - INFO verbosity gating (V0..V9) is simpler-managed on both backends: - * g_log_info_v populated from set_log_info_v(); onboard receives the - * value via KernelArgs.log_info_v at kernel entry, sim receives it via - * dlsym from the host runner. + * g_log_info_v populated from set_log_info_v(); onboard latches the value + * once per device from InitArgs.log_info_v via simpler_aicpu_init, sim + * receives it via dlsym from the host runner. * * Platform Support: * - a5 : Real hardware with CANN dlog API diff --git a/src/common/platform/onboard/aicpu/device_log.cpp b/src/common/platform/onboard/aicpu/device_log.cpp index 44f779bc17..494dd8a0ad 100644 --- a/src/common/platform/onboard/aicpu/device_log.cpp +++ b/src/common/platform/onboard/aicpu/device_log.cpp @@ -18,8 +18,8 @@ * only authoritative source on the AICPU). * * Verbosity (V0..V9) is simpler-managed: g_log_info_v is set by - * set_log_info_v() from the host-published KernelArgs.log_info_v before each - * kernel run. + * set_log_info_v(), latched once per device from InitArgs.log_info_v by + * simpler_aicpu_init (not re-pushed per run). */ #include "aicpu/device_log.h" diff --git a/src/common/platform/onboard/host/device_runner_base.cpp b/src/common/platform/onboard/host/device_runner_base.cpp index 4dc2a46b43..f7fd594c47 100644 --- a/src/common/platform/onboard/host/device_runner_base.cpp +++ b/src/common/platform/onboard/host/device_runner_base.cpp @@ -49,6 +49,12 @@ // `print_handshake_results` / `bind_callable_to_runtime` / // `prepare_orch_so`. +// Implemented by each runtime's host part (runtime_maker.cpp). Reports the +// AICPU entry symbols this runtime exports beyond the base {exec, init} set, so +// the common AICPU loader carries no runtime-specific symbol knowledge. TMARB +// returns simpler_aicpu_register_callable; host_build_graph returns none. +extern "C" const char *const *runtime_extra_aicpu_symbols(size_t *count); + namespace { HostRuntimeTimeoutConfig resolve_onboard_timeout_config() { @@ -426,8 +432,16 @@ int DeviceRunnerBase::ensure_binaries_loaded() { } LOG_INFO_V2("DeviceRunner: inner SO uploaded to preinstall via dispatcher bootstrap"); - // JSON-register the inner SO and resolve its runtime entry handles. - rc = load_aicpu_op_.Init(); + // JSON-register the inner SO and resolve its runtime entry handles. The + // runtime reports any AICPU entries it exports beyond the base set so the + // loader stays runtime-agnostic. + std::vector extra_symbols; + size_t extra_count = 0; + const char *const *extra = runtime_extra_aicpu_symbols(&extra_count); + for (size_t i = 0; i < extra_count && extra != nullptr; ++i) { + if (extra[i] != nullptr) extra_symbols.emplace_back(extra[i]); + } + rc = load_aicpu_op_.Init(extra_symbols); if (rc != 0) { LOG_ERROR("LoadAicpuOp::Init failed: %d", rc); return rc; diff --git a/src/common/platform/onboard/host/device_runner_base.h b/src/common/platform/onboard/host/device_runner_base.h index 3567640e4c..0ac203d253 100644 --- a/src/common/platform/onboard/host/device_runner_base.h +++ b/src/common/platform/onboard/host/device_runner_base.h @@ -611,13 +611,11 @@ class DeviceRunnerBase : public L3L2OrchCommBackend { void read_device_wall_ns(); /** - * H2D the Runtime struct via `kernel_args_.init_runtime_args` and - * publish log config + device ordinal into KernelArgs. AICPU reads - * these at launch — log_level / log_info_v are sourced from - * `HostLogger::get_instance()` (the single source of truth seeded - * by `simpler_log_init` before host_runtime.so loaded); device_id - * is the per-device suffix the AICPU executor uses for the - * per-device orchestration-SO name. + * H2D the Runtime struct via `kernel_args_.init_runtime_args`. Log config + * and device ordinal are NOT published here: they are per-device invariants + * latched once into the AICPU SO globals by `simpler_aicpu_init` + * (`ensure_aicpu_init_launched`) at device init, not carried per-run on + * KernelArgs. * * @return 0 on success, the underlying init_runtime_args rc on failure. */