diff --git a/examples/a5/tensormap_and_ringbuffer/vector_example/kernels/aiv/kernel_add.cpp b/examples/a5/tensormap_and_ringbuffer/vector_example/kernels/aiv/kernel_add.cpp index 9e139f9d6..117da0708 100644 --- a/examples/a5/tensormap_and_ringbuffer/vector_example/kernels/aiv/kernel_add.cpp +++ b/examples/a5/tensormap_and_ringbuffer/vector_example/kernels/aiv/kernel_add.cpp @@ -81,7 +81,11 @@ extern "C" __aicore__ __attribute__((always_inline)) void kernel_entry(__gm__ in TLOAD(src1Tile, src1Global); set_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); wait_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); + + bisheng::cce::mark_stamp(); TADD(dstTile, src0Tile, src1Tile); + bisheng::cce::mark_stamp(); + set_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); wait_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); TSTORE(dstGlobal, dstTile); diff --git a/src/a5/platform/include/host/msprof_session.h b/src/a5/platform/include/host/msprof_session.h new file mode 100644 index 000000000..773af2cb8 --- /dev/null +++ b/src/a5/platform/include/host/msprof_session.h @@ -0,0 +1,103 @@ +/* + * 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 msprof_session.h + * @brief Host-driven msprof daemon control via aclprof* C API (route 1). + * + * Triggered by env vars: + * SIMPLER_MSPROF=1 Enable; otherwise everything is no-op. + * SIMPLER_MSPROF_OUT= Output directory; default ./prof_output. + * SIMPLER_MSPROF_AICORE_METRICS= aclprofAicoreMetrics enum value; + * default 1 (ACL_AICORE_PIPE_UTILIZATION). + * SIMPLER_MSPROF_MASK= dataTypeConfig bitmask; + * default 0x4F (ACL_API|TASK_TIME| + * AICORE_METRICS|AICPU|MSPROFTX). + * + * libacl_prof.so is dlopen'd lazily on first use; if dlopen or any dlsym + * fails the session stays disabled and every entry point becomes a no-op. + * + * Lifecycle: + * - Process: MsprofSession singleton dlopens + aclprofInit on first + * MsprofRunScope construction; aclprofFinalize + dlclose run + * from atexit(). + * - Per run: MsprofRunScope wraps a single device launch with + * aclprofCreateConfig + Start (ctor) and Stop + DestroyConfig + * (dtor). Multiple consecutive runs each get their own slice. + */ + +#ifndef SRC_A5_PLATFORM_INCLUDE_HOST_MSPROF_SESSION_H_ +#define SRC_A5_PLATFORM_INCLUDE_HOST_MSPROF_SESSION_H_ + +#include +#include + +// Forward-declare CANN types so this header has no dependency on acl/acl_prof.h +// (the .cpp pulls the real header for typedefs). +struct aclprofConfig; + +namespace msprof { + +class MsprofSession { +public: + static MsprofSession &Instance(); + + // True iff SIMPLER_MSPROF=1, dlopen succeeded, and aclprofInit returned 0. + bool enabled() const { return enabled_; } + + // Function pointers resolved via dlsym. Null when !enabled(). + using CreateConfigFn = aclprofConfig *(*)(uint32_t *, uint32_t, int, const void *, uint64_t); + using DestroyConfigFn = int (*)(const aclprofConfig *); + using StartFn = int (*)(const aclprofConfig *); + using StopFn = int (*)(const aclprofConfig *); + + CreateConfigFn create_config = nullptr; + DestroyConfigFn destroy_config = nullptr; + StartFn start = nullptr; + StopFn stop = nullptr; + + int aicore_metrics() const { return aicore_metrics_; } + uint64_t data_type_config() const { return data_type_config_; } + +private: + MsprofSession(); + ~MsprofSession(); + MsprofSession(const MsprofSession &) = delete; + MsprofSession &operator=(const MsprofSession &) = delete; + + void *handle_ = nullptr; + bool enabled_ = false; + int aicore_metrics_ = 1; // ACL_AICORE_PIPE_UTILIZATION + uint64_t data_type_config_ = 0x4Full; + std::string output_dir_; + + using InitFn = int (*)(const char *, std::size_t); + using FinalizeFn = int (*)(); + InitFn init_fn_ = nullptr; + FinalizeFn finalize_fn_ = nullptr; + + static void AtExitFinalize(); +}; + +class MsprofRunScope { +public: + explicit MsprofRunScope(int device_id); + ~MsprofRunScope(); + MsprofRunScope(const MsprofRunScope &) = delete; + MsprofRunScope &operator=(const MsprofRunScope &) = delete; + +private: + aclprofConfig *cfg_ = nullptr; +}; + +} // namespace msprof + +#endif // SRC_A5_PLATFORM_INCLUDE_HOST_MSPROF_SESSION_H_ diff --git a/src/a5/platform/onboard/host/CMakeLists.txt b/src/a5/platform/onboard/host/CMakeLists.txt index 0232f9b4a..8ceb1474e 100644 --- a/src/a5/platform/onboard/host/CMakeLists.txt +++ b/src/a5/platform/onboard/host/CMakeLists.txt @@ -40,6 +40,7 @@ list(APPEND HOST_RUNTIME_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/platform_compile_info.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/host_regs.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../../src/host/l2_perf_collector.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../../src/host/msprof_session.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../../src/host/pmu_collector.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../../src/host/tensor_dump_collector.cpp" ) 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 fa151b1ab..93d35600c 100644 --- a/src/a5/platform/onboard/host/pto_runtime_c_api.cpp +++ b/src/a5/platform/onboard/host/pto_runtime_c_api.cpp @@ -26,6 +26,7 @@ #include "common/unified_log.h" #include "device_runner.h" #include "host_log.h" +#include "host/msprof_session.h" #include "host/raii_scope_guard.h" #include "runtime.h" @@ -212,6 +213,7 @@ int run_runtime( std::vector aicpu_vec(aicpu_binary, aicpu_binary + aicpu_size); std::vector aicore_vec(aicore_binary, aicore_binary + aicore_size); + msprof::MsprofRunScope prof_scope(device_id); rc = runner->run(*r, block_dim, device_id, aicpu_vec, aicore_vec, aicpu_thread_num); if (rc != 0) { validate_runtime_impl(r); diff --git a/src/a5/platform/src/host/msprof_session.cpp b/src/a5/platform/src/host/msprof_session.cpp new file mode 100644 index 000000000..e0e27231e --- /dev/null +++ b/src/a5/platform/src/host/msprof_session.cpp @@ -0,0 +1,177 @@ +/* + * 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. + * ----------------------------------------------------------------------------------------------------------- + */ + +#include "host/msprof_session.h" + +#include +#include +#include +#include + +#include "common/unified_log.h" + +namespace msprof { + +namespace { + +constexpr const char *kEnvEnable = "SIMPLER_MSPROF"; +constexpr const char *kEnvOutDir = "SIMPLER_MSPROF_OUT"; +constexpr const char *kEnvAicoreMetrics = "SIMPLER_MSPROF_AICORE_METRICS"; +constexpr const char *kEnvMask = "SIMPLER_MSPROF_MASK"; +constexpr const char *kDefaultOutDir = "./prof_output"; +constexpr const char *kAclProfLib = "libacl_prof.so"; + +bool ParseEnabledFlag() { + const char *v = std::getenv(kEnvEnable); + if (v == nullptr) return false; + return v[0] == '1' || v[0] == 't' || v[0] == 'T' || v[0] == 'y' || v[0] == 'Y'; +} + +std::string ParseOutDir() { + const char *v = std::getenv(kEnvOutDir); + return (v == nullptr || v[0] == '\0') ? std::string(kDefaultOutDir) : std::string(v); +} + +int ParseAicoreMetrics(int fallback) { + const char *v = std::getenv(kEnvAicoreMetrics); + if (v == nullptr || v[0] == '\0') return fallback; + char *end = nullptr; + long parsed = std::strtol(v, &end, 0); + if (end == v) return fallback; + return static_cast(parsed); +} + +uint64_t ParseMask(uint64_t fallback) { + const char *v = std::getenv(kEnvMask); + if (v == nullptr || v[0] == '\0') return fallback; + char *end = nullptr; + unsigned long long parsed = std::strtoull(v, &end, 0); + if (end == v) return fallback; + return static_cast(parsed); +} + +} // namespace + +MsprofSession &MsprofSession::Instance() { + static MsprofSession s; + return s; +} + +MsprofSession::MsprofSession() { + if (!ParseEnabledFlag()) { + return; + } + + output_dir_ = ParseOutDir(); + aicore_metrics_ = ParseAicoreMetrics(aicore_metrics_); + data_type_config_ = ParseMask(data_type_config_); + + handle_ = dlopen(kAclProfLib, RTLD_LAZY | RTLD_GLOBAL); + if (handle_ == nullptr) { + LOG_WARN("MsprofSession: dlopen(%s) failed: %s; profiling disabled", kAclProfLib, dlerror()); + return; + } + + init_fn_ = reinterpret_cast(dlsym(handle_, "aclprofInit")); + finalize_fn_ = reinterpret_cast(dlsym(handle_, "aclprofFinalize")); + create_config = reinterpret_cast(dlsym(handle_, "aclprofCreateConfig")); + destroy_config = reinterpret_cast(dlsym(handle_, "aclprofDestroyConfig")); + start = reinterpret_cast(dlsym(handle_, "aclprofStart")); + stop = reinterpret_cast(dlsym(handle_, "aclprofStop")); + + if (init_fn_ == nullptr || finalize_fn_ == nullptr || create_config == nullptr || destroy_config == nullptr || + start == nullptr || stop == nullptr) { + LOG_WARN("MsprofSession: missing aclprof symbols in %s; profiling disabled", kAclProfLib); + dlclose(handle_); + handle_ = nullptr; + init_fn_ = nullptr; + finalize_fn_ = nullptr; + create_config = nullptr; + destroy_config = nullptr; + start = nullptr; + stop = nullptr; + return; + } + + int rc = init_fn_(output_dir_.c_str(), output_dir_.size()); + if (rc != 0) { + LOG_WARN("MsprofSession: aclprofInit(%s) returned %d; profiling disabled", output_dir_.c_str(), rc); + dlclose(handle_); + handle_ = nullptr; + return; + } + + enabled_ = true; + LOG_INFO_V5( + "MsprofSession: enabled, out=%s aicore_metrics=%d mask=0x%llx", output_dir_.c_str(), aicore_metrics_, + static_cast(data_type_config_) + ); + std::atexit(&MsprofSession::AtExitFinalize); +} + +MsprofSession::~MsprofSession() { + // Finalization is owned by AtExitFinalize so it runs once even if the + // singleton's static destructor races with other teardown paths. +} + +void MsprofSession::AtExitFinalize() { + auto &self = Instance(); + if (!self.enabled_) return; + if (self.finalize_fn_ != nullptr) { + int rc = self.finalize_fn_(); + if (rc != 0) { + LOG_WARN("MsprofSession: aclprofFinalize returned %d", rc); + } + } + if (self.handle_ != nullptr) { + dlclose(self.handle_); + self.handle_ = nullptr; + } + self.enabled_ = false; +} + +MsprofRunScope::MsprofRunScope(int device_id) { + auto &session = MsprofSession::Instance(); + if (!session.enabled()) return; + + uint32_t dev = static_cast(device_id); + cfg_ = session.create_config(&dev, 1, session.aicore_metrics(), nullptr, session.data_type_config()); + if (cfg_ == nullptr) { + LOG_WARN("MsprofRunScope: aclprofCreateConfig returned null for device %d", device_id); + return; + } + int rc = session.start(cfg_); + if (rc != 0) { + LOG_WARN("MsprofRunScope: aclprofStart returned %d", rc); + session.destroy_config(cfg_); + cfg_ = nullptr; + } +} + +MsprofRunScope::~MsprofRunScope() { + if (cfg_ == nullptr) return; + auto &session = MsprofSession::Instance(); + if (!session.enabled()) { + cfg_ = nullptr; + return; + } + int rc = session.stop(cfg_); + if (rc != 0) { + LOG_WARN("MsprofRunScope: aclprofStop returned %d", rc); + } + rc = session.destroy_config(cfg_); + if (rc != 0) { + LOG_WARN("MsprofRunScope: aclprofDestroyConfig returned %d", rc); + } + cfg_ = nullptr; +} + +} // namespace msprof