diff --git a/docs/chip-level-arch.md b/docs/chip-level-arch.md index 06dd64445d..1560926937 100644 --- a/docs/chip-level-arch.md +++ b/docs/chip-level-arch.md @@ -105,20 +105,28 @@ The PTO Runtime consists of **three separate programs** that communicate through DeviceRunner runner; void *ptr = runner.allocate_tensor(bytes); runner.copy_to_device(dev_ptr, host_ptr, bytes); -runner.run(runtime, block_dim, device_id, aicpu_binary, aicore_binary, launch_aicpu_num); +runner.set_executors(aicpu_binary, aicore_binary); // once, at init time +runner.run(runtime, block_dim, launch_aicpu_num); runner.finalize(); ``` ### Layer 2: C API (`src/common/worker/pto_runtime_c_api.h`) ```c +// libsimpler_log.so (RTLD_GLOBAL, loaded first): +simpler_log_init(log_level, log_info_v); // seed HostLogger once + +// host_runtime.so (RTLD_LOCAL, loaded after): DeviceContextHandle ctx = create_device_context(); -simpler_init(ctx, device_id, log_level, log_info_v); // attach + log config +simpler_init(ctx, device_id, // attach + binary takeover + aicpu_binary, aicpu_size, + aicore_binary, aicore_size); size_t size = get_runtime_size(); -run_runtime(ctx, runtime, callable, args, block_dim, - aicpu_thread_num, device_id, - aicpu_binary, aicpu_size, aicore_binary, aicore_size, - enable_l2_swimlane, enable_dump_tensor, enable_pmu); +prepare_callable(ctx, cid, callable); // one-time per callable +run_prepared(ctx, runtime, cid, args, block_dim, // per-launch — no binaries + aicpu_thread_num, + enable_l2_swimlane, enable_dump_tensor, enable_pmu, output_prefix); +unregister_callable(ctx, cid); finalize_device(ctx); destroy_device_context(ctx); ``` @@ -172,12 +180,16 @@ Python test_*.py (SceneTestCase) │ └─→ ChipWorker() └─→ init(host_path, aicpu_path, aicore_path, simpler_log_path, device_id) + ├─→ dlopen(libsimpler_log.so) RTLD_GLOBAL + ├─→ simpler_log_init(log_level, log_info_v) → HostLogger seeded ├─→ dlopen(host.so) → resolve C API symbols via dlsym ├─→ create_device_context() → DeviceContextHandle - └─→ simpler_init(ctx, device_id, log_level, log_info_v) - └─→ DeviceRunner::attach_current_thread(device_id) - ├─→ rtSetDevice(device_id) on onboard - └─→ pto_cpu_sim_bind+acquire on sim + └─→ simpler_init(ctx, device_id, aicpu*, aicpu_size, aicore*, aicore_size) + ├─→ DeviceRunner::attach_current_thread(device_id) + │ ├─→ rtSetDevice(device_id) on onboard + │ └─→ pto_cpu_sim_bind+acquire on sim + ├─→ DeviceRunner::set_executors(aicpu, aicore) + └─→ (onboard) dlog_setlevel(HostLogger.level()) ``` ### 2. Initialization Phase diff --git a/docs/dynamic-linking.md b/docs/dynamic-linking.md index 63a63b09cf..89d7840966 100644 --- a/docs/dynamic-linking.md +++ b/docs/dynamic-linking.md @@ -258,23 +258,28 @@ different tasks have different configurations. ### Simulation (in-process, per-task) ```text -ChipWorker.init(host_path, aicpu_path, aicore_path, device_id) - dlopen(host_runtime.so, RTLD_GLOBAL) +ChipWorker.init(host_path, aicpu_path, aicore_path, simpler_log_path, device_id) + dlopen(libsimpler_log.so, RTLD_GLOBAL) + simpler_log_init(log_level, log_info_v) seeds HostLogger before host_runtime + dlopen(host_runtime.so, RTLD_LOCAL) dlsym: create_device_context, destroy_device_context, simpler_init, - get_runtime_size, run_runtime, finalize_device + get_runtime_size, prepare_callable, run_prepared, unregister_callable, + finalize_device create_device_context() → DeviceContextHandle - simpler_init(ctx, device_id, log_level, log_info_v) + simpler_init(ctx, device_id, aicpu*, aicpu_size, aicore*, aicore_size) DeviceRunner::attach_current_thread(device_id) pto_cpu_sim_bind_device(device_id) pto_cpu_sim_acquire_device(device_id) + DeviceRunner::set_executors(aicpu, aicore) binaries owned by runner -ChipWorker.run(callable, args, config) - run_runtime(ctx, buf, callable, args, ...) +ChipWorker.run(cid, args, config) + run_prepared(ctx, buf, cid, args, block_dim, aicpu_thread_num, …) new (buf) Runtime() - init_runtime_impl(r, callable, args) build graph, upload kernels - DeviceRunner::run(r, ...) + bind_prepared_callable_to_runtime(r, cid) restore kernel/orch addrs + bind_prepared_to_runtime_impl(r, args) + DeviceRunner::run(r, block_dim, aicpu_thread_num) clear_cpu_sim_shared_storage() - ensure_binaries_loaded() dlopen aicpu/aicore SOs + ensure_binaries_loaded() dlopen aicpu/aicore SOs once launch AICPU + AICore threads join all threads unload_executor_binaries() dlclose aicpu/aicore SOs @@ -292,23 +297,32 @@ ChipWorker.finalize() ```text device_worker_main(device_id) for each runtime_group: - ChipWorker.init(host_path, aicpu_path, aicore_path, device_id) - dlopen(host_runtime.so, RTLD_GLOBAL) + ChipWorker.init(host_path, aicpu_path, aicore_path, simpler_log_path, device_id) + dlopen(libsimpler_log.so, RTLD_GLOBAL) + simpler_log_init(log_level, log_info_v) + dlopen(host_runtime.so, RTLD_LOCAL) create_device_context() - simpler_init(ctx, device_id, log_level, log_info_v) + simpler_init(ctx, device_id, aicpu*, aicpu_size, aicore*, aicore_size) DeviceRunner::attach_current_thread(device_id) rtSetDevice() - - for each task in group: - ChipWorker.run(callable, args, config) - run_runtime(ctx, buf, callable, args, ...) - new (buf) Runtime() - init_runtime_impl() rtMalloc, rtMemcpy to device - DeviceRunner::run() - ensure_binaries_loaded() rtMemcpy AICPU SO to HBM (once) - rtAicpuKernelLaunchExWithArgs() launch on device - rtStreamSynchronize() wait for completion - launch_aicore_kernel() rtRegisterAllKernel + rtKernelLaunch - validate_runtime_impl() rtMemcpy results back to host + DeviceRunner::set_executors(aicpu, aicore) + dlog_setlevel(HostLogger.level()) sync CANN dlog + + for each callable: + ChipWorker.prepare_callable(cid, callable) + prepare_callable(ctx, cid, callable) + upload child kernels, copy orch SO to device buffer + for each launch with that cid: + ChipWorker.run(cid, args, config) + run_prepared(ctx, buf, cid, args, block_dim, aicpu_thread_num, …) + new (buf) Runtime() + bind_prepared_callable_to_runtime() + bind_prepared_to_runtime_impl() rtMalloc, rtMemcpy to device + DeviceRunner::run() + ensure_binaries_loaded() rtMemcpy AICPU SO to HBM (once) + rtAicpuKernelLaunchExWithArgs() launch on device + rtStreamSynchronize() wait for completion + launch_aicore_kernel() rtRegisterAllKernel + rtKernelLaunch + validate_runtime_impl() rtMemcpy results back to host ChipWorker.finalize() finalize_device(ctx) rtDeviceReset() diff --git a/docs/logging.md b/docs/logging.md index d001e284e5..b367c2dff1 100644 --- a/docs/logging.md +++ b/docs/logging.md @@ -17,15 +17,21 @@ Python: logging.getLogger("simpler").setLevel(N) ChipWorker.init(host_lib, aicpu, aicore, simpler_log_lib, sim_ctx_lib, sev, v) │ 1. dlopen libsimpler_log.so RTLD_GLOBAL ◀── one HostLogger per process - 2. dlopen libcpu_sim_context RTLD_GLOBAL (sim only) - 3. dlopen libhost_runtime.so RTLD_LOCAL ──→ undefined HostLogger / + 2. simpler_log_init(sev, v) ──→ HostLogger.set_level/set_info_v + (seeds HostLogger BEFORE any host_runtime / + sim_context / aicore SO is dlopen'd, so + any LOG_* macro firing during dlopen-time + constructors already sees the right filter) + 3. dlopen libcpu_sim_context RTLD_GLOBAL (sim only) + 4. dlopen libhost_runtime.so RTLD_LOCAL ──→ undefined HostLogger / unified_log_* symbols resolve via (1) - 4. simpler_init(ctx, sev, v) ──→ HostLogger.set_level/set_info_v - ──→ runner snapshots (sev, v) into KernelArgs - ──→ (onboard) dlog_setlevel via CANN + 5. simpler_init(ctx, device_id, aicpu*, aicore*) + ──→ attach thread + transfer executor binaries + ──→ (onboard) dlog_setlevel(HostLogger.level()) Per kernel launch: + runner reads HostLogger.level() / .info_v() ──→ KernelArgs.log_level/info_v AICPU receives sev/v in KernelArgs → sets g_is_log_enable_* + g_log_info_v ``` @@ -147,13 +153,18 @@ symbols against this single instance via `RTLD_GLOBAL` load order. void ChipWorker::init(host_lib_path, aicpu_path, aicore_path, simpler_log_lib_path, sim_context_lib_path, sev, v) { ensure_simpler_log_loaded(simpler_log_lib_path); // 1: RTLD_NOW | RTLD_GLOBAL + simpler_log_init_fn(sev, v); // 2: seed HostLogger BEFORE + // any consumer SO is opened if (!sim_context_lib_path.empty()) - ensure_sim_context_loaded(sim_context_lib_path);// 2: RTLD_NOW | RTLD_GLOBAL - handle = dlopen(host_lib_path, RTLD_NOW | RTLD_LOCAL); // 3: undefined HostLogger / + ensure_sim_context_loaded(sim_context_lib_path);// 3: RTLD_NOW | RTLD_GLOBAL + handle = dlopen(host_lib_path, RTLD_NOW | RTLD_LOCAL); // 4: undefined HostLogger / // unified_log_* resolve // via (1) - simpler_init_fn(device_ctx, sev, v); // pushes (sev, v) into the - // singleton + simpler_init_fn(device_ctx, device_id, + aicpu_bytes, aicpu_size, + aicore_bytes, aicore_size); // 5: attach thread + + // transfer binaries + + // (onboard) sync dlog } ``` @@ -217,9 +228,10 @@ CANN's level enum has no INFO sub-tiers. | ----- | ------ | ------ | | Python import | `_log.py` registers `V0..V9` / `NUL` with `logging.addLevelName`; sets `simpler` logger to V5 if untouched | `python/simpler/_log.py` | | `Worker.init()` | reads `simpler` logger's effective level, splits via `_split_threshold(t) → (sev, info_v)` | `python/simpler/_log.py:get_current_config()` | -| `ChipWorker.init()` | dlopen libsimpler_log → libsim_context → libhost_runtime; call `simpler_init` | `src/common/worker/chip_worker.cpp` | -| `simpler_init` (per platform) | `HostLogger.set_level/set_info_v`; runner snapshots for AICPU; (onboard) `dlog_setlevel` | `src/{arch}/platform/{onboard,sim}/host/pto_runtime_c_api.cpp` | -| Per kernel launch | runner writes `(sev, v)` into `KernelArgs`; AICPU `kernel.cpp` calls `set_log_level/set_log_info_v` on entry | `src/{arch}/platform/onboard/aicpu/kernel.cpp` | +| `ChipWorker.init()` | dlopen libsimpler_log → `simpler_log_init(sev,v)` (seeds HostLogger) → dlopen libsim_context → libhost_runtime → `simpler_init` | `src/common/worker/chip_worker.cpp` | +| `simpler_log_init` | `HostLogger.set_level/set_info_v` — only writer of log filter | `src/common/log/host_log.cpp` | +| `simpler_init` (per platform) | attach thread, transfer executor binaries to runner; (onboard) `dlog_setlevel(HostLogger.level())` | `src/{arch}/platform/{onboard,sim}/host/pto_runtime_c_api.cpp` | +| Per kernel launch | runner reads `HostLogger.level() / info_v()` directly, writes into `KernelArgs`; AICPU `kernel.cpp` calls `set_log_level/set_log_info_v` on entry | `src/{arch}/platform/onboard/aicpu/kernel.cpp` | The Python-side level snapshot is **one-shot** at `Worker.init()`. Calling `logger.setLevel(...)` afterwards has no effect on a live `ChipWorker` — diff --git a/docs/testing.md b/docs/testing.md index 5357f54c75..a3a2827089 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -168,11 +168,14 @@ visible by default; lower the threshold (e.g. `--log-level warn`) to hide them. formatters writing `%(levelname)s`) accept and emit them. - **Snapshot at `Worker.init()`, not per-run**: when a `Worker` is initialised it reads the current `simpler` logger level once and forwards it through - `ChipWorker.init(..., log_level, log_info_v)` to the platform SO's - `simpler_init`, which configures `HostLogger`, the runner's snapshot of the - values for AICPU `KernelArgs`, and (onboard) `dlog_setlevel`. **Subsequent - `logger.setLevel(...)` calls are not re-pushed to that worker** — recreate - the worker if you need to change levels mid-run. + `ChipWorker.init(..., log_level, log_info_v)`. ChipWorker then calls + libsimpler_log's `simpler_log_init` (which writes the values into the + process-wide `HostLogger` singleton) BEFORE `host_runtime.so` is dlopen'd; + the platform SO's `simpler_init` reads `HostLogger.level()` to sync CANN + `dlog` onboard, and per-launch the runner reads `HostLogger.level() / .info_v()` + directly when populating `KernelArgs`. **Subsequent `logger.setLevel(...)` + calls are not re-pushed to that worker** — recreate the worker if you need + to change levels mid-run. - L3 / L4 hierarchical workers fork chip subprocesses; the parent snapshots the same `(severity, info_v)` pair before `fork()` and passes it explicitly to `_chip_process_loop` so each subprocess starts its own `ChipWorker.init` @@ -184,9 +187,8 @@ The onboard AICPU library reads severity from CANN's `dlog` (CheckLogLevel), not from `KernelArgs.log_level`. Configure it via `ASCEND_GLOBAL_LOG_LEVEL=0..4` or `dlog_setlevel(-1, level, 0)`. `simpler_init` (called from `ChipWorker::init` in the platform SO) issues -`dlog_setlevel(-1, severity, 0)` automatically — derived from the snapshotted -simpler logger level — unless `ASCEND_GLOBAL_LOG_LEVEL` is already set in -the environment. The INFO **verbosity** sub-tier (V0..V9) is still +`dlog_setlevel(-1, HostLogger.level(), 0)` automatically — unless +`ASCEND_GLOBAL_LOG_LEVEL` is already set in the environment. The INFO **verbosity** sub-tier (V0..V9) is still controlled through the simpler logger and travels via `KernelArgs.log_info_v`. ### Behaviour change since the V0..V9 migration diff --git a/python/simpler/__init__.py b/python/simpler/__init__.py index bfa7a8690a..416ae2ab5b 100644 --- a/python/simpler/__init__.py +++ b/python/simpler/__init__.py @@ -8,10 +8,12 @@ # ----------------------------------------------------------------------------------------------------------- """Simpler runtime — public Python surface. -CANN dlog bootstrap and host-side log filter setup are performed by the -platform SO's `simpler_init` C entry, called once from `ChipWorker::init()` -with the snapshot of the `simpler` Python logger level. No Python-side -ctypes / dlopen is needed here. +Host-side log filter setup is performed via libsimpler_log.so's +`simpler_log_init` C entry (seeding the process-wide HostLogger); CANN dlog +bootstrap is performed by the platform SO's `simpler_init` reading off that +same HostLogger. Both are driven once from `ChipWorker::init()` with the +snapshot of the `simpler` Python logger level. No Python-side ctypes / +dlopen is needed here. """ # Importing _log auto-configures the simpler logger to V5 if unset. diff --git a/python/simpler/_log.py b/python/simpler/_log.py index 4ae8bf4f5e..bec7a25fb7 100644 --- a/python/simpler/_log.py +++ b/python/simpler/_log.py @@ -22,9 +22,11 @@ C++ side uses two axes (severity enum, info_v int) — `_split_threshold()` converts the Python integer into that pair, which `Worker.init()` forwards -to `ChipWorker::init(..., log_level, log_info_v)` once. The platform SO's -`simpler_init()` then propagates that snapshot to HostLogger, runner state, -and (onboard only) CANN dlog. +to `ChipWorker::init(..., log_level, log_info_v)` once. `ChipWorker::init` +calls libsimpler_log.so's `simpler_log_init()` to seed the process-wide +HostLogger; from then on the platform SO reads back through +`HostLogger::get_instance()` (populating `KernelArgs.log_level` / +`log_info_v` and, onboard only, syncing CANN dlog inside `simpler_init`). This module configures the "simpler" logger at import so that an unconfigured user gets the V5 default rather than Python's WARNING root inheritance. diff --git a/src/a2a3/platform/onboard/host/device_runner.cpp b/src/a2a3/platform/onboard/host/device_runner.cpp index 667a92410a..c6a83794f7 100644 --- a/src/a2a3/platform/onboard/host/device_runner.cpp +++ b/src/a2a3/platform/onboard/host/device_runner.cpp @@ -17,6 +17,8 @@ #include "device_runner.h" +#include "host_log.h" + #include #include @@ -253,17 +255,16 @@ std::thread DeviceRunner::create_thread(std::function fn) { }); } -int DeviceRunner::ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { - // First attach the current thread and create fresh run-scoped streams - int rc = prepare_run_context(device_id); +int DeviceRunner::ensure_device_initialized() { + // First attach the current thread and create fresh run-scoped streams. + // device_id_ was set in attach_current_thread() during simpler_init. + int rc = prepare_run_context(device_id_); if (rc != 0) { return rc; } // Then ensure binaries are loaded - return ensure_binaries_loaded(aicpu_so_binary, aicore_kernel_binary); + return ensure_binaries_loaded(); } int DeviceRunner::attach_current_thread(int device_id) { @@ -412,15 +413,10 @@ void DeviceRunner::release_run_context() { } } -int DeviceRunner::ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { - // Check if already loaded +int DeviceRunner::ensure_binaries_loaded() { + // Check if already loaded (binaries are owned by the runner via + // set_executors and live for the runner's lifetime). if (binaries_loaded_) { - // Just update kernel binary if different - if (aicore_kernel_binary_ != aicore_kernel_binary) { - aicore_kernel_binary_ = aicore_kernel_binary; - } return 0; } @@ -430,10 +426,8 @@ int DeviceRunner::ensure_binaries_loaded( return -1; } - aicore_kernel_binary_ = aicore_kernel_binary; - // Load AICPU SO - int rc = so_info_.init(aicpu_so_binary, mem_alloc_); + int rc = so_info_.init(aicpu_so_binary_, mem_alloc_); if (rc != 0) { LOG_ERROR("AicpuSoInfo::init failed: %d", rc); return rc; @@ -470,10 +464,7 @@ int DeviceRunner::copy_from_device(void *host_ptr, const void *dev_ptr, size_t b return rtMemcpy(host_ptr, bytes, dev_ptr, bytes, RT_MEMCPY_DEVICE_TO_HOST); } -int DeviceRunner::run( - Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num -) { +int DeviceRunner::run(Runtime &runtime, int block_dim, int launch_aicpu_num) { // Validate launch_aicpu_num if (launch_aicpu_num < 1 || launch_aicpu_num > PLATFORM_MAX_AICPU_THREADS) { LOG_ERROR("launch_aicpu_num (%d) must be in range [1, %d]", launch_aicpu_num, PLATFORM_MAX_AICPU_THREADS); @@ -511,7 +502,7 @@ int DeviceRunner::run( } // Ensure device is initialized (lazy initialization) - int rc = ensure_device_initialized(device_id, aicpu_so_binary, aicore_kernel_binary); + int rc = ensure_device_initialized(); if (rc != 0) { LOG_ERROR("ensure_device_initialized failed: %d", rc); return rc; @@ -550,7 +541,7 @@ int DeviceRunner::run( // Get AICore register addresses for register-based task dispatch rc = init_aicore_register_addresses( - &kernel_args_.args.regs, static_cast(device_id), mem_alloc_, AicoreRegKind::Ctrl + &kernel_args_.args.regs, static_cast(device_id_), mem_alloc_, AicoreRegKind::Ctrl ); if (rc != 0) { LOG_ERROR("init_aicore_register_addresses(Ctrl) failed: %d", rc); @@ -560,7 +551,7 @@ int DeviceRunner::run( // Get AICore PMU register addresses (distinct MMIO page from AIC_CTRL). if (enable_pmu_) { rc = init_aicore_register_addresses( - &kernel_args_.args.pmu_reg_addrs, static_cast(device_id), mem_alloc_, AicoreRegKind::Pmu + &kernel_args_.args.pmu_reg_addrs, static_cast(device_id_), mem_alloc_, AicoreRegKind::Pmu ); if (rc != 0) { LOG_ERROR("init_aicore_register_addresses(Pmu) failed: %d", rc); @@ -613,7 +604,7 @@ int DeviceRunner::run( // Initialize per-subsystem shared memory. if (enable_l2_swimlane_) { - rc = init_l2_perf(num_aicore, device_id); + rc = init_l2_perf(num_aicore, device_id_); if (rc != 0) { LOG_ERROR("init_l2_perf failed: %d", rc); return rc; @@ -622,7 +613,7 @@ int DeviceRunner::run( if (enable_dump_tensor_) { // Initialize tensor dump (independent from profiling) - rc = init_tensor_dump(runtime, device_id); + rc = init_tensor_dump(runtime, device_id_); if (rc != 0) { LOG_ERROR("init_tensor_dump failed: %d", rc); return rc; @@ -630,7 +621,7 @@ int DeviceRunner::run( } if (enable_pmu_) { - rc = init_pmu(num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id); + rc = init_pmu(num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id_); if (rc != 0) { LOG_ERROR("init_pmu failed: %d", rc); return rc; @@ -638,7 +629,7 @@ int DeviceRunner::run( } if (enable_dep_gen_) { - rc = init_dep_gen(launch_aicpu_num, device_id); + rc = init_dep_gen(launch_aicpu_num, device_id_); if (rc != 0) { LOG_ERROR("init_dep_gen failed: %d", rc); return rc; @@ -677,8 +668,11 @@ int DeviceRunner::run( } // Publish log config to AICPU via KernelArgs (severity floor + INFO verbosity). - kernel_args_.args.log_level = static_cast(log_level_); - kernel_args_.args.log_info_v = static_cast(log_info_v_); + // HostLogger is the single source of truth for log config (seeded by + // libsimpler_log.so via simpler_log_init before host_runtime.so was even + // dlopen'd). Read it directly when populating KernelArgs. + kernel_args_.args.log_level = static_cast(HostLogger::get_instance().level()); + kernel_args_.args.log_info_v = static_cast(HostLogger::get_instance().info_v()); rc = kernel_args_.init_ffts_base_addr(); if (rc != 0) { diff --git a/src/a2a3/platform/onboard/host/device_runner.h b/src/a2a3/platform/onboard/host/device_runner.h index 38e9f80219..2bb5fd00e7 100644 --- a/src/a2a3/platform/onboard/host/device_runner.h +++ b/src/a2a3/platform/onboard/host/device_runner.h @@ -248,15 +248,27 @@ class DeviceRunner { * @param runtime Runtime to execute (will be modified to * initialize workers) * @param block_dim Number of blocks (1 block = 1 AIC + 2 AIV) - * @param device_id Device ID (0-15) - * @param aicpu_so_binary Binary data of AICPU shared object - * @param aicore_kernel_binary Binary data of AICore kernel - * @param launch_aicpu_num Number of AICPU instances (default: 1) + * @param launch_aicpu_num Number of AICPU instances (default: 1) * @return 0 on success, error code on failure + * + * The bound device id, AICPU/AICore executor binaries, and log filter + * are captured once by simpler_init (binaries) / libsimpler_log.so (log) + * and read off DeviceRunner state / HostLogger here — no per-run args. */ - int - run(Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num = 1); + int run(Runtime &runtime, int block_dim, int launch_aicpu_num = 1); + + /** + * Take ownership of the AICPU + AICore executor binaries. Called once + * by simpler_init at ChipWorker::init time; subsequent run() invocations + * read from `aicpu_so_binary_` / `aicore_kernel_binary_`. + */ + void set_executors(std::vector aicpu_so_binary, std::vector aicore_kernel_binary) { + aicpu_so_binary_ = std::move(aicpu_so_binary); + aicore_kernel_binary_ = std::move(aicore_kernel_binary); + } + + /** The device id captured by simpler_init's attach_current_thread call. */ + int device_id() const { return device_id_; } /** * Enablement setters for the three diagnostics sub-features. Called by @@ -271,11 +283,6 @@ class DeviceRunner { pmu_event_type_ = resolve_pmu_event_type(enable_pmu); } void set_dep_gen_enabled(bool enable) { enable_dep_gen_ = enable; } - // Severity floor (0=DEBUG..4=NUL) and INFO verbosity threshold (0..9). - // Pushed in by the Python layer via run_runtime() and propagated to AICPU - // through KernelArgs. - void set_log_level(int log_level) { log_level_ = log_level; } - void set_log_info_v(int log_info_v) { log_info_v_ = log_info_v; } // Directory under which all diagnostic artifacts (l2_perf_records.json / // tensor_dump/ / pmu.csv) land. Required (non-empty) when any diagnostic // is enabled; CallConfig::validate() enforces this contract upstream. @@ -526,6 +533,9 @@ class DeviceRunner { int block_dim_{0}; int cores_per_blockdim_{PLATFORM_CORES_PER_BLOCKDIM}; int worker_count_{0}; // Stored for print_handshake_results in destructor + // Executor binaries — populated once via set_executors() during + // simpler_init, owned by this runner for the rest of its lifetime. + std::vector aicpu_so_binary_; std::vector aicore_kernel_binary_; // Memory management @@ -623,29 +633,20 @@ class DeviceRunner { * - Load AICPU SO to device memory * - Initialize device args * - * @param device_id Device ID (0-15) - * @param aicpu_so_binary Binary data of AICPU shared object - * @param aicore_kernel_binary Binary data of AICore kernel + * Reads the bound device id and executor binaries from runner state. * @return 0 on success, error code on failure */ - int ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); + int ensure_device_initialized(); /** * Load AICPU SO and initialize device args * - * Called by run() after prepare_run_context(). Performs: - * - Load AICPU SO to device memory - * - Initialize device args + * Called by run() after prepare_run_context(). Reads aicpu_so_binary_ / + * aicore_kernel_binary_ off the runner. * - * @param aicpu_so_binary Binary data of AICPU shared object - * @param aicore_kernel_binary Binary data of AICore kernel * @return 0 on success, error code on failure */ - int ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); + int ensure_binaries_loaded(); /** * Populate runtime.{dev_orch_so_addr_, dev_orch_so_size_} from @@ -736,8 +737,6 @@ class DeviceRunner { bool enable_dep_gen_{false}; PmuEventType pmu_event_type_{PmuEventType::PIPE_UTILIZATION}; // resolved from set_pmu_enabled() std::string output_prefix_{}; // diagnostic artifact root directory - int log_level_{1}; // 0=DEBUG..4=NUL; default INFO - int log_info_v_{5}; // INFO verbosity threshold; default V5 }; #endif // RUNTIME_DEVICERUNNER_H diff --git a/src/a2a3/platform/onboard/host/pto_runtime_c_api.cpp b/src/a2a3/platform/onboard/host/pto_runtime_c_api.cpp index 5cdb41a9a4..26ce8def01 100644 --- a/src/a2a3/platform/onboard/host/pto_runtime_c_api.cpp +++ b/src/a2a3/platform/onboard/host/pto_runtime_c_api.cpp @@ -46,7 +46,7 @@ int bind_prepared_to_runtime_impl(Runtime *runtime, const ChipStorageTaskArgs *o int validate_runtime_impl(Runtime *runtime); /* =========================================================================== - * Per-thread DeviceRunner binding (set by run_runtime, read by HostApi wrappers) + * Per-thread DeviceRunner binding (set by prepare_callable / run_prepared, read by HostApi wrappers) * =========================================================================== */ static pthread_key_t g_runner_key; @@ -208,12 +208,12 @@ void record_tensor_pair(RuntimeHandle runtime, void *host_ptr, void *dev_ptr, si r->record_tensor_pair(host_ptr, dev_ptr, size); } -int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_info_v) { +int simpler_init( + DeviceContextHandle ctx, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, + const uint8_t *aicore_binary, size_t aicore_size +) { if (ctx == NULL) return -1; - // Attach FIRST so that an attach failure does not leave process-wide side - // effects (CANN dlog level, HostLogger singleton) mutated. Subsequent - // logger writes only happen on the success path. DeviceRunner *runner = static_cast(ctx); int rc; try { @@ -223,17 +223,23 @@ int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_ } if (rc != 0) return rc; - // CANN dlog: derive from simpler logger choice unless ASCEND_GLOBAL_LOG_LEVEL - // is externally configured. - if (std::getenv("ASCEND_GLOBAL_LOG_LEVEL") == NULL) { - dlog_setlevel(-1, log_level, /*enableEvent*/ 0); + // Transfer ownership of the executor binaries to the runner. Subsequent + // prepare_callable / run_prepared invocations reuse them — no per-run + // binary push across the C ABI. + try { + std::vector aicpu_vec(aicpu_binary, aicpu_binary + aicpu_size); + std::vector aicore_vec(aicore_binary, aicore_binary + aicore_size); + runner->set_executors(std::move(aicpu_vec), std::move(aicore_vec)); + } catch (...) { + return -1; } - HostLogger::get_instance().set_level(static_cast(log_level)); - HostLogger::get_instance().set_info_v(log_info_v); - - runner->set_log_level(log_level); - runner->set_log_info_v(log_info_v); + // CANN dlog: derive from HostLogger (seeded by libsimpler_log.so's + // simpler_log_init() earlier in ChipWorker::init) unless + // ASCEND_GLOBAL_LOG_LEVEL is externally configured. + if (std::getenv("ASCEND_GLOBAL_LOG_LEVEL") == NULL) { + dlog_setlevel(-1, HostLogger::get_instance().level(), /*enableEvent*/ 0); + } return 0; } @@ -241,20 +247,10 @@ int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_ * Per-callable_id preparation * =========================================================================== */ -int prepare_callable( - DeviceContextHandle ctx, int32_t callable_id, const void *callable, int device_id, const uint8_t *aicpu_binary, - size_t aicpu_size, const uint8_t *aicore_binary, size_t aicore_size -) { +int prepare_callable(DeviceContextHandle ctx, int32_t callable_id, const void *callable) { if (ctx == NULL || callable == NULL) return -1; DeviceRunner *runner = static_cast(ctx); - // AICPU/AICore executor binaries are only consumed by run()/run_prepared(); - // prepare_callable just uploads kernel + orch SO state. - (void)aicpu_binary; - (void)aicpu_size; - (void)aicore_binary; - (void)aicore_size; - pthread_once(&g_runner_key_once, create_runner_key); pthread_setspecific(g_runner_key, ctx); auto tsd_guard = RAIIScopeGuard([]() { @@ -262,7 +258,7 @@ int prepare_callable( }); try { - int rc = runner->prepare_run_context(device_id); + int rc = runner->prepare_run_context(runner->device_id()); if (rc != 0) return rc; auto run_context_guard = RAIIScopeGuard([runner]() { runner->release_run_context(); @@ -321,8 +317,7 @@ int prepare_callable( int run_prepared( DeviceContextHandle ctx, RuntimeHandle runtime, int32_t callable_id, const void *args, int block_dim, - int aicpu_thread_num, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, const uint8_t *aicore_binary, - size_t aicore_size, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int enable_dep_gen, + int aicpu_thread_num, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int enable_dep_gen, const char *output_prefix ) { if (ctx == NULL || runtime == NULL) return -1; @@ -340,7 +335,7 @@ int run_prepared( }); try { - int rc = runner->prepare_run_context(device_id); + int rc = runner->prepare_run_context(runner->device_id()); if (rc != 0) return rc; auto run_context_guard = RAIIScopeGuard([runner]() { runner->release_run_context(); @@ -376,9 +371,7 @@ int run_prepared( runner->set_dep_gen_enabled(enable_dep_gen != 0); runner->set_output_prefix(output_prefix); - std::vector aicpu_vec(aicpu_binary, aicpu_binary + aicpu_size); - std::vector aicore_vec(aicore_binary, aicore_binary + aicore_size); - rc = runner->run(*r, block_dim, device_id, aicpu_vec, aicore_vec, aicpu_thread_num); + rc = runner->run(*r, block_dim, aicpu_thread_num); if (rc != 0) { validate_runtime_impl(r); r->~Runtime(); diff --git a/src/a2a3/platform/sim/host/device_runner.cpp b/src/a2a3/platform/sim/host/device_runner.cpp index 9bc38cd519..1755020be6 100644 --- a/src/a2a3/platform/sim/host/device_runner.cpp +++ b/src/a2a3/platform/sim/host/device_runner.cpp @@ -152,23 +152,20 @@ int DeviceRunner::attach_current_thread(int device_id) { return 0; } -int DeviceRunner::ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { - int rc = attach_current_thread(device_id); +int DeviceRunner::ensure_device_initialized() { + // device_id_ was set in attach_current_thread() during simpler_init. + int rc = attach_current_thread(device_id_); if (rc != 0) return rc; - return ensure_binaries_loaded(aicpu_so_binary, aicore_kernel_binary); + return ensure_binaries_loaded(); } -int DeviceRunner::ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { +int DeviceRunner::ensure_binaries_loaded() { // AICPU .so: load-once, matching onboard's binaries_loaded_ pattern. // Keeping the DSO alive across runs preserves g_aicpu_executor state // (orch_so_handle_ etc.), which is required for the orch-SO cache-hit path. - if (!aicpu_so_loaded_ && !aicpu_so_binary.empty()) { + if (!aicpu_so_loaded_ && !aicpu_so_binary_.empty()) { if (!create_temp_so_file( - "/tmp/aicpu_sim_XXXXXX", aicpu_so_binary.data(), aicpu_so_binary.size(), &aicpu_so_path_ + "/tmp/aicpu_sim_XXXXXX", aicpu_so_binary_.data(), aicpu_so_binary_.size(), &aicpu_so_path_ )) { LOG_ERROR("Failed to create temp file for AICPU SO"); return -1; @@ -251,10 +248,9 @@ int DeviceRunner::ensure_binaries_loaded( return -1; } - // Log config bindings (optional; older SOs without these stay at their - // compile-time defaults). - set_log_level_func_ = reinterpret_cast(dlsym(aicpu_so_handle_, "set_log_level")); - set_log_info_v_func_ = reinterpret_cast(dlsym(aicpu_so_handle_, "set_log_info_v")); + // Log config travels via the RTLD_GLOBAL HostLogger singleton in + // libsimpler_log.so — already seeded by simpler_log_init() before the + // AICPU sim SO was dlopen'd, so no per-SO setter forwarding is needed. aicpu_so_loaded_ = true; LOG_INFO_V0("DeviceRunner(sim): Loaded aicpu_execute from %s", aicpu_so_path_.c_str()); @@ -273,9 +269,9 @@ int DeviceRunner::ensure_binaries_loaded( } // Write AICore binary to temp file and dlopen - if (!aicore_kernel_binary.empty()) { + if (!aicore_kernel_binary_.empty()) { if (!create_temp_so_file( - "/tmp/aicore_sim_XXXXXX", aicore_kernel_binary.data(), aicore_kernel_binary.size(), &aicore_so_path_ + "/tmp/aicore_sim_XXXXXX", aicore_kernel_binary_.data(), aicore_kernel_binary_.size(), &aicore_so_path_ )) { LOG_ERROR("Failed to create temp file for AICore SO"); return -1; @@ -330,10 +326,7 @@ int DeviceRunner::copy_from_device(void *host_ptr, const void *dev_ptr, size_t b return 0; } -int DeviceRunner::run( - Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num -) { +int DeviceRunner::run(Runtime &runtime, int block_dim, int launch_aicpu_num) { clear_cpu_sim_shared_storage(); // Validate launch_aicpu_num if (launch_aicpu_num < 1 || launch_aicpu_num > PLATFORM_MAX_AICPU_THREADS) { @@ -372,7 +365,7 @@ int DeviceRunner::run( } // Ensure device is initialized - int rc = ensure_device_initialized(device_id, aicpu_so_binary, aicore_kernel_binary); + int rc = ensure_device_initialized(); if (rc != 0) { LOG_ERROR("ensure_device_initialized failed: %d", rc); return rc; @@ -441,7 +434,7 @@ int DeviceRunner::run( // Initialize per-subsystem shared memory. if (enable_l2_swimlane_) { - rc = init_l2_perf(num_aicore, device_id); + rc = init_l2_perf(num_aicore, device_id_); if (rc != 0) { LOG_ERROR("init_l2_perf failed: %d", rc); return rc; @@ -450,7 +443,7 @@ int DeviceRunner::run( if (enable_dump_tensor_) { // Initialize tensor dump (independent from profiling) - rc = init_tensor_dump(runtime, device_id); + rc = init_tensor_dump(runtime, device_id_); if (rc != 0) { LOG_ERROR("init_tensor_dump failed: %d", rc); return rc; @@ -458,7 +451,7 @@ int DeviceRunner::run( } if (enable_pmu_) { - rc = init_pmu(num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id); + rc = init_pmu(num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id_); if (rc != 0) { LOG_ERROR("init_pmu failed: %d", rc); return rc; @@ -466,7 +459,7 @@ int DeviceRunner::run( } if (enable_dep_gen_) { - rc = init_dep_gen(launch_aicpu_num, device_id); + rc = init_dep_gen(launch_aicpu_num, device_id_); if (rc != 0) { LOG_ERROR("init_dep_gen failed: %d", rc); return rc; @@ -582,14 +575,9 @@ int DeviceRunner::run( set_platform_dep_gen_base_func_(kernel_args_.dep_gen_data_base); set_dep_gen_enabled_func_(enable_dep_gen_); - // Publish log config to the AICPU SO. Optional dlsym for forward - // compatibility with pre-log-config SOs. - if (set_log_level_func_ != nullptr) { - set_log_level_func_(log_level_); - } - if (set_log_info_v_func_ != nullptr) { - set_log_info_v_func_(log_info_v_); - } + // No per-SO log-config push: HostLogger lives in libsimpler_log.so + // (RTLD_GLOBAL singleton) and the AICPU sim SO reads it directly via the + // same global lookup. // Start collector mgmt + poll threads now, just before kernels launch. // Starting earlier wastes CPU on empty queues and risks tripping diff --git a/src/a2a3/platform/sim/host/device_runner.h b/src/a2a3/platform/sim/host/device_runner.h index eb3371bb94..e7988a6836 100644 --- a/src/a2a3/platform/sim/host/device_runner.h +++ b/src/a2a3/platform/sim/host/device_runner.h @@ -139,15 +139,27 @@ class DeviceRunner { * * @param runtime Runtime to execute * @param block_dim Number of blocks (1 block = 1 AIC + 2 AIV) - * @param device_id Device ID (ignored in simulation) - * @param aicpu_so_binary AICPU binary (ignored in simulation) - * @param aicore_kernel_binary AICore binary (ignored in simulation) * @param launch_aicpu_num Number of AICPU threads * @return 0 on success + * + * Bound device id, AICPU/AICore executor binaries, and log filter are + * captured once by simpler_init / libsimpler_log.so and read off + * DeviceRunner state / HostLogger here — no per-run args. + */ + int run(Runtime &runtime, int block_dim, int launch_aicpu_num = 1); + + /** + * Take ownership of the AICPU + AICore executor binaries. Called once + * by simpler_init at ChipWorker::init time; subsequent run() invocations + * read from `aicpu_so_binary_` / `aicore_kernel_binary_`. */ - int - run(Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num = 1); + void set_executors(std::vector aicpu_so_binary, std::vector aicore_kernel_binary) { + aicpu_so_binary_ = std::move(aicpu_so_binary); + aicore_kernel_binary_ = std::move(aicore_kernel_binary); + } + + /** The device id captured by simpler_init's attach_current_thread call. */ + int device_id() const { return device_id_; } /** * Enablement setters for the three diagnostics sub-features. Called by @@ -162,11 +174,6 @@ class DeviceRunner { pmu_event_type_ = resolve_pmu_event_type(enable_pmu); } void set_dep_gen_enabled(bool enable) { enable_dep_gen_ = enable; } - // Severity floor (0=DEBUG..4=NUL) and INFO verbosity threshold (0..9). - // Pushed in by the Python layer via run_runtime() and propagated to AICPU - // through KernelArgs. - void set_log_level(int log_level) { log_level_ = log_level; } - void set_log_info_v(int log_info_v) { log_info_v_ = log_info_v; } // Directory under which all diagnostic artifacts (l2_perf_records.json / // tensor_dump/ / pmu.csv) land. Required (non-empty) when any diagnostic // is enabled; CallConfig::validate() enforces this contract upstream. @@ -255,6 +262,10 @@ class DeviceRunner { int block_dim_{0}; int cores_per_blockdim_{PLATFORM_CORES_PER_BLOCKDIM}; int worker_count_{0}; + // Executor binaries — populated once via set_executors() during + // simpler_init, owned by this runner for the rest of its lifetime. + std::vector aicpu_so_binary_; + std::vector aicore_kernel_binary_; // Memory management MemoryAllocator mem_alloc_; @@ -326,8 +337,6 @@ class DeviceRunner { void (*set_pmu_enabled_func_)(bool){nullptr}; void (*set_platform_dep_gen_base_func_)(uint64_t){nullptr}; void (*set_dep_gen_enabled_func_)(bool){nullptr}; - void (*set_log_level_func_)(int){nullptr}; - void (*set_log_info_v_func_)(int){nullptr}; std::string aicpu_so_path_; std::string aicore_so_path_; @@ -341,13 +350,10 @@ class DeviceRunner { // dep_gen collector — captures orchestrator submit_task inputs for offline replay DepGenCollector dep_gen_collector_; - // Private helper methods - int ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); - int ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); + // Private helper methods — read aicpu_so_binary_ / aicore_kernel_binary_ + // off the runner (populated by set_executors during simpler_init). + int ensure_device_initialized(); + int ensure_binaries_loaded(); void unload_executor_binaries(); /** @@ -386,8 +392,6 @@ class DeviceRunner { bool enable_dep_gen_{false}; PmuEventType pmu_event_type_{PmuEventType::PIPE_UTILIZATION}; // resolved from set_pmu_enabled() std::string output_prefix_{}; // diagnostic artifact root directory - int log_level_{1}; // 0=DEBUG..4=NUL; default INFO - int log_info_v_{5}; // INFO verbosity threshold; default V5 }; #endif // SRC_A2A3_PLATFORM_SIM_HOST_DEVICE_RUNNER_H_ diff --git a/src/a2a3/platform/sim/host/pto_runtime_c_api.cpp b/src/a2a3/platform/sim/host/pto_runtime_c_api.cpp index ebcf06187d..20e77c1c93 100644 --- a/src/a2a3/platform/sim/host/pto_runtime_c_api.cpp +++ b/src/a2a3/platform/sim/host/pto_runtime_c_api.cpp @@ -42,7 +42,7 @@ int bind_prepared_to_runtime_impl(Runtime *runtime, const ChipStorageTaskArgs *o int validate_runtime_impl(Runtime *runtime); /* =========================================================================== - * Per-thread DeviceRunner binding (set by run_runtime, read by HostApi wrappers) + * Per-thread DeviceRunner binding (set by prepare_callable / run_prepared, read by HostApi wrappers) * =========================================================================== */ static pthread_key_t g_runner_key; @@ -200,11 +200,12 @@ void record_tensor_pair(RuntimeHandle runtime, void *host_ptr, void *dev_ptr, si r->record_tensor_pair(host_ptr, dev_ptr, size); } -int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_info_v) { +int simpler_init( + DeviceContextHandle ctx, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, + const uint8_t *aicore_binary, size_t aicore_size +) { if (ctx == NULL) return -1; - // Attach FIRST so that an attach failure (e.g. invalid device_id) does not - // leave the process-wide HostLogger singleton mutated. DeviceRunner *runner = static_cast(ctx); int rc; try { @@ -214,11 +215,20 @@ int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_ } if (rc != 0) return rc; - // No CANN dlog on sim. - HostLogger::get_instance().set_level(static_cast(log_level)); - HostLogger::get_instance().set_info_v(log_info_v); - runner->set_log_level(log_level); - runner->set_log_info_v(log_info_v); + try { + std::vector aicpu_vec; + std::vector aicore_vec; + if (aicpu_binary != NULL && aicpu_size > 0) { + aicpu_vec.assign(aicpu_binary, aicpu_binary + aicpu_size); + } + if (aicore_binary != NULL && aicore_size > 0) { + aicore_vec.assign(aicore_binary, aicore_binary + aicore_size); + } + runner->set_executors(std::move(aicpu_vec), std::move(aicore_vec)); + } catch (...) { + return -1; + } + // No CANN dlog on sim. HostLogger is owned by libsimpler_log.so. return 0; } @@ -226,19 +236,10 @@ int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_ * Per-callable_id preparation * =========================================================================== */ -int prepare_callable( - DeviceContextHandle ctx, int32_t callable_id, const void *callable, int device_id, const uint8_t *aicpu_binary, - size_t aicpu_size, const uint8_t *aicore_binary, size_t aicore_size -) { +int prepare_callable(DeviceContextHandle ctx, int32_t callable_id, const void *callable) { if (ctx == NULL || callable == NULL) return -1; DeviceRunner *runner = static_cast(ctx); - (void)aicpu_binary; - (void)aicpu_size; - (void)aicore_binary; - (void)aicore_size; - (void)device_id; - pthread_once(&g_runner_key_once, create_runner_key); pthread_setspecific(g_runner_key, ctx); @@ -292,8 +293,7 @@ int prepare_callable( int run_prepared( DeviceContextHandle ctx, RuntimeHandle runtime, int32_t callable_id, const void *args, int block_dim, - int aicpu_thread_num, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, const uint8_t *aicore_binary, - size_t aicore_size, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int enable_dep_gen, + int aicpu_thread_num, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int enable_dep_gen, const char *output_prefix ) { if (ctx == NULL || runtime == NULL) return -1; @@ -338,15 +338,7 @@ int run_prepared( runner->set_dep_gen_enabled(enable_dep_gen != 0); runner->set_output_prefix(output_prefix); - std::vector aicpu_vec; - std::vector aicore_vec; - if (aicpu_binary != NULL && aicpu_size > 0) { - aicpu_vec.assign(aicpu_binary, aicpu_binary + aicpu_size); - } - if (aicore_binary != NULL && aicore_size > 0) { - aicore_vec.assign(aicore_binary, aicore_binary + aicore_size); - } - rc = runner->run(*r, block_dim, device_id, aicpu_vec, aicore_vec, aicpu_thread_num); + rc = runner->run(*r, block_dim, aicpu_thread_num); if (rc != 0) { validate_runtime_impl(r); r->~Runtime(); diff --git a/src/a5/platform/onboard/host/device_runner.cpp b/src/a5/platform/onboard/host/device_runner.cpp index 4b38d786b5..a84cae24e2 100644 --- a/src/a5/platform/onboard/host/device_runner.cpp +++ b/src/a5/platform/onboard/host/device_runner.cpp @@ -17,6 +17,8 @@ #include "device_runner.h" +#include "host_log.h" + #include #include @@ -155,17 +157,16 @@ std::thread DeviceRunner::create_thread(std::function fn) { }); } -int DeviceRunner::ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { - // First attach the current thread and create fresh run-scoped streams - int rc = prepare_run_context(device_id); +int DeviceRunner::ensure_device_initialized() { + // First attach the current thread and create fresh run-scoped streams. + // device_id_ was set in attach_current_thread() during simpler_init. + int rc = prepare_run_context(device_id_); if (rc != 0) { return rc; } // Then ensure binaries are loaded - return ensure_binaries_loaded(aicpu_so_binary, aicore_kernel_binary); + return ensure_binaries_loaded(); } int DeviceRunner::attach_current_thread(int device_id) { @@ -234,15 +235,9 @@ void DeviceRunner::release_run_context() { } } -int DeviceRunner::ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { - // Check if already loaded +int DeviceRunner::ensure_binaries_loaded() { + // Check if already loaded (binaries owned by the runner via set_executors). if (binaries_loaded_) { - // Just update kernel binary if different - if (aicore_kernel_binary_ != aicore_kernel_binary) { - aicore_kernel_binary_ = aicore_kernel_binary; - } return 0; } @@ -252,10 +247,8 @@ int DeviceRunner::ensure_binaries_loaded( return -1; } - aicore_kernel_binary_ = aicore_kernel_binary; - // Load AICPU SO - int rc = so_info_.init(aicpu_so_binary, mem_alloc_); + int rc = so_info_.init(aicpu_so_binary_, mem_alloc_); if (rc != 0) { LOG_ERROR("AicpuSoInfo::init failed: %d", rc); return rc; @@ -292,10 +285,7 @@ int DeviceRunner::copy_from_device(void *host_ptr, const void *dev_ptr, size_t b return rtMemcpy(host_ptr, bytes, dev_ptr, bytes, RT_MEMCPY_DEVICE_TO_HOST); } -int DeviceRunner::run( - Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num -) { +int DeviceRunner::run(Runtime &runtime, int block_dim, int launch_aicpu_num) { if (launch_aicpu_num < 1 || launch_aicpu_num > PLATFORM_MAX_AICPU_THREADS) { LOG_ERROR("launch_aicpu_num (%d) must be in range [1, %d]", launch_aicpu_num, PLATFORM_MAX_AICPU_THREADS); return -1; @@ -332,7 +322,7 @@ int DeviceRunner::run( } // Ensure device is initialized (lazy initialization) - int rc = ensure_device_initialized(device_id, aicpu_so_binary, aicore_kernel_binary); + int rc = ensure_device_initialized(); if (rc != 0) { LOG_ERROR("ensure_device_initialized failed: %d", rc); return rc; @@ -353,7 +343,7 @@ int DeviceRunner::run( runtime.sche_cpu_num = launch_aicpu_num; // Get AICore register addresses for register-based task dispatch - rc = init_aicore_register_addresses(&kernel_args_.args.regs, static_cast(device_id), mem_alloc_); + rc = init_aicore_register_addresses(&kernel_args_.args.regs, static_cast(device_id_), mem_alloc_); if (rc != 0) { LOG_ERROR("init_aicore_register_addresses failed: %d", rc); return rc; @@ -409,7 +399,7 @@ int DeviceRunner::run( // Initialize performance profiling if enabled if (enable_l2_swimlane_) { - rc = init_l2_perf_collection(num_aicore, device_id); + rc = init_l2_perf_collection(num_aicore, device_id_); if (rc != 0) { LOG_ERROR("init_l2_perf_collection failed: %d", rc); return rc; @@ -422,7 +412,7 @@ int DeviceRunner::run( // Initialize tensor dump if enabled if (enable_dump_tensor_) { - rc = init_tensor_dump(runtime, num_aicore, device_id); + rc = init_tensor_dump(runtime, num_aicore, device_id_); if (rc != 0) { LOG_ERROR("init_tensor_dump failed: %d", rc); return rc; @@ -432,7 +422,7 @@ int DeviceRunner::run( if (enable_pmu_) { rc = init_pmu_buffers( - num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id + num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id_ ); if (rc != 0) { LOG_ERROR("PMU init failed: %d, disabling PMU for this run", rc); @@ -455,8 +445,11 @@ int DeviceRunner::run( } // Publish log config to AICPU via KernelArgs (severity floor + INFO verbosity). - kernel_args_.args.log_level = static_cast(log_level_); - kernel_args_.args.log_info_v = static_cast(log_info_v_); + // HostLogger is the single source of truth for log config (seeded by + // libsimpler_log.so via simpler_log_init before host_runtime.so was even + // dlopen'd). Read it directly when populating KernelArgs. + kernel_args_.args.log_level = static_cast(HostLogger::get_instance().level()); + kernel_args_.args.log_info_v = static_cast(HostLogger::get_instance().info_v()); LOG_INFO_V0("=== launch_aicpu_kernel DynTileFwkKernelServerInit ==="); // Launch AICPU init kernel diff --git a/src/a5/platform/onboard/host/device_runner.h b/src/a5/platform/onboard/host/device_runner.h index 7e898096f5..672c3325d9 100644 --- a/src/a5/platform/onboard/host/device_runner.h +++ b/src/a5/platform/onboard/host/device_runner.h @@ -222,15 +222,27 @@ class DeviceRunner { * @param runtime Runtime to execute (will be modified to * initialize workers) * @param block_dim Number of blocks (1 block = 1 AIC + 2 AIV) - * @param device_id Device ID (0-15) - * @param aicpu_so_binary Binary data of AICPU shared object - * @param aicore_kernel_binary Binary data of AICore kernel - * @param launch_aicpu_num Number of AICPU instances (default: 1) + * @param launch_aicpu_num Number of AICPU instances (default: 1) * @return 0 on success, error code on failure + * + * The bound device id, AICPU/AICore executor binaries, and log filter + * are captured once by simpler_init (binaries) / libsimpler_log.so (log) + * and read off DeviceRunner state / HostLogger here — no per-run args. */ - int - run(Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num = 1); + int run(Runtime &runtime, int block_dim, int launch_aicpu_num = 1); + + /** + * Take ownership of the AICPU + AICore executor binaries. Called once + * by simpler_init at ChipWorker::init time; subsequent run() invocations + * read from `aicpu_so_binary_` / `aicore_kernel_binary_`. + */ + void set_executors(std::vector aicpu_so_binary, std::vector aicore_kernel_binary) { + aicpu_so_binary_ = std::move(aicpu_so_binary); + aicore_kernel_binary_ = std::move(aicore_kernel_binary); + } + + /** The device id captured by simpler_init's attach_current_thread call. */ + int device_id() const { return device_id_; } /** * Enablement setters for the three diagnostics sub-features. Called by @@ -244,11 +256,6 @@ class DeviceRunner { enable_pmu_ = (enable_pmu > 0); pmu_event_type_ = resolve_pmu_event_type(enable_pmu); } - // Severity floor (0=DEBUG..4=NUL) and INFO verbosity threshold (0..9). - // Pushed in by the Python layer via run_runtime() and propagated to AICPU - // through KernelArgs. - void set_log_level(int log_level) { log_level_ = log_level; } - void set_log_info_v(int log_info_v) { log_info_v_ = log_info_v; } // Directory under which all diagnostic artifacts (l2_perf_records.json / // tensor_dump/ / pmu.csv) land. Required (non-empty) when any diagnostic // is enabled; CallConfig::validate() enforces this contract upstream. @@ -442,6 +449,9 @@ class DeviceRunner { int block_dim_{0}; int cores_per_blockdim_{PLATFORM_CORES_PER_BLOCKDIM}; int worker_count_{0}; // Stored for print_handshake_results in destructor + // Executor binaries — populated once via set_executors() during + // simpler_init, owned by this runner for the rest of its lifetime. + std::vector aicpu_so_binary_; std::vector aicore_kernel_binary_; // Memory management @@ -516,29 +526,20 @@ class DeviceRunner { * - Load AICPU SO to device memory * - Initialize device args * - * @param device_id Device ID (0-15) - * @param aicpu_so_binary Binary data of AICPU shared object - * @param aicore_kernel_binary Binary data of AICore kernel + * Reads the bound device id and executor binaries from runner state. * @return 0 on success, error code on failure */ - int ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); + int ensure_device_initialized(); /** * Load AICPU SO and initialize device args * - * Called by run() after prepare_run_context(). Performs: - * - Load AICPU SO to device memory - * - Initialize device args + * Called by run() after prepare_run_context(). Reads aicpu_so_binary_ / + * aicore_kernel_binary_ off the runner. * - * @param aicpu_so_binary Binary data of AICPU shared object - * @param aicore_kernel_binary Binary data of AICore kernel * @return 0 on success, error code on failure */ - int ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); + int ensure_binaries_loaded(); /** * Stage the orchestration SO into a device-resident buffer (with hash @@ -586,8 +587,6 @@ class DeviceRunner { bool enable_pmu_{false}; PmuEventType pmu_event_type_{PmuEventType::PIPE_UTILIZATION}; // resolved from set_pmu_enabled() std::string output_prefix_{}; // diagnostic artifact root directory - int log_level_{1}; // 0=DEBUG..4=NUL; default INFO - int log_info_v_{5}; // INFO verbosity threshold; default V5 int init_pmu_buffers( int num_cores, int num_threads, const std::string &csv_path, PmuEventType event_type, int device_id diff --git a/src/a5/platform/onboard/host/pto_runtime_c_api.cpp b/src/a5/platform/onboard/host/pto_runtime_c_api.cpp index 3b03dc06cf..ba5f8148a6 100644 --- a/src/a5/platform/onboard/host/pto_runtime_c_api.cpp +++ b/src/a5/platform/onboard/host/pto_runtime_c_api.cpp @@ -46,7 +46,7 @@ int bind_prepared_to_runtime_impl(Runtime *runtime, const ChipStorageTaskArgs *o int validate_runtime_impl(Runtime *runtime); /* =========================================================================== - * Per-thread DeviceRunner binding (set by run_runtime, read by HostApi wrappers) + * Per-thread DeviceRunner binding (set by prepare_callable / run_prepared, read by HostApi wrappers) * =========================================================================== */ static pthread_key_t g_runner_key; @@ -240,12 +240,12 @@ void record_tensor_pair(RuntimeHandle runtime, void *host_ptr, void *dev_ptr, si r->record_tensor_pair(host_ptr, dev_ptr, size); } -int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_info_v) { +int simpler_init( + DeviceContextHandle ctx, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, + const uint8_t *aicore_binary, size_t aicore_size +) { if (ctx == NULL) return -1; - // Attach FIRST so that an attach failure does not leave process-wide side - // effects (CANN dlog level, HostLogger singleton) mutated. Subsequent - // logger writes only happen on the success path. DeviceRunner *runner = static_cast(ctx); int rc; try { @@ -255,40 +255,30 @@ int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_ } if (rc != 0) return rc; - // CANN dlog: derive from simpler logger choice unless ASCEND_GLOBAL_LOG_LEVEL - // is externally configured. dlog_setlevel mutates libunified_dlog.so's - // runtime filter so this works even after other Ascend libs have loaded. - if (std::getenv("ASCEND_GLOBAL_LOG_LEVEL") == NULL) { - dlog_setlevel(-1, log_level, /*enableEvent*/ 0); + try { + std::vector aicpu_vec(aicpu_binary, aicpu_binary + aicpu_size); + std::vector aicore_vec(aicore_binary, aicore_binary + aicore_size); + runner->set_executors(std::move(aicpu_vec), std::move(aicore_vec)); + } catch (...) { + return -1; } - // Host C++ LOG_* gating - HostLogger::get_instance().set_level(static_cast(log_level)); - HostLogger::get_instance().set_info_v(log_info_v); - - // Snapshot into runner — read by run_runtime when populating KernelArgs - runner->set_log_level(log_level); - runner->set_log_info_v(log_info_v); + // CANN dlog: derive from HostLogger (seeded by libsimpler_log.so's + // simpler_log_init() earlier in ChipWorker::init) unless + // ASCEND_GLOBAL_LOG_LEVEL is externally configured. + if (std::getenv("ASCEND_GLOBAL_LOG_LEVEL") == NULL) { + dlog_setlevel(-1, HostLogger::get_instance().level(), /*enableEvent*/ 0); + } return 0; } /* =========================================================================== * Per-callable_id preparation * =========================================================================== */ -int prepare_callable( - DeviceContextHandle ctx, int32_t callable_id, const void *callable, int device_id, const uint8_t *aicpu_binary, - size_t aicpu_size, const uint8_t *aicore_binary, size_t aicore_size -) { +int prepare_callable(DeviceContextHandle ctx, int32_t callable_id, const void *callable) { if (ctx == NULL || callable == NULL) return -1; DeviceRunner *runner = static_cast(ctx); - // AICPU/AICore executor binaries are only consumed by run()/run_prepared(); - // prepare_callable just uploads kernel + orch SO state. - (void)aicpu_binary; - (void)aicpu_size; - (void)aicore_binary; - (void)aicore_size; - pthread_once(&g_runner_key_once, create_runner_key); pthread_setspecific(g_runner_key, ctx); auto tsd_guard = RAIIScopeGuard([]() { @@ -296,7 +286,7 @@ int prepare_callable( }); try { - int rc = runner->prepare_run_context(device_id); + int rc = runner->prepare_run_context(runner->device_id()); if (rc != 0) return rc; auto run_context_guard = RAIIScopeGuard([runner]() { runner->release_run_context(); @@ -351,8 +341,7 @@ int prepare_callable( int run_prepared( DeviceContextHandle ctx, RuntimeHandle runtime, int32_t callable_id, const void *args, int block_dim, - int aicpu_thread_num, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, const uint8_t *aicore_binary, - size_t aicore_size, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int /*enable_dep_gen*/, + int aicpu_thread_num, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int /*enable_dep_gen*/, const char *output_prefix ) { if (ctx == NULL || runtime == NULL) return -1; @@ -370,7 +359,7 @@ int run_prepared( }); try { - int rc = runner->prepare_run_context(device_id); + int rc = runner->prepare_run_context(runner->device_id()); if (rc != 0) return rc; auto run_context_guard = RAIIScopeGuard([runner]() { runner->release_run_context(); @@ -405,9 +394,7 @@ int run_prepared( runner->set_pmu_enabled(enable_pmu); runner->set_output_prefix(output_prefix); - std::vector aicpu_vec(aicpu_binary, aicpu_binary + aicpu_size); - std::vector aicore_vec(aicore_binary, aicore_binary + aicore_size); - rc = runner->run(*r, block_dim, device_id, aicpu_vec, aicore_vec, aicpu_thread_num); + rc = runner->run(*r, block_dim, aicpu_thread_num); if (rc != 0) { validate_runtime_impl(r); r->~Runtime(); diff --git a/src/a5/platform/sim/host/device_runner.cpp b/src/a5/platform/sim/host/device_runner.cpp index 72a74d4b9d..654cda882b 100644 --- a/src/a5/platform/sim/host/device_runner.cpp +++ b/src/a5/platform/sim/host/device_runner.cpp @@ -127,23 +127,20 @@ int DeviceRunner::attach_current_thread(int device_id) { return 0; } -int DeviceRunner::ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { - int rc = attach_current_thread(device_id); +int DeviceRunner::ensure_device_initialized() { + // device_id_ was set in attach_current_thread() during simpler_init. + int rc = attach_current_thread(device_id_); if (rc != 0) return rc; - return ensure_binaries_loaded(aicpu_so_binary, aicore_kernel_binary); + return ensure_binaries_loaded(); } -int DeviceRunner::ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary -) { +int DeviceRunner::ensure_binaries_loaded() { // AICPU .so: load-once, matching onboard's binaries_loaded_ pattern. // Keeping the DSO alive across runs preserves g_aicpu_executor state // (orch_so_handle_ etc.), which is required for the orch-SO cache-hit path. - if (!aicpu_so_loaded_ && !aicpu_so_binary.empty()) { + if (!aicpu_so_loaded_ && !aicpu_so_binary_.empty()) { if (!create_temp_so_file( - "/tmp/aicpu_sim_XXXXXX", aicpu_so_binary.data(), aicpu_so_binary.size(), &aicpu_so_path_ + "/tmp/aicpu_sim_XXXXXX", aicpu_so_binary_.data(), aicpu_so_binary_.size(), &aicpu_so_path_ )) { LOG_ERROR("Failed to create temp file for AICPU SO"); return -1; @@ -208,10 +205,9 @@ int DeviceRunner::ensure_binaries_loaded( return -1; } - // Log config bindings (optional; older SOs without these stay at their - // compile-time defaults). - set_log_level_func_ = reinterpret_cast(dlsym(aicpu_so_handle_, "set_log_level")); - set_log_info_v_func_ = reinterpret_cast(dlsym(aicpu_so_handle_, "set_log_info_v")); + // Log config travels via the RTLD_GLOBAL HostLogger singleton in + // libsimpler_log.so — already seeded by simpler_log_init() before the + // AICPU sim SO was dlopen'd, so no per-SO setter forwarding is needed. aicpu_so_loaded_ = true; LOG_INFO_V0("DeviceRunner(sim): Loaded aicpu_execute from %s", aicpu_so_path_.c_str()); @@ -230,9 +226,9 @@ int DeviceRunner::ensure_binaries_loaded( } // Write AICore binary to temp file and dlopen - if (!aicore_kernel_binary.empty()) { + if (!aicore_kernel_binary_.empty()) { if (!create_temp_so_file( - "/tmp/aicore_sim_XXXXXX", aicore_kernel_binary.data(), aicore_kernel_binary.size(), &aicore_so_path_ + "/tmp/aicore_sim_XXXXXX", aicore_kernel_binary_.data(), aicore_kernel_binary_.size(), &aicore_so_path_ )) { LOG_ERROR("Failed to create temp file for AICore SO"); return -1; @@ -288,10 +284,7 @@ int DeviceRunner::copy_from_device(void *host_ptr, const void *dev_ptr, size_t b return 0; } -int DeviceRunner::run( - Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num -) { +int DeviceRunner::run(Runtime &runtime, int block_dim, int launch_aicpu_num) { clear_cpu_sim_shared_storage(); // Validate launch_aicpu_num if (launch_aicpu_num < 1 || launch_aicpu_num > PLATFORM_MAX_AICPU_THREADS) { @@ -330,7 +323,7 @@ int DeviceRunner::run( } // Ensure device is initialized - int rc = ensure_device_initialized(device_id, aicpu_so_binary, aicore_kernel_binary); + int rc = ensure_device_initialized(); if (rc != 0) { LOG_ERROR("ensure_device_initialized failed: %d", rc); return rc; @@ -396,7 +389,7 @@ int DeviceRunner::run( // Initialize performance profiling if enabled if (enable_l2_swimlane_) { - rc = init_l2_perf_collection(num_aicore, device_id); + rc = init_l2_perf_collection(num_aicore, device_id_); if (rc != 0) { LOG_ERROR("init_l2_perf_collection failed: %d", rc); return rc; @@ -409,7 +402,7 @@ int DeviceRunner::run( if (enable_dump_tensor_) { // Initialize tensor dump (independent from profiling) - rc = init_tensor_dump(runtime, num_aicore, device_id); + rc = init_tensor_dump(runtime, num_aicore, device_id_); if (rc != 0) { LOG_ERROR("init_tensor_dump failed: %d", rc); return rc; @@ -419,7 +412,7 @@ int DeviceRunner::run( if (enable_pmu_) { rc = init_pmu_buffers( - num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id + num_aicore, launch_aicpu_num, make_pmu_csv_path(output_prefix_), pmu_event_type_, device_id_ ); if (rc != 0) { LOG_ERROR("PMU init failed: %d, disabling PMU for this run", rc); @@ -488,14 +481,9 @@ int DeviceRunner::run( set_platform_pmu_base_func_(kernel_args_.pmu_data_base); set_pmu_enabled_func_(enable_pmu_); - // Publish log config to the AICPU SO. Optional dlsym for forward - // compatibility with pre-log-config SOs. - if (set_log_level_func_ != nullptr) { - set_log_level_func_(log_level_); - } - if (set_log_info_v_func_ != nullptr) { - set_log_info_v_func_(log_info_v_); - } + // No per-SO log-config push: HostLogger lives in libsimpler_log.so + // (RTLD_GLOBAL singleton) and the AICPU sim SO reads it directly via the + // same global lookup. // Launch AICPU threads (over-launch for affinity gate) constexpr int over_launch = PLATFORM_MAX_AICPU_THREADS_JUST_FOR_LAUNCH; diff --git a/src/a5/platform/sim/host/device_runner.h b/src/a5/platform/sim/host/device_runner.h index 4769efdc1d..1cd9f9f6e3 100644 --- a/src/a5/platform/sim/host/device_runner.h +++ b/src/a5/platform/sim/host/device_runner.h @@ -136,15 +136,27 @@ class DeviceRunner { * * @param runtime Runtime to execute * @param block_dim Number of blocks (1 block = 1 AIC + 2 AIV) - * @param device_id Device ID (ignored in simulation) - * @param aicpu_so_binary AICPU binary (ignored in simulation) - * @param aicore_kernel_binary AICore binary (ignored in simulation) * @param launch_aicpu_num Number of AICPU threads * @return 0 on success + * + * Bound device id, AICPU/AICore executor binaries, and log filter are + * captured once by simpler_init / libsimpler_log.so and read off + * DeviceRunner state / HostLogger here — no per-run args. + */ + int run(Runtime &runtime, int block_dim, int launch_aicpu_num = 1); + + /** + * Take ownership of the AICPU + AICore executor binaries. Called once + * by simpler_init at ChipWorker::init time; subsequent run() invocations + * read from `aicpu_so_binary_` / `aicore_kernel_binary_`. */ - int - run(Runtime &runtime, int block_dim, int device_id, const std::vector &aicpu_so_binary, - const std::vector &aicore_kernel_binary, int launch_aicpu_num = 1); + void set_executors(std::vector aicpu_so_binary, std::vector aicore_kernel_binary) { + aicpu_so_binary_ = std::move(aicpu_so_binary); + aicore_kernel_binary_ = std::move(aicore_kernel_binary); + } + + /** The device id captured by simpler_init's attach_current_thread call. */ + int device_id() const { return device_id_; } /** * Enablement setters for the three diagnostics sub-features. Called by @@ -158,11 +170,6 @@ class DeviceRunner { enable_pmu_ = (enable_pmu > 0); pmu_event_type_ = resolve_pmu_event_type(enable_pmu); } - // Severity floor (0=DEBUG..4=NUL) and INFO verbosity threshold (0..9). - // Pushed in by the Python layer via run_runtime() and propagated to AICPU - // through KernelArgs. - void set_log_level(int log_level) { log_level_ = log_level; } - void set_log_info_v(int log_info_v) { log_info_v_ = log_info_v; } // Directory under which all diagnostic artifacts (l2_perf_records.json / // tensor_dump/ / pmu.csv) land. Required (non-empty) when any diagnostic // is enabled; CallConfig::validate() enforces this contract upstream. @@ -263,6 +270,10 @@ class DeviceRunner { int block_dim_{0}; int cores_per_blockdim_{PLATFORM_CORES_PER_BLOCKDIM}; int worker_count_{0}; + // Executor binaries — populated once via set_executors() during + // simpler_init, owned by this runner for the rest of its lifetime. + std::vector aicpu_so_binary_; + std::vector aicore_kernel_binary_; // Memory management MemoryAllocator mem_alloc_; @@ -321,8 +332,6 @@ class DeviceRunner { void (*set_platform_l2_perf_base_func_)(uint64_t){nullptr}; void (*set_l2_swimlane_enabled_func_)(bool){nullptr}; void (*set_pmu_enabled_func_)(bool){nullptr}; - void (*set_log_level_func_)(int){nullptr}; - void (*set_log_info_v_func_)(int){nullptr}; std::string aicpu_so_path_; std::string aicore_so_path_; @@ -335,13 +344,10 @@ class DeviceRunner { // PMU profiling (per-task AICore hardware counters) PmuCollector pmu_collector_; - // Private helper methods - int ensure_device_initialized( - int device_id, const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); - int ensure_binaries_loaded( - const std::vector &aicpu_so_binary, const std::vector &aicore_kernel_binary - ); + // Private helper methods — read aicpu_so_binary_ / aicore_kernel_binary_ + // off the runner (populated by set_executors during simpler_init). + int ensure_device_initialized(); + int ensure_binaries_loaded(); void unload_executor_binaries(); /** @@ -384,8 +390,6 @@ class DeviceRunner { bool enable_pmu_{false}; PmuEventType pmu_event_type_{PmuEventType::PIPE_UTILIZATION}; // resolved from set_pmu_enabled() std::string output_prefix_{}; // diagnostic artifact root directory - int log_level_{1}; // 0=DEBUG..4=NUL; default INFO - int log_info_v_{5}; // INFO verbosity threshold; default V5 int init_pmu_buffers( int num_cores, int num_threads, const std::string &csv_path, PmuEventType event_type, int device_id diff --git a/src/a5/platform/sim/host/pto_runtime_c_api.cpp b/src/a5/platform/sim/host/pto_runtime_c_api.cpp index 947de4f047..d664190f65 100644 --- a/src/a5/platform/sim/host/pto_runtime_c_api.cpp +++ b/src/a5/platform/sim/host/pto_runtime_c_api.cpp @@ -42,7 +42,7 @@ int bind_prepared_to_runtime_impl(Runtime *runtime, const ChipStorageTaskArgs *o int validate_runtime_impl(Runtime *runtime); /* =========================================================================== - * Per-thread DeviceRunner binding (set by run_runtime, read by HostApi wrappers) + * Per-thread DeviceRunner binding (set by prepare_callable / run_prepared, read by HostApi wrappers) * =========================================================================== */ static pthread_key_t g_runner_key; @@ -200,11 +200,12 @@ void record_tensor_pair(RuntimeHandle runtime, void *host_ptr, void *dev_ptr, si r->record_tensor_pair(host_ptr, dev_ptr, size); } -int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_info_v) { +int simpler_init( + DeviceContextHandle ctx, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, + const uint8_t *aicore_binary, size_t aicore_size +) { if (ctx == NULL) return -1; - // Attach FIRST so that an attach failure (e.g. invalid device_id) does not - // leave the process-wide HostLogger singleton mutated. DeviceRunner *runner = static_cast(ctx); int rc; try { @@ -214,30 +215,30 @@ int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_ } if (rc != 0) return rc; - // No CANN dlog on sim; only HostLogger + runner state. - HostLogger::get_instance().set_level(static_cast(log_level)); - HostLogger::get_instance().set_info_v(log_info_v); - runner->set_log_level(log_level); - runner->set_log_info_v(log_info_v); + try { + std::vector aicpu_vec; + std::vector aicore_vec; + if (aicpu_binary != NULL && aicpu_size > 0) { + aicpu_vec.assign(aicpu_binary, aicpu_binary + aicpu_size); + } + if (aicore_binary != NULL && aicore_size > 0) { + aicore_vec.assign(aicore_binary, aicore_binary + aicore_size); + } + runner->set_executors(std::move(aicpu_vec), std::move(aicore_vec)); + } catch (...) { + return -1; + } + // No CANN dlog on sim. HostLogger is owned by libsimpler_log.so. return 0; } /* =========================================================================== * Per-callable_id preparation * =========================================================================== */ -int prepare_callable( - DeviceContextHandle ctx, int32_t callable_id, const void *callable, int device_id, const uint8_t *aicpu_binary, - size_t aicpu_size, const uint8_t *aicore_binary, size_t aicore_size -) { +int prepare_callable(DeviceContextHandle ctx, int32_t callable_id, const void *callable) { if (ctx == NULL || callable == NULL) return -1; DeviceRunner *runner = static_cast(ctx); - (void)aicpu_binary; - (void)aicpu_size; - (void)aicore_binary; - (void)aicore_size; - (void)device_id; - pthread_once(&g_runner_key_once, create_runner_key); pthread_setspecific(g_runner_key, ctx); @@ -289,8 +290,7 @@ int prepare_callable( int run_prepared( DeviceContextHandle ctx, RuntimeHandle runtime, int32_t callable_id, const void *args, int block_dim, - int aicpu_thread_num, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, const uint8_t *aicore_binary, - size_t aicore_size, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int /*enable_dep_gen*/, + int aicpu_thread_num, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int /*enable_dep_gen*/, const char *output_prefix ) { if (ctx == NULL || runtime == NULL) return -1; @@ -334,15 +334,7 @@ int run_prepared( runner->set_pmu_enabled(enable_pmu); runner->set_output_prefix(output_prefix); - std::vector aicpu_vec; - std::vector aicore_vec; - if (aicpu_binary != NULL && aicpu_size > 0) { - aicpu_vec.assign(aicpu_binary, aicpu_binary + aicpu_size); - } - if (aicore_binary != NULL && aicore_size > 0) { - aicore_vec.assign(aicore_binary, aicore_binary + aicore_size); - } - rc = runner->run(*r, block_dim, device_id, aicpu_vec, aicore_vec, aicpu_thread_num); + rc = runner->run(*r, block_dim, aicpu_thread_num); if (rc != 0) { validate_runtime_impl(r); r->~Runtime(); diff --git a/src/common/log/host_log.cpp b/src/common/log/host_log.cpp index 7e208762bd..51d2de29bf 100644 --- a/src/common/log/host_log.cpp +++ b/src/common/log/host_log.cpp @@ -44,6 +44,10 @@ void HostLogger::set_info_v(int v) { current_info_v_ = v; } +int HostLogger::level() const { return static_cast(current_level_); } + +int HostLogger::info_v() const { return current_info_v_; } + bool HostLogger::is_severity_enabled(LogLevel level) const { // current_level_ is the floor: messages with severity >= floor are kept. return static_cast(level) >= static_cast(current_level_) && current_level_ != LogLevel::NUL; @@ -118,3 +122,28 @@ void HostLogger::log_info_v(int v, const char *func, const char *fmt, ...) { vlog_info_v(v, func, fmt, args); va_end(args); } + +// --------------------------------------------------------------------------- +// C ABI entry — resolved by ChipWorker via dlsym from libsimpler_log.so. +// +// 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 +// has to travel through any other SO's C ABI. +// +// Severity layout matches CANN dlog (0=DEBUG..4=NUL); info_v ∈ [0,9]. +// Returns 0 on success, negative on out-of-range input. +// --------------------------------------------------------------------------- +extern "C" int simpler_log_init(int log_level, int log_info_v) { + if (log_level < static_cast(LogLevel::DEBUG) || log_level > static_cast(LogLevel::NUL)) { + return -1; + } + if (log_info_v < 0 || log_info_v > 9) { + return -1; + } + HostLogger::get_instance().set_level(static_cast(log_level)); + HostLogger::get_instance().set_info_v(log_info_v); + return 0; +} diff --git a/src/common/log/include/host_log.h b/src/common/log/include/host_log.h index 7a6c0887ce..bb9295b3df 100644 --- a/src/common/log/include/host_log.h +++ b/src/common/log/include/host_log.h @@ -68,6 +68,13 @@ class HostLogger { void set_level(simpler::log::LogLevel level); 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 + // 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) + int info_v() const; + bool is_severity_enabled(simpler::log::LogLevel level) const; bool is_info_v_enabled(int v) const; diff --git a/src/common/worker/chip_worker.cpp b/src/common/worker/chip_worker.cpp index 10c9970797..86acef59b8 100644 --- a/src/common/worker/chip_worker.cpp +++ b/src/common/worker/chip_worker.cpp @@ -121,6 +121,17 @@ void ChipWorker::init( } ensure_simpler_log_loaded(simpler_log_lib_path); + // Seed the process-wide HostLogger BEFORE host_runtime.so is dlopen'd, so + // any LOG_* macro firing during host_runtime's dlopen-time constructors + // already sees the user's chosen filter rather than the C++ static init + // default. simpler_log_init lives in libsimpler_log.so. + simpler_log_init_fn_ = load_symbol(g_simpler_log_handle, "simpler_log_init"); + int log_rc = simpler_log_init_fn_(log_level, log_info_v); + if (log_rc != 0) { + simpler_log_init_fn_ = nullptr; + throw std::runtime_error("simpler_log_init failed with code " + std::to_string(log_rc)); + } + // Load the sim context SO with RTLD_GLOBAL (once per process) so that // PTO ISA TPUSH/TPOP can resolve pto_sim_get_subblock_id and // pto_sim_get_pipe_shared_state via dlsym(RTLD_DEFAULT). @@ -187,18 +198,56 @@ void ChipWorker::init( throw std::runtime_error("create_device_context returned null"); } - // Read platform binaries from files - aicpu_binary_ = read_binary_file(aicpu_path); - aicore_binary_ = read_binary_file(aicore_path); - runtime_buf_.resize(get_runtime_size_fn_()); // One-shot platform-side init: attach the calling thread to `device_id` - // (rtSetDevice on onboard, sim bind+acquire on sim) and push the user's - // simpler-logger choice into HostLogger + runner state (and CANN dlog - // onboard). Subsequent device-ops re-attach their caller threads - // idempotently against the recorded device id. - int init_rc = simpler_init_fn_(device_ctx_, device_id, log_level, log_info_v); + // (rtSetDevice on onboard, sim bind+acquire on sim), transfer ownership + // of the executor binaries to the DeviceRunner, and (onboard) sync CANN + // dlog from HostLogger. Subsequent device-ops re-attach their caller + // threads idempotently against the recorded device id; subsequent + // prepare_callable / run_prepared invocations reuse the cached binaries. + // + // read_binary_file may throw — defer the dlsym/dlclose rollback to the + // catch block so the buffers and any partially-resolved handle are torn + // down symmetrically. + int init_rc = 0; + try { + std::vector aicpu_bytes = read_binary_file(aicpu_path); + std::vector aicore_bytes = read_binary_file(aicore_path); + init_rc = simpler_init_fn_( + device_ctx_, device_id, aicpu_bytes.data(), aicpu_bytes.size(), aicore_bytes.data(), aicore_bytes.size() + ); + } catch (...) { + destroy_device_context_fn_(device_ctx_); + device_ctx_ = nullptr; + dlclose(handle); + lib_handle_ = nullptr; + create_device_context_fn_ = nullptr; + destroy_device_context_fn_ = nullptr; + device_malloc_ctx_fn_ = nullptr; + device_free_ctx_fn_ = nullptr; + copy_to_device_ctx_fn_ = nullptr; + copy_from_device_ctx_fn_ = nullptr; + get_runtime_size_fn_ = nullptr; + simpler_init_fn_ = nullptr; + prepare_callable_fn_ = nullptr; + run_prepared_fn_ = nullptr; + unregister_callable_fn_ = nullptr; + get_aicpu_dlopen_count_fn_ = nullptr; + get_host_dlopen_count_fn_ = nullptr; + finalize_device_fn_ = nullptr; + ensure_acl_ready_fn_ = nullptr; + create_comm_stream_fn_ = nullptr; + destroy_comm_stream_fn_ = nullptr; + comm_init_fn_ = nullptr; + comm_alloc_windows_fn_ = nullptr; + comm_get_local_window_base_fn_ = nullptr; + comm_get_window_size_fn_ = nullptr; + comm_barrier_fn_ = nullptr; + comm_destroy_fn_ = nullptr; + runtime_buf_.clear(); + throw; + } if (init_rc != 0) { // Symmetric teardown: drop the device context, clear all dlsym'd // function pointers, dlclose, and discard cached binaries so the @@ -233,8 +282,6 @@ void ChipWorker::init( comm_barrier_fn_ = nullptr; comm_destroy_fn_ = nullptr; runtime_buf_.clear(); - aicpu_binary_.clear(); - aicore_binary_.clear(); throw std::runtime_error("simpler_init failed with code " + std::to_string(init_rc)); } @@ -284,9 +331,8 @@ void ChipWorker::finalize() { comm_get_window_size_fn_ = nullptr; comm_barrier_fn_ = nullptr; comm_destroy_fn_ = nullptr; + simpler_log_init_fn_ = nullptr; runtime_buf_.clear(); - aicpu_binary_.clear(); - aicore_binary_.clear(); initialized_ = false; device_id_ = -1; finalized_ = true; @@ -303,10 +349,7 @@ void ChipWorker::prepare_callable(int32_t callable_id, const void *callable) { if (callable == nullptr) { throw std::runtime_error("prepare_callable: callable must not be null"); } - int rc = prepare_callable_fn_( - device_ctx_, callable_id, callable, device_id_, aicpu_binary_.data(), aicpu_binary_.size(), - aicore_binary_.data(), aicore_binary_.size() - ); + int rc = prepare_callable_fn_(device_ctx_, callable_id, callable); if (rc != 0) { throw std::runtime_error("prepare_callable failed with code " + std::to_string(rc)); } @@ -326,8 +369,7 @@ void ChipWorker::run_prepared(int32_t callable_id, const void *args, const CallC void *rt = runtime_buf_.data(); int rc = run_prepared_fn_( - device_ctx_, rt, callable_id, args, config.block_dim, config.aicpu_thread_num, device_id_, aicpu_binary_.data(), - aicpu_binary_.size(), aicore_binary_.data(), aicore_binary_.size(), config.enable_l2_swimlane, + device_ctx_, rt, callable_id, args, config.block_dim, config.aicpu_thread_num, config.enable_l2_swimlane, config.enable_dump_tensor, config.enable_pmu, config.enable_dep_gen, config.output_prefix ); if (rc != 0) { diff --git a/src/common/worker/chip_worker.h b/src/common/worker/chip_worker.h index 7fb22fb470..8948f126da 100644 --- a/src/common/worker/chip_worker.h +++ b/src/common/worker/chip_worker.h @@ -107,13 +107,15 @@ class ChipWorker : public IWorker { using CopyToDeviceCtxFn = int (*)(void *, void *, const void *, size_t); using CopyFromDeviceCtxFn = int (*)(void *, void *, const void *, size_t); using GetRuntimeSizeFn = size_t (*)(); - using SimplerInitFn = int (*)(void *, int, int, int); - using PrepareCallableFn = - int (*)(void *, int32_t, const void *, int, const uint8_t *, size_t, const uint8_t *, size_t); - using RunPreparedFn = int (*)( - void *, void *, int32_t, const void *, int, int, int, const uint8_t *, size_t, const uint8_t *, size_t, int, - int, int, int, const char * - ); + // From libsimpler_log.so. Called with (log_level, log_info_v) to seed the + // process-wide HostLogger before host_runtime.so is even opened. + using SimplerLogInitFn = int (*)(int, int); + // From host_runtime.so. Single platform-side init that does (a) thread + // attach + device-id record, (b) executor binary takeover, (c) onboard + // CANN dlog sync. Reads the current log level off HostLogger itself. + using SimplerInitFn = int (*)(void *, int, const uint8_t *, size_t, const uint8_t *, size_t); + using PrepareCallableFn = int (*)(void *, int32_t, const void *); + using RunPreparedFn = int (*)(void *, void *, int32_t, const void *, int, int, int, int, int, int, const char *); using UnregisterCallableFn = int (*)(void *, int32_t); using GetAicpuDlopenCountFn = size_t (*)(void *); using FinalizeDeviceFn = int (*)(void *); @@ -135,6 +137,7 @@ class ChipWorker : public IWorker { CopyToDeviceCtxFn copy_to_device_ctx_fn_ = nullptr; CopyFromDeviceCtxFn copy_from_device_ctx_fn_ = nullptr; GetRuntimeSizeFn get_runtime_size_fn_ = nullptr; + SimplerLogInitFn simpler_log_init_fn_ = nullptr; // resolved from libsimpler_log.so SimplerInitFn simpler_init_fn_ = nullptr; PrepareCallableFn prepare_callable_fn_ = nullptr; RunPreparedFn run_prepared_fn_ = nullptr; @@ -159,8 +162,6 @@ class ChipWorker : public IWorker { void *comm_stream_ = nullptr; std::vector runtime_buf_; - std::vector aicpu_binary_; - std::vector aicore_binary_; // device_id_ is set once in init() and never modified afterward. All // ChipWorker callers run on the thread that called init() (the same // thread is the only one that subsequently calls malloc / copy_to / diff --git a/src/common/worker/pto_runtime_c_api.h b/src/common/worker/pto_runtime_c_api.h index 5c403ee1c9..1f886084f1 100644 --- a/src/common/worker/pto_runtime_c_api.h +++ b/src/common/worker/pto_runtime_c_api.h @@ -82,29 +82,30 @@ int copy_from_device_ctx(DeviceContextHandle ctx, void *host_ptr, const void *de /** * One-shot platform-side init. Called once by ChipWorker::init() right - * after dlopen, before any other entry. Two responsibilities: + * after dlopen, before any other entry. Three responsibilities: * * 1. Attach the calling thread to `device_id` (rtSetDevice on onboard, * pto_cpu_sim_bind_device + pto_cpu_sim_acquire_device on sim) and * record the device id on the DeviceRunner so subsequent device-ops * can re-attach their own caller threads idempotently. * - * 2. Push the user's chosen severity + INFO verbosity into HostLogger - * and into runner state (which run_prepared later forwards to AICPU - * via KernelArgs). + * 2. Take ownership of the AICPU + AICore executor binaries (copied into + * DeviceRunner-owned vectors). All subsequent prepare_callable / + * run_prepared invocations reuse this resident pair — no binary bytes + * cross the C ABI on per-run paths. * - * On onboard, also calls dlog_setlevel(-1, log_level, 0) so CANN's runtime - * filter matches the simpler logger — unless ASCEND_GLOBAL_LOG_LEVEL was - * externally configured, in which case CANN keeps the user's explicit choice. - * - * On sim, no CANN dlog state to touch — only HostLogger + runner. - * - * `log_level` is CANN-aligned: 0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=NUL. - * `log_info_v` ∈ [0, 9]; only meaningful when severity is INFO. + * 3. (Onboard only) Sync CANN dlog with HostLogger::get_instance().level() + * via dlog_setlevel(-1, level, 0), unless ASCEND_GLOBAL_LOG_LEVEL was + * externally configured, in which case CANN keeps the user's choice. + * The log level itself is owned by libsimpler_log.so (seeded earlier + * by simpler_log_init); it never travels through this ABI. * * Returns 0 on success, negative on attach failure. */ -int simpler_init(DeviceContextHandle ctx, int device_id, int log_level, int log_info_v); +int simpler_init( + DeviceContextHandle ctx, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, + const uint8_t *aicore_binary, size_t aicore_size +); /** * Release all device resources held by the context. @@ -135,20 +136,13 @@ int finalize_device(DeviceContextHandle ctx); * one buffer). Subsequent `run_prepared(callable_id, ...)` calls reuse this * state. * - * The `device_id`, `aicpu_binary` / `aicpu_size`, `aicore_binary` / - * `aicore_size` parameters are accepted to keep the signature aligned with - * `run_prepared` so codegen layers can share a single forwarding shim; the - * current implementations ignore them (kernel upload uses the ChipCallable - * payload, and the AICPU / AICore executor binaries are already loaded at - * `simpler_init`). + * `device_id` and the executor binaries are not threaded through this entry + * — they were captured by `simpler_init` and live on the DeviceRunner. * * @return 0 on success, negative on error (NULL ctx, callable_id out of * range, or upload/copy failure). */ -int prepare_callable( - DeviceContextHandle ctx, int32_t callable_id, const void *callable, int device_id, const uint8_t *aicpu_binary, - size_t aicpu_size, const uint8_t *aicore_binary, size_t aicore_size -); +int prepare_callable(DeviceContextHandle ctx, int32_t callable_id, const void *callable); /** * Launch a callable previously staged via `prepare_callable`. @@ -160,12 +154,14 @@ int prepare_callable( * first run for a given callable_id sets `register_new_callable_id_` so the * AICPU does its one-time dlopen. * + * `device_id` and the executor binaries are not threaded through this entry + * — they were captured by `simpler_init` and live on the DeviceRunner. + * * @return 0 on success, negative on error (no prep state, NULL ctx, etc.). */ int run_prepared( DeviceContextHandle ctx, RuntimeHandle runtime, int32_t callable_id, const void *args, int block_dim, - int aicpu_thread_num, int device_id, const uint8_t *aicpu_binary, size_t aicpu_size, const uint8_t *aicore_binary, - size_t aicore_size, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int enable_dep_gen, + int aicpu_thread_num, int enable_l2_swimlane, int enable_dump_tensor, int enable_pmu, int enable_dep_gen, const char *output_prefix );