Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions docs/chip-level-arch.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
```
Expand Down Expand Up @@ -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
Expand Down
62 changes: 38 additions & 24 deletions docs/dynamic-linking.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
36 changes: 24 additions & 12 deletions docs/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

Expand Down Expand Up @@ -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
}
```

Expand Down Expand Up @@ -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` —
Expand Down
18 changes: 10 additions & 8 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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
Expand Down
10 changes: 6 additions & 4 deletions python/simpler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 5 additions & 3 deletions python/simpler/_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading