From db3442c1f987046768f13f501b57ccd4e498381b Mon Sep 17 00:00:00 2001 From: Chao Wang <26245345+ChaoWao@users.noreply.github.com> Date: Sun, 31 May 2026 12:34:51 +0800 Subject: [PATCH] Refactor: extract near-identical platform files (-1100 lines) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move 6 headers + 1 source whose per-arch differences were ONLY: - Header guards (SRC_A2A3_… vs SRC_A5_…) - Comments naming the arch ("a2a3" / "a5" — generalized to the shared "onboard" / "sim" axis) - Two log-string tweaks in tensor_dump_aicpu.cpp into src/common/platform/include/ + src/common/platform/src/aicpu/. No code-level semantic changes; the per-arch copies were equivalent modulo doc strings. Files moved (canonical copy now in common): - include/common/memory_barrier.h (63) - include/aicpu/tensor_dump_aicpu.h (305) - include/aicpu/device_time.h (28) - include/aicpu/orch_so_file.h (57) - include/host/function_cache.h (122) - include/host/platform_compile_info.h (37) - src/aicpu/tensor_dump_aicpu.cpp (598) Per-arch saved: 1210 Total dedup'd: ~1100 Comment cleanups carried with the move: - device_time.h: "a2a3: Real Ascend hardware" → "onboard: …" - orch_so_file.h: "a2a3 (onboard): pid-based naming" → "onboard: …" - function_cache.h: "a2a3: Real hardware" → "onboard: …" - platform_compile_info.h: "Each platform (a2a3, a2a3sim, ...)" → "Each platform (one of a2a3, a2a3sim, a5, a5sim)" - Header guards normalized to SRC_COMMON_PLATFORM_INCLUDE_… Include-path follow-up: - l2_perf_collector_aicpu.h (still per-arch — DIFF) was doing `#include "device_time.h"` (no subdirectory prefix), which only worked because device_time.h lived alongside it in the same `aicpu/` directory. Now that device_time.h moved up to common/platform/include/aicpu/, qualify the include as `#include "aicpu/device_time.h"` to match the shared search-path shape. Both arches' l2_perf_collector_aicpu.h updated. Builds: - a2a3sim + a5sim host_runtime.so clean - a2a3sim ST L1+L2 pass (38/38, devices 0,1) - a5sim ST L1+L2 pass (22/22, devices 0,1) Stacked on #934 (platform-shared-headers). Co-authored-by: Chao Wang <26245345+ChaoWao@users.noreply.github.com> --- src/a2a3/platform/include/aicpu/device_time.h | 28 - .../aicpu/l2_swimlane_collector_aicpu.h | 2 +- .../include/aicpu/tensor_dump_aicpu.h | 305 --------- .../platform/include/common/memory_barrier.h | 63 -- .../include/host/platform_compile_info.h | 37 -- src/a5/platform/include/aicpu/device_time.h | 28 - .../aicpu/l2_swimlane_collector_aicpu.h | 2 +- src/a5/platform/include/aicpu/orch_so_file.h | 57 -- src/a5/platform/include/host/function_cache.h | 122 ---- .../platform/src/aicpu/tensor_dump_aicpu.cpp | 599 ------------------ .../platform/include/aicpu/device_time.h | 38 ++ .../platform/include/aicpu/orch_so_file.h | 16 +- .../include/aicpu/tensor_dump_aicpu.h | 6 +- .../platform/include/common/memory_barrier.h | 6 +- .../platform/include/host/function_cache.h | 12 +- .../include/host/platform_compile_info.h | 13 +- .../platform/src/aicpu/tensor_dump_aicpu.cpp | 0 17 files changed, 67 insertions(+), 1267 deletions(-) delete mode 100644 src/a2a3/platform/include/aicpu/device_time.h delete mode 100644 src/a2a3/platform/include/aicpu/tensor_dump_aicpu.h delete mode 100644 src/a2a3/platform/include/common/memory_barrier.h delete mode 100644 src/a2a3/platform/include/host/platform_compile_info.h delete mode 100644 src/a5/platform/include/aicpu/device_time.h delete mode 100644 src/a5/platform/include/aicpu/orch_so_file.h delete mode 100644 src/a5/platform/include/host/function_cache.h delete mode 100644 src/a5/platform/src/aicpu/tensor_dump_aicpu.cpp create mode 100644 src/common/platform/include/aicpu/device_time.h rename src/{a2a3 => common}/platform/include/aicpu/orch_so_file.h (82%) rename src/{a5 => common}/platform/include/aicpu/tensor_dump_aicpu.h (98%) rename src/{a5 => common}/platform/include/common/memory_barrier.h (92%) rename src/{a2a3 => common}/platform/include/host/function_cache.h (93%) rename src/{a5 => common}/platform/include/host/platform_compile_info.h (68%) rename src/{a2a3 => common}/platform/src/aicpu/tensor_dump_aicpu.cpp (100%) diff --git a/src/a2a3/platform/include/aicpu/device_time.h b/src/a2a3/platform/include/aicpu/device_time.h deleted file mode 100644 index ea22a44843..0000000000 --- a/src/a2a3/platform/include/aicpu/device_time.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file device_time.h - * @brief AICPU Device Timestamping Interface - * - * Provides get_sys_cnt_aicpu() for AICPU-side timestamping on both - * real hardware and simulation. - * - * Platform Support: - * - a2a3: Real Ascend hardware (reads CNTVCT_EL0) - * - a2a3sim: Host-based simulation using std::chrono - */ - -#ifndef PLATFORM_AICPU_DEVICE_TIME_H_ -#define PLATFORM_AICPU_DEVICE_TIME_H_ - -#include - -/** - * AICPU system counter for performance profiling. - * - * Returns a monotonic counter value compatible with AICore's get_sys_cnt(). - * Implementation is platform-specific (hardware counter or chrono simulation). - * - * @return Counter ticks - */ -uint64_t get_sys_cnt_aicpu(); - -#endif // PLATFORM_AICPU_DEVICE_TIME_H_ diff --git a/src/a2a3/platform/include/aicpu/l2_swimlane_collector_aicpu.h b/src/a2a3/platform/include/aicpu/l2_swimlane_collector_aicpu.h index ecfb9723ef..37d1134a4b 100644 --- a/src/a2a3/platform/include/aicpu/l2_swimlane_collector_aicpu.h +++ b/src/a2a3/platform/include/aicpu/l2_swimlane_collector_aicpu.h @@ -24,7 +24,7 @@ // Include platform-specific timestamp implementation // Build system selects the correct inner_aicpu.h based on platform: // Both provide unified get_sys_cnt_aicpu() interface -#include "device_time.h" +#include "aicpu/device_time.h" // ============= Public Interface ============= diff --git a/src/a2a3/platform/include/aicpu/tensor_dump_aicpu.h b/src/a2a3/platform/include/aicpu/tensor_dump_aicpu.h deleted file mode 100644 index d6babd8f62..0000000000 --- a/src/a2a3/platform/include/aicpu/tensor_dump_aicpu.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) PyPTO Contributors. - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of - * CANN Open Software License Agreement Version 2.0 (the "License"). - * Please refer to the License for details. You may not use this file except in compliance with the License. - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - * See LICENSE in the root of the software repository for the full text of the License. - * ----------------------------------------------------------------------------------------------------------- - */ -/** - * @file tensor_dump_aicpu.h - * @brief AICPU tensor dump collection interface - * - * Provides tensor dump management for AICPU side. - * Handles dump shared-memory base propagation plus buffer initialization, - * tensor data copying to arenas, metadata recording, and flushing. - */ - -#ifndef PLATFORM_AICPU_TENSOR_DUMP_AICPU_H_ -#define PLATFORM_AICPU_TENSOR_DUMP_AICPU_H_ - -#include - -#ifndef __cplusplus -#include -#endif - -#ifdef __cplusplus -#include -#endif - -#include "common/memory_barrier.h" -#include "common/tensor_dump.h" -#include "data_type.h" - -#ifdef __cplusplus -#include "callable.h" -#include "common/unified_log.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Set the tensor dump shared-memory base address. - * Called by the platform layer before AICPU execution starts. - * - * @param dump_data_base Device pointer (as uint64_t) to dump shared memory - */ -void set_platform_dump_base(uint64_t dump_data_base); - -/** - * Get the tensor dump shared-memory base address. - * - * @return Device pointer (as uint64_t) to dump shared memory - */ -uint64_t get_platform_dump_base(); - -/** - * Set whether tensor dump is enabled for this execution. - * Called by the platform layer before AICPU execution starts. - * - * @param enable true to enable tensor dump, false to disable - */ -void set_dump_tensor_enabled(bool enable); - -/** - * Get whether tensor dump is enabled for this execution. - * - * @return true if tensor dump is enabled - */ -bool is_dump_tensor_enabled(); -void set_dump_tensor_selective_mode(bool enable); -bool is_dump_tensor_selective_mode(); -void set_dump_tensor_task_mask(uint64_t task_id, TensorDumpArgMask mask); -TensorDumpArgMask get_dump_tensor_task_mask(uint64_t task_id); - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -bool get_tensor_dump_role_from_direction(ArgDirection dir, TensorDumpRole *role); -int32_t count_callable_tensor_args(const CoreCallable &callable); -bool should_dump_tensor_at_stage(TensorDumpRole role, TensorDumpStage stage); -bool should_dump_task(TensorDumpArgMask arg_mask); -bool should_dump_tensor_arg(TensorDumpArgMask arg_mask, int32_t arg_index); -bool try_log_tensor_dump_layout_mismatch(); -int dump_tensor_record(int thread_idx, const TensorDumpInfo &info); - -template -inline void dump_tensors_for_task( - int32_t thread_idx, const SlotStateT &slot_state, TensorDumpStage stage, IsSubtaskActiveFn is_subtask_active, - GetFunctionBinAddrFn get_function_bin_addr -) { - const auto &pl = *slot_state.payload; - TensorDumpArgMask dump_arg_mask = TENSOR_DUMP_ARG_MASK_NONE; - if (is_dump_tensor_selective_mode()) { - dump_arg_mask = get_dump_tensor_task_mask(slot_state.task->task_id.raw); - } - if (!should_dump_task(dump_arg_mask)) { - return; - } - const CoreCallable *callables[MaxSubtaskSlots] = {}; - int32_t total_tensor_args = 0; - - for (int raw_subtask_id = 0; raw_subtask_id < MaxSubtaskSlots; raw_subtask_id++) { - if (!is_subtask_active(slot_state.active_mask, raw_subtask_id)) { - continue; - } - int32_t slot_idx = raw_subtask_id; - uint64_t callable_addr = get_function_bin_addr(slot_state.task->kernel_id[slot_idx]); - if (callable_addr == 0) { - return; - } - callables[slot_idx] = reinterpret_cast(callable_addr); - total_tensor_args += count_callable_tensor_args(*callables[slot_idx]); - } - - if (total_tensor_args != pl.tensor_count) { - if (try_log_tensor_dump_layout_mismatch()) { - LOG_WARN( - "Thread %d: tensor dump skipped for task 0x%" PRIx64 - ": active callable tensor count (%d) does not match payload tensor count (%d). " - "Task-level dump assumes payload tensors are concatenated by active subtask order.", - thread_idx, static_cast(slot_state.task->task_id.raw), total_tensor_args, pl.tensor_count - ); - } - return; - } - - rmb(); - - int32_t payload_index = 0; - for (int raw_subtask_id = 0; raw_subtask_id < MaxSubtaskSlots; raw_subtask_id++) { - if (!is_subtask_active(slot_state.active_mask, raw_subtask_id)) { - continue; - } - int32_t slot_idx = raw_subtask_id; - const CoreCallable &callable = *callables[slot_idx]; - for (int32_t sig_idx = 0; sig_idx < callable.sig_count(); sig_idx++) { - ArgDirection dir = callable.sig(sig_idx); - if (dir == ArgDirection::SCALAR) { - continue; - } - TensorDumpRole role; - if (get_tensor_dump_role_from_direction(dir, &role) && should_dump_tensor_at_stage(role, stage) && - should_dump_tensor_arg(dump_arg_mask, payload_index)) { - const auto &t = pl.tensors[payload_index]; - TensorDumpInfo info = {}; - info.buffer_addr = t.buffer.addr; - info.dtype = static_cast(t.dtype); - info.ndims = static_cast(t.ndims); - info.start_offset = t.start_offset; - for (uint32_t d = 0; d < t.ndims && d < PLATFORM_DUMP_MAX_DIMS; d++) { - info.shapes[d] = t.shapes[d]; - info.strides[d] = t.strides[d]; - } - info.task_id = slot_state.task->task_id.raw; - info.subtask_id = raw_subtask_id; - info.func_id = slot_state.task->kernel_id[slot_idx]; - info.arg_index = static_cast(payload_index); - info.role = role; - info.stage = stage; - dump_tensor_record(thread_idx, info); - } - payload_index++; - } - } -} - -template -inline void dump_tensors_for_task( - int32_t thread_idx, uint64_t task_id, uint8_t subtask_id, int32_t task_arg_count, int32_t func_id, - const CoreCallable &callable, const TensorInfoT *tensor_info, int32_t tensor_info_count, - const uint64_t *buffer_addrs, int32_t buffer_count, TensorDumpStage stage -) { - int32_t sig_count = callable.sig_count(); - if (task_arg_count < sig_count) { - static bool logged_task_signature_mismatch = false; - if (!logged_task_signature_mismatch) { - logged_task_signature_mismatch = true; - LOG_WARN( - "Thread %d: tensor dump skipped for task 0x%" PRIx64 - ": task args (%d) smaller than callable signature (%d)", - thread_idx, task_id, task_arg_count, sig_count - ); - } - return; - } - - int32_t tensor_arg_count = count_callable_tensor_args(callable); - if (tensor_info == nullptr || tensor_info_count != tensor_arg_count) { - if (tensor_arg_count == 0) { - return; - } - if (try_log_tensor_dump_layout_mismatch()) { - LOG_WARN( - "Thread %d: tensor dump skipped for task 0x%" PRIx64 - ": callable tensor args (%d) do not match registered tensor info (%d)", - thread_idx, task_id, tensor_arg_count, tensor_info_count - ); - } - return; - } - - if (buffer_addrs == nullptr || buffer_count != tensor_arg_count) { - static bool logged_task_tensor_addr_mismatch = false; - if (!logged_task_tensor_addr_mismatch) { - logged_task_tensor_addr_mismatch = true; - LOG_WARN( - "Thread %d: tensor dump skipped for task 0x%" PRIx64 - ": reconstructed tensor buffers (%d) do not match callable tensor args (%d)", - thread_idx, task_id, buffer_count, tensor_arg_count - ); - } - return; - } - - rmb(); - - int32_t tensor_arg_index = 0; - for (int32_t sig_idx = 0; sig_idx < sig_count; sig_idx++) { - ArgDirection dir = callable.sig(sig_idx); - if (dir == ArgDirection::SCALAR) { - continue; - } - - TensorDumpRole role; - if (!get_tensor_dump_role_from_direction(dir, &role) || !should_dump_tensor_at_stage(role, stage)) { - tensor_arg_index++; - continue; - } - - const auto &t = tensor_info[tensor_arg_index]; - TensorDumpInfo info = {}; - info.task_id = task_id; - info.subtask_id = subtask_id; - info.role = role; - info.stage = stage; - info.dtype = static_cast(t.dtype); - info.ndims = t.ndims; - info.func_id = static_cast(func_id); - info.arg_index = static_cast(tensor_arg_index); - info.buffer_addr = buffer_addrs[tensor_arg_index]; - // TensorInfo (host_build_graph) still carries (raw_shapes, offsets) - // implicitly describing a row-major-aligned sub-region. Translate to - // (start_offset, strides[]) on the fly: - // strides[d] = prod(raw_shapes[d+1..]) - // start_offset = Σ offsets[d] · strides[d] - uint64_t s = 1; - uint64_t start = 0; - for (int32_t d = static_cast(t.ndims) - 1; d >= 0 && d < PLATFORM_DUMP_MAX_DIMS; --d) { - info.shapes[d] = t.shapes[d]; - info.strides[d] = static_cast(s); - start += static_cast(t.offsets[d]) * s; - s *= t.raw_shapes[d]; - } - info.start_offset = start; - dump_tensor_record(thread_idx, info); - tensor_arg_index++; - } -} - -/** - * Initialize tensor dump. - * - * Sets up per-thread DumpBufferState pointers and pops initial - * metadata buffers from each thread's free_queue. - * - * @param num_dump_threads Number of scheduling threads that will dump tensors - */ -void dump_tensor_init(int num_dump_threads); - -/** - * Record a single tensor dump. - * - * Copies tensor data from GM to the thread's arena, appends a - * TensorDumpRecord to the current metadata buffer. Switches - * buffers when full via the SPSC free_queue. - * - * When metadata buffers are temporarily exhausted, old dump metadata may be - * overwritten so execution can continue without losing the active buffer. - * - * @param thread_idx Scheduling thread index - * @param info Tensor metadata and identification - * @return 0 on success or intentional drop, -1 only when dump state is unavailable - */ -int dump_tensor_record(int thread_idx, const TensorDumpInfo &info); - -/** - * Flush remaining tensor dump data for a thread. - * - * Marks non-empty metadata buffers as ready and enqueues them - * for host collection. - * - * @param thread_idx Thread index - */ -void dump_tensor_flush(int thread_idx); - -#endif - -#endif // PLATFORM_AICPU_TENSOR_DUMP_AICPU_H_ diff --git a/src/a2a3/platform/include/common/memory_barrier.h b/src/a2a3/platform/include/common/memory_barrier.h deleted file mode 100644 index 404dff12c6..0000000000 --- a/src/a2a3/platform/include/common/memory_barrier.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) PyPTO Contributors. - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of - * CANN Open Software License Agreement Version 2.0 (the "License"). - * Please refer to the License for details. You may not use this file except in compliance with the License. - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - * See LICENSE in the root of the software repository for the full text of the License. - * ----------------------------------------------------------------------------------------------------------- - */ - -/** - * @file memory_barrier.h - * @brief Memory barrier definitions for shared memory synchronization - * - * This header provides platform-specific memory barrier macros for - * synchronizing shared memory accesses between Host, AICPU, and AICore. - * - * Memory barriers ensure that: - * - Read barriers (rmb): All reads before the barrier complete before any reads after - * - Write barriers (wmb): All writes before the barrier complete before any writes after - * - * These are critical for correct operation of lock-free data structures - * and shared memory protocols across different processing units. - */ - -#ifndef SRC_A2A3_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ -#define SRC_A2A3_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ - -// ============================================================================= -// Memory Barrier Macros -// ============================================================================= - -#ifdef __aarch64__ -/** - * Read memory barrier (ARM64) - * Ensures all loads before this point complete before any loads after. - */ -#define rmb() __asm__ __volatile__("dsb ld" ::: "memory") - -/** - * Write memory barrier (ARM64) - * Ensures all stores before this point complete before any stores after. - */ -#define wmb() __asm__ __volatile__("dsb st" ::: "memory") - -/** - * Store-store barrier (ARM64, inner shareable domain) - * Ensures all stores before this barrier are globally visible before any - * stores after. - */ -#define OUT_OF_ORDER_STORE_BARRIER() __asm__ __volatile__("dmb ishst" ::: "memory") -#else -/** - * Compiler barrier (fallback for non-ARM64 platforms) - * Prevents compiler reordering but does not emit hardware barriers. - */ -#define rmb() __asm__ __volatile__("" ::: "memory") -#define wmb() __asm__ __volatile__("" ::: "memory") -#define OUT_OF_ORDER_STORE_BARRIER() __asm__ __volatile__("" ::: "memory") -#endif - -#endif // SRC_A2A3_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ diff --git a/src/a2a3/platform/include/host/platform_compile_info.h b/src/a2a3/platform/include/host/platform_compile_info.h deleted file mode 100644 index 0813ead860..0000000000 --- a/src/a2a3/platform/include/host/platform_compile_info.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) PyPTO Contributors. - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of - * CANN Open Software License Agreement Version 2.0 (the "License"). - * Please refer to the License for details. You may not use this file except in compliance with the License. - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - * See LICENSE in the root of the software repository for the full text of the License. - * ----------------------------------------------------------------------------------------------------------- - */ -/** - * Platform Compile Info Interface - * - * Minimal interface: platform only declares its identity. - * Each platform (a2a3, a2a3sim, ...) implements get_platform() to return - * its name. Runtime code uses this to decide which toolchain to use. - */ - -#ifndef PLATFORM_COMPILE_INFO_H -#define PLATFORM_COMPILE_INFO_H - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Get the platform name. - * - * @return Platform identifier string (e.g., "a2a3", "a2a3sim") - */ -const char *get_platform(void); - -#ifdef __cplusplus -} -#endif - -#endif /* PLATFORM_COMPILE_INFO_H */ diff --git a/src/a5/platform/include/aicpu/device_time.h b/src/a5/platform/include/aicpu/device_time.h deleted file mode 100644 index 85a7d31e3d..0000000000 --- a/src/a5/platform/include/aicpu/device_time.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @file device_time.h - * @brief AICPU Device Timestamping Interface - * - * Provides get_sys_cnt_aicpu() for AICPU-side timestamping on both - * real hardware and simulation. - * - * Platform Support: - * - a5: Real Ascend hardware (reads CNTVCT_EL0) - * - a5sim: Host-based simulation using std::chrono - */ - -#ifndef PLATFORM_AICPU_DEVICE_TIME_H_ -#define PLATFORM_AICPU_DEVICE_TIME_H_ - -#include - -/** - * AICPU system counter for performance profiling. - * - * Returns a monotonic counter value compatible with AICore's get_sys_cnt(). - * Implementation is platform-specific (hardware counter or chrono simulation). - * - * @return Counter ticks - */ -uint64_t get_sys_cnt_aicpu(); - -#endif // PLATFORM_AICPU_DEVICE_TIME_H_ diff --git a/src/a5/platform/include/aicpu/l2_swimlane_collector_aicpu.h b/src/a5/platform/include/aicpu/l2_swimlane_collector_aicpu.h index e3680fd17a..269619aa53 100644 --- a/src/a5/platform/include/aicpu/l2_swimlane_collector_aicpu.h +++ b/src/a5/platform/include/aicpu/l2_swimlane_collector_aicpu.h @@ -25,7 +25,7 @@ // Include platform-specific timestamp implementation // Build system selects the correct inner_aicpu.h based on platform: // Both provide unified get_sys_cnt_aicpu() interface -#include "device_time.h" +#include "aicpu/device_time.h" // ============= Public Interface ============= diff --git a/src/a5/platform/include/aicpu/orch_so_file.h b/src/a5/platform/include/aicpu/orch_so_file.h deleted file mode 100644 index 162e12dcb0..0000000000 --- a/src/a5/platform/include/aicpu/orch_so_file.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) PyPTO Contributors. - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of - * CANN Open Software License Agreement Version 2.0 (the "License"). - * Please refer to the License for details. You may not use this file except in compliance with the License. - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - * See LICENSE in the root of the software repository for the full text of the License. - * ----------------------------------------------------------------------------------------------------------- - */ -/** - * @file orch_so_file.h - * @brief Orchestration SO File Creation Interface for AICPU - * - * Creates a writable, executable-mode file under a candidate directory for - * staging the device orchestration shared library prior to dlopen. - * - * Platform Support: - * - a5 (onboard): pid-based naming via open() with mode 0755. AICPU device - * libc may not provide mkstemps, and only one runtime runs per device process. - * - a5sim (simulation): mkstemps() with fchmod(0755). Multiple sim workers - * can share a process, so names must be unique per call. - */ - -#ifndef PLATFORM_AICPU_ORCH_SO_FILE_H_ -#define PLATFORM_AICPU_ORCH_SO_FILE_H_ - -#include -#include - -/** - * Create a unique orchestration SO file under `dir`. - * - * On success, writes the full chosen path into `out_path` (null-terminated) - * and returns an open writable fd (caller must close). Permissions are set - * so the file is executable (0755) and suitable for dlopen. - * - * On failure (path too long, directory not writable, etc.), returns -1. - * Caller is expected to try the next candidate directory. - * - * @param dir Candidate directory (e.g. "/tmp") - * @param callable_id Per-callable_id table slot id (>= 0). Required for - * uniqueness on the onboard path so concurrently- - * resident orch SOs (one per cid) do not collide on - * the same on-disk file. Pass -1 for the legacy - * single-slot dispatch path. - * @param device_id ACL device ordinal, suffixed onto the onboard name so - * the paired dies of one chip (which share this preinstall - * filesystem) never stage/execute the same on-disk file. - * @param out_path Buffer that receives the full file path on success - * @param out_path_size Size of `out_path` in bytes - * @return Open writable fd on success, -1 on failure - */ -int32_t -create_orch_so_file(const char *dir, int32_t callable_id, int32_t device_id, char *out_path, size_t out_path_size); - -#endif // PLATFORM_AICPU_ORCH_SO_FILE_H_ diff --git a/src/a5/platform/include/host/function_cache.h b/src/a5/platform/include/host/function_cache.h deleted file mode 100644 index 545140d430..0000000000 --- a/src/a5/platform/include/host/function_cache.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) PyPTO Contributors. - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of - * CANN Open Software License Agreement Version 2.0 (the "License"). - * Please refer to the License for details. You may not use this file except in compliance with the License. - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - * See LICENSE in the root of the software repository for the full text of the License. - * ----------------------------------------------------------------------------------------------------------- - */ -/** - * @file function_cache.h - * @brief Function Cache Structures for Kernel Binary Management - * - * Defines data structures for caching compiled kernel binaries and managing - * their addresses in memory (device GM memory for a5, host memory for a5sim). - * - * Platform Support: - * - a5: Real hardware with device GM memory - * - a5sim: Host-based simulation with host memory - * - * These structures follow the production system design from: - * - src/interface/cache/core_func_data.h - * - src/interface/cache/function_cache.h - * - * Memory Layout: - * ┌────────────────────────────────────────────────┐ - * │ CoreFunctionBinCache │ - * │ ┌────────────────────────────────────────────┐ │ - * │ │ data_size │ │ - * │ ├────────────────────────────────────────────┤ │ - * │ │ offset[0] │ │ - * │ │ offset[1] │ │ - * │ │ ... │ │ - * │ ├────────────────────────────────────────────┤ │ - * │ │ CoreFunctionBin[0] │ │ - * │ │ size │ │ - * │ │ data[...binary...] │ │ - * │ ├────────────────────────────────────────────┤ │ - * │ │ CoreFunctionBin[1] │ │ - * │ │ size │ │ - * │ │ data[...binary...] │ │ - * │ └────────────────────────────────────────────┘ │ - * └────────────────────────────────────────────────┘ - */ - -#ifndef PLATFORM_FUNCTION_CACHE_H_ -#define PLATFORM_FUNCTION_CACHE_H_ - -#include - -/** - * Single kernel binary container - * - * Contains the size and binary data for one compiled kernel. - * The data field is a flexible array member that extends beyond - * the struct boundary. - */ -#pragma pack(1) -struct CoreFunctionBin { - uint64_t size; // Size of binary data in bytes - uint8_t data[0]; // Flexible array member for kernel binary -}; -#pragma pack() - -/** - * Binary cache structure for all kernels - * - * This structure packs multiple kernel binaries into a single contiguous - * memory block for efficient memory allocation and copying. - * - * Memory Layout: - * [data_size][num_kernels][offset0][offset1]...[offsetN][CoreFunctionBin0][CoreFunctionBin1]... - * - * Each offset points to the start of a CoreFunctionBin structure relative - * to the beginning of the cache. - * - * Platform Behavior: - * - a5: Binaries are copied to device GM memory - * - a5sim: Binaries are kept in host memory or registered as function pointers - */ -struct CoreFunctionBinCache { - uint64_t data_size; // Total size of all data (excluding this header) - uint64_t num_kernels; // Number of kernels in this cache - - /** - * Get offset array pointer - * @return Pointer to array of offsets - */ - uint64_t *get_offsets() { - return reinterpret_cast(reinterpret_cast(this) + sizeof(CoreFunctionBinCache)); - } - - /** - * Get pointer to binary data region - * @return Pointer to start of binary data - */ - uint8_t *get_binary_data() { return reinterpret_cast(get_offsets()) + num_kernels * sizeof(uint64_t); } - - /** - * Get CoreFunctionBin by index - * @param index Kernel index - * @return Pointer to CoreFunctionBin structure, nullptr if invalid index - */ - CoreFunctionBin *get_kernel(uint64_t index) { - if (index >= num_kernels) { - return nullptr; - } - uint64_t offset = get_offsets()[index]; - return reinterpret_cast(get_binary_data() + offset); - } - - /** - * Calculate total cache size including header - * @return Total size in bytes - */ - uint64_t get_total_size() const { - return sizeof(CoreFunctionBinCache) + num_kernels * sizeof(uint64_t) + data_size; - } -}; - -#endif // PLATFORM_FUNCTION_CACHE_H_ diff --git a/src/a5/platform/src/aicpu/tensor_dump_aicpu.cpp b/src/a5/platform/src/aicpu/tensor_dump_aicpu.cpp deleted file mode 100644 index 15eb4405a5..0000000000 --- a/src/a5/platform/src/aicpu/tensor_dump_aicpu.cpp +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Copyright (c) PyPTO Contributors. - * This program is free software, you can redistribute it and/or modify it under the terms and conditions of - * CANN Open Software License Agreement Version 2.0 (the "License"). - * Please refer to the License for details. You may not use this file except in compliance with the License. - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. - * See LICENSE in the root of the software repository for the full text of the License. - * ----------------------------------------------------------------------------------------------------------- - */ - -/** - * @file tensor_dump_aicpu.cpp - * @brief AICPU tensor dump collection implementation - * - * Mirrors l2_swimlane_collector_aicpu.cpp patterns: - * - Per-thread DumpBufferState with SPSC free queues - * - Per-thread ready queue for handing off full metadata buffers - * - Per-thread circular arena for tensor payload data - */ - -#include "aicpu/tensor_dump_aicpu.h" - -#include -#include - -#include "common/memory_barrier.h" -#include "common/platform_config.h" -#include "common/unified_log.h" - -// Cached pointers for hot-path access (set during init) -static uint64_t g_platform_dump_base = 0; -static DumpDataHeader *s_dump_header = nullptr; -static DumpBufferState *s_dump_states[PLATFORM_MAX_AICPU_THREADS] = {}; -static DumpMetaBuffer *s_current_dump_buf[PLATFORM_MAX_AICPU_THREADS] = {}; - -static bool s_logged_ready_queue_full[PLATFORM_MAX_AICPU_THREADS] = {}; -static bool s_logged_no_free_meta_buffer[PLATFORM_MAX_AICPU_THREADS] = {}; -static bool s_logged_dump_layout_mismatch = false; -static uint32_t s_records_written[PLATFORM_MAX_AICPU_THREADS] = {}; -static uint32_t s_buffers_switched[PLATFORM_MAX_AICPU_THREADS] = {}; -static uint32_t s_buffers_flushed[PLATFORM_MAX_AICPU_THREADS] = {}; - -static inline void account_dropped_records(DumpBufferState *state, uint32_t dropped_records) { - if (state == nullptr || dropped_records == 0) { - return; - } - uint32_t prev = state->dropped_record_count; - uint32_t next = prev + dropped_records; - state->dropped_record_count = (next < prev) ? UINT32_MAX : next; -} - -extern "C" void set_platform_dump_base(uint64_t dump_data_base) { g_platform_dump_base = dump_data_base; } - -extern "C" uint64_t get_platform_dump_base() { return g_platform_dump_base; } - -static bool g_enable_dump_tensor = false; -static bool g_dump_tensor_selective_mode = false; -struct DumpTaskMaskEntry { - uint64_t task_id; - TensorDumpArgMask mask; -}; -static constexpr uint64_t DUMP_TASK_MASK_EMPTY_TASK_ID = UINT64_MAX; -static constexpr uint32_t DUMP_TASK_MASK_TABLE_CAPACITY = 32768; -static DumpTaskMaskEntry *g_dump_mask_table = nullptr; -static bool ensure_dump_mask_table() { - if (g_dump_mask_table != nullptr) { - return true; - } - g_dump_mask_table = - static_cast(malloc(sizeof(DumpTaskMaskEntry) * DUMP_TASK_MASK_TABLE_CAPACITY)); - if (g_dump_mask_table == nullptr) { - LOG_ERROR("Failed to allocate tensor dump selective mask table"); - return false; - } - for (uint32_t i = 0; i < DUMP_TASK_MASK_TABLE_CAPACITY; i++) { - g_dump_mask_table[i].task_id = DUMP_TASK_MASK_EMPTY_TASK_ID; - g_dump_mask_table[i].mask = TENSOR_DUMP_ARG_MASK_NONE; - } - return true; -} - -static void clear_dump_mask_table() { - if (g_dump_mask_table == nullptr) { - return; - } - for (uint32_t i = 0; i < DUMP_TASK_MASK_TABLE_CAPACITY; i++) { - g_dump_mask_table[i].task_id = DUMP_TASK_MASK_EMPTY_TASK_ID; - g_dump_mask_table[i].mask = TENSOR_DUMP_ARG_MASK_NONE; - } -} - -extern "C" void set_dump_tensor_enabled(bool enable) { - g_enable_dump_tensor = enable; - g_dump_tensor_selective_mode = false; - clear_dump_mask_table(); -} - -extern "C" bool is_dump_tensor_enabled() { return g_enable_dump_tensor; } - -extern "C" void set_dump_tensor_selective_mode(bool enable) { g_dump_tensor_selective_mode = enable; } - -extern "C" bool is_dump_tensor_selective_mode() { return g_dump_tensor_selective_mode; } - -extern "C" void set_dump_tensor_task_mask(uint64_t task_id, TensorDumpArgMask mask) { - if (mask == TENSOR_DUMP_ARG_MASK_NONE) { - return; - } - if (!ensure_dump_mask_table()) { - return; - } - uint32_t ring_id = static_cast(task_id >> 32); - if (ring_id >= TENSOR_DUMP_MASK_POOL_MAX_RINGS) { - return; - } - uint32_t slot = static_cast(task_id) & TENSOR_DUMP_MASK_POOL_DEFAULT_SLOT_MASK; - uint32_t idx = (ring_id * TENSOR_DUMP_MASK_POOL_MAX_SLOTS + slot) & (DUMP_TASK_MASK_TABLE_CAPACITY - 1); - for (uint32_t probe = 0; probe < DUMP_TASK_MASK_TABLE_CAPACITY; probe++) { - DumpTaskMaskEntry &entry = g_dump_mask_table[(idx + probe) & (DUMP_TASK_MASK_TABLE_CAPACITY - 1)]; - if (entry.task_id == DUMP_TASK_MASK_EMPTY_TASK_ID || entry.task_id == task_id) { - entry.task_id = task_id; - entry.mask = mask; - return; - } - } - LOG_ERROR("tensor dump selective mask table is full"); -} - -extern "C" TensorDumpArgMask get_dump_tensor_task_mask(uint64_t task_id) { - if (g_dump_mask_table == nullptr) { - return TENSOR_DUMP_ARG_MASK_NONE; - } - uint32_t ring_id = static_cast(task_id >> 32); - if (ring_id >= TENSOR_DUMP_MASK_POOL_MAX_RINGS) { - return TENSOR_DUMP_ARG_MASK_NONE; - } - uint32_t slot = static_cast(task_id) & TENSOR_DUMP_MASK_POOL_DEFAULT_SLOT_MASK; - uint32_t idx = (ring_id * TENSOR_DUMP_MASK_POOL_MAX_SLOTS + slot) & (DUMP_TASK_MASK_TABLE_CAPACITY - 1); - for (uint32_t probe = 0; probe < DUMP_TASK_MASK_TABLE_CAPACITY; probe++) { - const DumpTaskMaskEntry &entry = g_dump_mask_table[(idx + probe) & (DUMP_TASK_MASK_TABLE_CAPACITY - 1)]; - if (entry.task_id == task_id) { - return entry.mask; - } - if (entry.task_id == DUMP_TASK_MASK_EMPTY_TASK_ID) { - return TENSOR_DUMP_ARG_MASK_NONE; - } - } - return TENSOR_DUMP_ARG_MASK_NONE; -} - -bool get_tensor_dump_role_from_direction(ArgDirection dir, TensorDumpRole *role) { - switch (dir) { - case ArgDirection::IN: - *role = TensorDumpRole::INPUT; - return true; - case ArgDirection::OUT: - *role = TensorDumpRole::OUTPUT; - return true; - case ArgDirection::INOUT: - *role = TensorDumpRole::INOUT; - return true; - case ArgDirection::SCALAR: - return false; - } - return false; -} - -int32_t count_callable_tensor_args(const CoreCallable &callable) { - int32_t tensor_count = 0; - for (int32_t i = 0; i < callable.sig_count(); i++) { - if (callable.sig(i) != ArgDirection::SCALAR) { - tensor_count++; - } - } - return tensor_count; -} - -bool should_dump_tensor_at_stage(TensorDumpRole role, TensorDumpStage stage) { - switch (role) { - case TensorDumpRole::INPUT: - return stage == TensorDumpStage::BEFORE_DISPATCH; - case TensorDumpRole::OUTPUT: - return stage == TensorDumpStage::AFTER_COMPLETION; - case TensorDumpRole::INOUT: - return true; - } - return false; -} - -bool should_dump_task(TensorDumpArgMask arg_mask) { - if (!is_dump_tensor_selective_mode()) { - return true; - } - return arg_mask != TENSOR_DUMP_ARG_MASK_NONE; -} - -bool should_dump_tensor_arg(TensorDumpArgMask arg_mask, int32_t arg_index) { - if (!is_dump_tensor_selective_mode()) { - return true; - } - if (arg_index < 0 || arg_index >= static_cast(TENSOR_DUMP_ARG_MASK_BITS)) return false; - return (arg_mask & (TensorDumpArgMask{1} << arg_index)) != 0; -} - -bool try_log_tensor_dump_layout_mismatch() { - if (s_logged_dump_layout_mismatch) { - return false; - } - s_logged_dump_layout_mismatch = true; - return true; -} - -/** - * Enqueue a full dump metadata buffer to the thread's ready queue. - */ -static int enqueue_dump_ready_buffer(int thread_idx, uint64_t buffer_ptr, uint32_t buffer_seq) { - uint32_t capacity = PLATFORM_DUMP_READYQUEUE_SIZE; - uint32_t current_tail = s_dump_header->queue_tails[thread_idx]; - uint32_t current_head = s_dump_header->queue_heads[thread_idx]; - - uint32_t next_tail = (current_tail + 1) % capacity; - if (next_tail == current_head) { - return -1; // Queue full - } - - s_dump_header->queues[thread_idx][current_tail].thread_index = static_cast(thread_idx); - s_dump_header->queues[thread_idx][current_tail].buffer_ptr = buffer_ptr; - s_dump_header->queues[thread_idx][current_tail].buffer_seq = buffer_seq; - wmb(); - s_dump_header->queue_tails[thread_idx] = next_tail; - wmb(); - - return 0; -} - -/** - * Maximum spin-wait iterations when free_queue or ready_queue is exhausted. - * Gives host mgmt_loop time to replenish before falling back to buffer overwrite. - */ -static constexpr uint32_t DUMP_SPIN_WAIT_LIMIT = 1000000; - -/** - * Switch metadata buffer: enqueue the full buffer, pop a new one. - * Spin-waits briefly for host to replenish before falling back to overwrite. - */ -static int switch_dump_meta_buffer(int thread_idx) { - if (thread_idx < 0 || thread_idx >= PLATFORM_MAX_AICPU_THREADS) { - return -1; - } - DumpBufferState *state = s_dump_states[thread_idx]; - DumpMetaBuffer *cur = s_current_dump_buf[thread_idx]; - if (state == nullptr || cur == nullptr) { - return -1; - } - - // Spin-wait for a free buffer, giving host mgmt_loop time to replenish - rmb(); - uint32_t head = state->free_queue.head; - uint32_t tail = state->free_queue.tail; - if (head == tail) { - for (uint32_t spin = 0; spin < DUMP_SPIN_WAIT_LIMIT; spin++) { - rmb(); - head = state->free_queue.head; - tail = state->free_queue.tail; - if (head != tail) { - break; - } - } - } - if (head == tail) { - // Still empty after spin — overwrite current buffer - account_dropped_records(state, cur->count); - cur->count = 0; - wmb(); - if (!s_logged_no_free_meta_buffer[thread_idx]) { - s_logged_no_free_meta_buffer[thread_idx] = true; - LOG_WARN( - "Tensor dump ran out of free metadata buffers on thread %d after spin-wait, " - "overwriting current buffer. Increase PLATFORM_DUMP_BUFFERS_PER_THREAD.", - thread_idx - ); - } - return 0; - } - - // Enqueue the full buffer (spin-wait if ready queue is full) - uint64_t buf_addr = reinterpret_cast(cur); - uint32_t seq = state->current_buf_seq; - int rc = enqueue_dump_ready_buffer(thread_idx, buf_addr, seq); - if (rc != 0) { - for (uint32_t spin = 0; spin < DUMP_SPIN_WAIT_LIMIT; spin++) { - rmb(); - rc = enqueue_dump_ready_buffer(thread_idx, buf_addr, seq); - if (rc == 0) { - break; - } - } - } - if (rc != 0) { - // Still full after spin — overwrite current buffer - account_dropped_records(state, cur->count); - cur->count = 0; - wmb(); - if (!s_logged_ready_queue_full[thread_idx]) { - s_logged_ready_queue_full[thread_idx] = true; - LOG_WARN( - "Tensor dump ready queue full on thread %d after spin-wait, " - "overwriting current buffer. Increase PLATFORM_DUMP_READYQUEUE_SIZE.", - thread_idx - ); - } - return 0; - } - - // Pop next buffer from free_queue - uint64_t new_ptr = state->free_queue.buffer_ptrs[head % PLATFORM_DUMP_SLOT_COUNT]; - rmb(); - state->free_queue.head = head + 1; - - DumpMetaBuffer *new_buf = reinterpret_cast(new_ptr); - new_buf->count = 0; - s_current_dump_buf[thread_idx] = new_buf; - state->current_buf_ptr = new_ptr; - state->current_buf_seq = seq + 1; - wmb(); - - s_buffers_switched[thread_idx]++; - - return 0; -} - -struct CircularArenaWriter { - char *arena; - uint64_t arena_size; - uint64_t base_offset; - uint64_t bytes_written; - - void write(const void *src, uint64_t size) { - if (size == 0) { - return; - } - uint64_t pos = (base_offset + bytes_written) % arena_size; - if (pos + size <= arena_size) { - memcpy(arena + pos, src, size); - } else { - uint64_t first = arena_size - pos; - memcpy(arena + pos, src, first); - memcpy(arena, reinterpret_cast(src) + first, size - first); - } - bytes_written += size; - } -}; - -static inline uint64_t get_tensor_dump_num_elements(const TensorDumpInfo &info) { - uint64_t elements = 1; - for (uint32_t d = 0; d < info.ndims && d < PLATFORM_DUMP_MAX_DIMS; d++) { - elements *= info.shapes[d]; - } - return elements; -} - -// PyTorch-style contiguous: strides[d] == prod(shapes[d+1..]) for all d. -static inline bool tensor_dump_is_contiguous(const TensorDumpInfo &info) { - if (info.ndims == 0) return true; - uint64_t expected = 1; - for (int32_t d = static_cast(info.ndims) - 1; d >= 0 && d < PLATFORM_DUMP_MAX_DIMS; --d) { - if (info.strides[d] != expected) return false; - expected *= info.shapes[d]; - } - return true; -} - -static inline void write_tensor_dump_contiguous_prefix( - CircularArenaWriter *writer, const TensorDumpInfo &info, uint64_t elem_sz, uint64_t copy_bytes -) { - const char *src = reinterpret_cast(info.buffer_addr) + info.start_offset * elem_sz; - writer->write(src, copy_bytes); -} - -// Recursive per-dim gather: at dim d we step shapes[d] times with element step -// strides[d]. Inner-most dim writes `shapes[d]` contiguous elements (only valid -// when strides[innermost] == 1 — non-unit innermost stride degrades to per-element). -static void gather_tensor_dump_dim( - CircularArenaWriter *writer, const TensorDumpInfo &info, uint64_t elem_sz, uint32_t dim, - uint64_t base_element_index, uint64_t *remaining_bytes -) { - if (*remaining_bytes == 0 || dim >= PLATFORM_DUMP_MAX_DIMS) { - return; - } - if (dim + 1 >= info.ndims) { - // Innermost dim: if strides[dim] == 1 the row is contiguous in memory and - // a single memcpy works. Otherwise emit element-by-element. - const uint32_t s = info.strides[dim]; - if (s == 1) { - const char *src = reinterpret_cast(info.buffer_addr) + base_element_index * elem_sz; - uint64_t row_bytes = - static_cast(info.shapes[dim]) * elem_sz; // promote first to avoid uint32 overflow - uint64_t bytes_to_copy = (row_bytes < *remaining_bytes) ? row_bytes : *remaining_bytes; - writer->write(src, bytes_to_copy); - *remaining_bytes -= bytes_to_copy; - } else { - for (uint32_t i = 0; i < info.shapes[dim] && *remaining_bytes >= elem_sz; i++) { - uint64_t pos = base_element_index + static_cast(i) * static_cast(s); - const char *src = reinterpret_cast(info.buffer_addr) + pos * elem_sz; - writer->write(src, elem_sz); - *remaining_bytes -= elem_sz; - } - } - return; - } - - const int32_t s = info.strides[dim]; - for (uint32_t i = 0; i < info.shapes[dim] && *remaining_bytes > 0; i++) { - uint64_t next_base = base_element_index + static_cast(i) * static_cast(s); - gather_tensor_dump_dim(writer, info, elem_sz, dim + 1, next_base, remaining_bytes); - } -} - -static inline void write_tensor_dump_logical_prefix( - CircularArenaWriter *writer, const TensorDumpInfo &info, uint64_t elem_sz, uint64_t copy_bytes -) { - if (copy_bytes == 0) { - return; - } - if (tensor_dump_is_contiguous(info)) { - write_tensor_dump_contiguous_prefix(writer, info, elem_sz, copy_bytes); - return; - } - // Walk the view origin first; per-dim recursion adds (i * strides[d]) for each axis. - uint64_t remaining_bytes = copy_bytes; - gather_tensor_dump_dim(writer, info, elem_sz, 0, info.start_offset, &remaining_bytes); -} - -void dump_tensor_init(int num_dump_threads) { - void *dump_base = reinterpret_cast(get_platform_dump_base()); - if (dump_base == nullptr) { - LOG_ERROR("platform dump base is NULL, cannot initialize tensor dump"); - return; - } - - s_dump_header = get_dump_header(dump_base); - - LOG_INFO_V0("Initializing tensor dump for %d threads (memcpy-based)", num_dump_threads); - - // Pop initial metadata buffer from free_queue for each thread - for (int t = 0; t < num_dump_threads; t++) { - DumpBufferState *state = get_dump_buffer_state(dump_base, t); - s_dump_states[t] = state; - - rmb(); - uint32_t head = state->free_queue.head; - uint32_t tail = state->free_queue.tail; - if (head != tail) { - uint64_t buf_ptr = state->free_queue.buffer_ptrs[head % PLATFORM_DUMP_SLOT_COUNT]; - rmb(); - state->free_queue.head = head + 1; - wmb(); - - DumpMetaBuffer *buf = reinterpret_cast(buf_ptr); - buf->count = 0; - s_current_dump_buf[t] = buf; - state->current_buf_ptr = buf_ptr; - state->current_buf_seq = 0; - wmb(); - LOG_DEBUG("Thread %d: popped initial dump buffer (addr=0x%lx)", t, buf_ptr); - } else { - LOG_ERROR("Thread %d: dump free_queue is empty during init!", t); - s_current_dump_buf[t] = nullptr; - state->current_buf_ptr = 0; - } - } - - memset(s_logged_ready_queue_full, 0, sizeof(s_logged_ready_queue_full)); - memset(s_logged_no_free_meta_buffer, 0, sizeof(s_logged_no_free_meta_buffer)); - memset(s_records_written, 0, sizeof(s_records_written)); - memset(s_buffers_switched, 0, sizeof(s_buffers_switched)); - memset(s_buffers_flushed, 0, sizeof(s_buffers_flushed)); -} - -int dump_tensor_record(int thread_idx, const TensorDumpInfo &info) { - if (s_dump_header == nullptr) { - return -1; - } - if (thread_idx < 0 || thread_idx >= PLATFORM_MAX_AICPU_THREADS) { - return -1; - } - - DumpBufferState *state = s_dump_states[thread_idx]; - DumpMetaBuffer *buf = s_current_dump_buf[thread_idx]; - if (buf == nullptr) { - return -1; - } - - // Switch metadata buffer if full - if (buf->count >= PLATFORM_DUMP_RECORDS_PER_BUFFER) { - if (switch_dump_meta_buffer(thread_idx) != 0) { - return -1; // No free buffer - } - buf = s_current_dump_buf[thread_idx]; - if (buf == nullptr) { - return -1; - } - } - - // Reserve space in arena - // Compute actual tensor data size from shape (not buffer.size which may include padding) - uint64_t actual_elements = get_tensor_dump_num_elements(info); - uint64_t elem_sz = get_element_size(static_cast(info.dtype)); - uint64_t bytes = actual_elements * elem_sz; - uint64_t copy_bytes = bytes; - bool truncated = false; - bool is_contiguous = tensor_dump_is_contiguous(info); - - if (bytes > state->arena_size) { - // Tensor larger than entire arena — copy a partial sample - copy_bytes = state->arena_size / 2; - truncated = true; - } - - uint64_t offset = state->arena_write_offset; - state->arena_write_offset = offset + copy_bytes; - - // Copy tensor data into arena (circular wraparound) - char *arena = reinterpret_cast(state->arena_base); - uint64_t arena_sz = state->arena_size; - CircularArenaWriter writer = {arena, arena_sz, offset, 0}; - write_tensor_dump_logical_prefix(&writer, info, elem_sz, copy_bytes); - wmb(); - - // Append metadata record - uint32_t idx = buf->count; - TensorDumpRecord *rec = &buf->records[idx]; - rec->task_id = info.task_id; - rec->subtask_id = info.subtask_id; - rec->func_id = info.func_id; - rec->arg_index = info.arg_index; - rec->is_contiguous = is_contiguous ? 1 : 0; - rec->role = static_cast(info.role); - rec->stage = static_cast(info.stage); - rec->ndims = info.ndims; - rec->dtype = info.dtype; - rec->truncated = truncated ? 1 : 0; - rec->payload_offset = offset; - rec->payload_size = copy_bytes; - rec->start_offset = info.start_offset; - for (int d = 0; d < info.ndims && d < PLATFORM_DUMP_MAX_DIMS; d++) { - rec->shapes[d] = info.shapes[d]; - rec->strides[d] = info.strides[d]; - } - buf->count = idx + 1; - wmb(); - - s_records_written[thread_idx]++; - - return 0; -} - -void dump_tensor_flush(int thread_idx) { - if (s_dump_header == nullptr) { - return; - } - if (thread_idx < 0 || thread_idx >= PLATFORM_MAX_AICPU_THREADS) { - return; - } - - DumpMetaBuffer *buf = s_current_dump_buf[thread_idx]; - DumpBufferState *state = s_dump_states[thread_idx]; - if (buf != nullptr && buf->count > 0 && state != nullptr) { - uint64_t buf_addr = reinterpret_cast(buf); - uint32_t seq = state->current_buf_seq; - if (enqueue_dump_ready_buffer(thread_idx, buf_addr, seq) == 0) { - s_current_dump_buf[thread_idx] = nullptr; - state->current_buf_ptr = 0; - wmb(); - } else { - // ready_queue full at end-of-run: account the loss and clear the - // buffer so host reconcile sees a clean state (current_buf_ptr=0) - // and dropped == flush failures rather than silent leftover. - // Bounded to one per thread per run (unlike the hot-path - // dump_tensor_record site), so no spam guard is needed here. - LOG_ERROR( - "Thread %d: failed to flush tensor-dump buffer (ready_queue full), %u records lost!", thread_idx, - buf->count - ); - account_dropped_records(state, buf->count); - buf->count = 0; - s_current_dump_buf[thread_idx] = nullptr; - state->current_buf_ptr = 0; - wmb(); - } - } - - s_buffers_flushed[thread_idx]++; - uint32_t dropped = s_dump_states[thread_idx] ? s_dump_states[thread_idx]->dropped_record_count : 0; - LOG_INFO_V0( - "Thread %d: dump_tensor_flush (records=%u, buf_switches=%u, flushes=%u, dropped=%u)", thread_idx, - s_records_written[thread_idx], s_buffers_switched[thread_idx], s_buffers_flushed[thread_idx], dropped - ); -} diff --git a/src/common/platform/include/aicpu/device_time.h b/src/common/platform/include/aicpu/device_time.h new file mode 100644 index 0000000000..97967596e9 --- /dev/null +++ b/src/common/platform/include/aicpu/device_time.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) PyPTO Contributors. + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of + * CANN Open Software License Agreement Version 2.0 (the "License"). + * Please refer to the License for details. You may not use this file except in compliance with the License. + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. + * See LICENSE in the root of the software repository for the full text of the License. + * ----------------------------------------------------------------------------------------------------------- + */ +/** + * @file device_time.h + * @brief AICPU Device Timestamping Interface + * + * Provides get_sys_cnt_aicpu() for AICPU-side timestamping on both + * real hardware and simulation. + * + * Platform Support (same shape for both arches): + * - onboard: Real Ascend hardware (reads CNTVCT_EL0) + * - sim: Host-based simulation using std::chrono + */ + +#ifndef SRC_COMMON_PLATFORM_INCLUDE_AICPU_DEVICE_TIME_H_ +#define SRC_COMMON_PLATFORM_INCLUDE_AICPU_DEVICE_TIME_H_ + +#include + +/** + * AICPU system counter for performance profiling. + * + * Returns a monotonic counter value compatible with AICore's get_sys_cnt(). + * Implementation is platform-specific (hardware counter or chrono simulation). + * + * @return Counter ticks + */ +uint64_t get_sys_cnt_aicpu(); + +#endif // SRC_COMMON_PLATFORM_INCLUDE_AICPU_DEVICE_TIME_H_ diff --git a/src/a2a3/platform/include/aicpu/orch_so_file.h b/src/common/platform/include/aicpu/orch_so_file.h similarity index 82% rename from src/a2a3/platform/include/aicpu/orch_so_file.h rename to src/common/platform/include/aicpu/orch_so_file.h index ef13c029d0..2ecf2b3bf9 100644 --- a/src/a2a3/platform/include/aicpu/orch_so_file.h +++ b/src/common/platform/include/aicpu/orch_so_file.h @@ -15,15 +15,15 @@ * Creates a writable, executable-mode file under a candidate directory for * staging the device orchestration shared library prior to dlopen. * - * Platform Support: - * - a2a3 (onboard): pid-based naming via open() with mode 0755. AICPU device - * libc may not provide mkstemps, and only one runtime runs per device process. - * - a2a3sim (simulation): mkstemps() with fchmod(0755). Multiple sim workers - * can share a process, so names must be unique per call. + * Platform Support (same shape for both arches): + * - onboard: pid-based naming via open() with mode 0755. AICPU device libc + * may not provide mkstemps, and only one runtime runs per device process. + * - sim: mkstemps() with fchmod(0755). Multiple sim workers can share a + * process, so names must be unique per call. */ -#ifndef PLATFORM_AICPU_ORCH_SO_FILE_H_ -#define PLATFORM_AICPU_ORCH_SO_FILE_H_ +#ifndef SRC_COMMON_PLATFORM_INCLUDE_AICPU_ORCH_SO_FILE_H_ +#define SRC_COMMON_PLATFORM_INCLUDE_AICPU_ORCH_SO_FILE_H_ #include #include @@ -54,4 +54,4 @@ int32_t create_orch_so_file(const char *dir, int32_t callable_id, int32_t device_id, char *out_path, size_t out_path_size); -#endif // PLATFORM_AICPU_ORCH_SO_FILE_H_ +#endif // SRC_COMMON_PLATFORM_INCLUDE_AICPU_ORCH_SO_FILE_H_ diff --git a/src/a5/platform/include/aicpu/tensor_dump_aicpu.h b/src/common/platform/include/aicpu/tensor_dump_aicpu.h similarity index 98% rename from src/a5/platform/include/aicpu/tensor_dump_aicpu.h rename to src/common/platform/include/aicpu/tensor_dump_aicpu.h index 5d124b082d..fc5f57365f 100644 --- a/src/a5/platform/include/aicpu/tensor_dump_aicpu.h +++ b/src/common/platform/include/aicpu/tensor_dump_aicpu.h @@ -17,8 +17,8 @@ * tensor data copying to arenas, metadata recording, and flushing. */ -#ifndef SRC_A5_PLATFORM_AICPU_TENSOR_DUMP_AICPU_H_ -#define SRC_A5_PLATFORM_AICPU_TENSOR_DUMP_AICPU_H_ +#ifndef SRC_COMMON_PLATFORM_INCLUDE_AICPU_TENSOR_DUMP_AICPU_H_ +#define SRC_COMMON_PLATFORM_INCLUDE_AICPU_TENSOR_DUMP_AICPU_H_ #include @@ -302,4 +302,4 @@ void dump_tensor_flush(int thread_idx); #endif -#endif // SRC_A5_PLATFORM_AICPU_TENSOR_DUMP_AICPU_H_ +#endif // SRC_COMMON_PLATFORM_INCLUDE_AICPU_TENSOR_DUMP_AICPU_H_ diff --git a/src/a5/platform/include/common/memory_barrier.h b/src/common/platform/include/common/memory_barrier.h similarity index 92% rename from src/a5/platform/include/common/memory_barrier.h rename to src/common/platform/include/common/memory_barrier.h index c0771b058d..841239421d 100644 --- a/src/a5/platform/include/common/memory_barrier.h +++ b/src/common/platform/include/common/memory_barrier.h @@ -24,8 +24,8 @@ * and shared memory protocols across different processing units. */ -#ifndef SRC_A5_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ -#define SRC_A5_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ +#ifndef SRC_COMMON_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ +#define SRC_COMMON_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ // ============================================================================= // Memory Barrier Macros @@ -60,4 +60,4 @@ #define OUT_OF_ORDER_STORE_BARRIER() __asm__ __volatile__("" ::: "memory") #endif -#endif // SRC_A5_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ +#endif // SRC_COMMON_PLATFORM_INCLUDE_COMMON_MEMORY_BARRIER_H_ diff --git a/src/a2a3/platform/include/host/function_cache.h b/src/common/platform/include/host/function_cache.h similarity index 93% rename from src/a2a3/platform/include/host/function_cache.h rename to src/common/platform/include/host/function_cache.h index dfbea88443..a24fb2241a 100644 --- a/src/a2a3/platform/include/host/function_cache.h +++ b/src/common/platform/include/host/function_cache.h @@ -13,11 +13,11 @@ * @brief Function Cache Structures for Kernel Binary Management * * Defines data structures for caching compiled kernel binaries and managing - * their addresses in memory (device GM memory for a2a3, host memory for a2a3sim). + * their addresses in memory (device GM memory onboard, host memory on sim). * - * Platform Support: - * - a2a3: Real hardware with device GM memory - * - a2a3sim: Host-based simulation with host memory + * Platform Support (same shape for both arches): + * - onboard: Real hardware with device GM memory + * - sim: Host-based simulation with host memory * * These structures follow the production system design from: * - src/interface/cache/core_func_data.h @@ -76,8 +76,8 @@ struct CoreFunctionBin { * to the beginning of the cache. * * Platform Behavior: - * - a2a3: Binaries are copied to device GM memory - * - a2a3sim: Binaries are kept in host memory or registered as function pointers + * - onboard: Binaries are copied to device GM memory + * - sim: Binaries are kept in host memory or registered as function pointers */ struct CoreFunctionBinCache { uint64_t data_size; // Total size of all data (excluding this header) diff --git a/src/a5/platform/include/host/platform_compile_info.h b/src/common/platform/include/host/platform_compile_info.h similarity index 68% rename from src/a5/platform/include/host/platform_compile_info.h rename to src/common/platform/include/host/platform_compile_info.h index 8f999e4b7a..fd353278f0 100644 --- a/src/a5/platform/include/host/platform_compile_info.h +++ b/src/common/platform/include/host/platform_compile_info.h @@ -12,12 +12,13 @@ * Platform Compile Info Interface * * Minimal interface: platform only declares its identity. - * Each platform (a5, a5sim, ...) implements get_platform() to return - * its name. Runtime code uses this to decide which toolchain to use. + * Each platform implements get_platform() to return its name (one of + * a2a3 / a2a3sim / a5 / a5sim). Runtime code uses this to decide which + * toolchain to use. */ -#ifndef PLATFORM_COMPILE_INFO_H -#define PLATFORM_COMPILE_INFO_H +#ifndef SRC_COMMON_PLATFORM_INCLUDE_HOST_PLATFORM_COMPILE_INFO_H_ +#define SRC_COMMON_PLATFORM_INCLUDE_HOST_PLATFORM_COMPILE_INFO_H_ #ifdef __cplusplus extern "C" { @@ -26,7 +27,7 @@ extern "C" { /** * Get the platform name. * - * @return Platform identifier string (e.g., "a5", "a5sim") + * @return Platform identifier string (one of "a2a3", "a2a3sim", "a5", "a5sim") */ const char *get_platform(void); @@ -34,4 +35,4 @@ const char *get_platform(void); } #endif -#endif /* PLATFORM_COMPILE_INFO_H */ +#endif /* SRC_COMMON_PLATFORM_INCLUDE_HOST_PLATFORM_COMPILE_INFO_H_ */ diff --git a/src/a2a3/platform/src/aicpu/tensor_dump_aicpu.cpp b/src/common/platform/src/aicpu/tensor_dump_aicpu.cpp similarity index 100% rename from src/a2a3/platform/src/aicpu/tensor_dump_aicpu.cpp rename to src/common/platform/src/aicpu/tensor_dump_aicpu.cpp