Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -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<PIPE_V, 1>();
TADD(dstTile, src0Tile, src1Tile);
bisheng::cce::mark_stamp<PIPE_V, 11>();

set_flag(PIPE_V, PIPE_MTE3, EVENT_ID0);
wait_flag(PIPE_V, PIPE_MTE3, EVENT_ID0);
TSTORE(dstGlobal, dstTile);
Expand Down
103 changes: 103 additions & 0 deletions src/a5/platform/include/host/msprof_session.h
Original file line number Diff line number Diff line change
@@ -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=<dir> Output directory; default ./prof_output.
* SIMPLER_MSPROF_AICORE_METRICS=<n> aclprofAicoreMetrics enum value;
* default 1 (ACL_AICORE_PIPE_UTILIZATION).
* SIMPLER_MSPROF_MASK=<hex> 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 <cstdint>
#include <string>

// 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_
1 change: 1 addition & 0 deletions src/a5/platform/onboard/host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down
2 changes: 2 additions & 0 deletions src/a5/platform/onboard/host/pto_runtime_c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -212,6 +213,7 @@ int run_runtime(

std::vector<uint8_t> aicpu_vec(aicpu_binary, aicpu_binary + aicpu_size);
std::vector<uint8_t> 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);
Expand Down
177 changes: 177 additions & 0 deletions src/a5/platform/src/host/msprof_session.cpp
Original file line number Diff line number Diff line change
@@ -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 <cstdlib>
#include <cstring>
#include <dlfcn.h>
#include <string>

#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<int>(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<uint64_t>(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<InitFn>(dlsym(handle_, "aclprofInit"));
finalize_fn_ = reinterpret_cast<FinalizeFn>(dlsym(handle_, "aclprofFinalize"));
create_config = reinterpret_cast<CreateConfigFn>(dlsym(handle_, "aclprofCreateConfig"));
destroy_config = reinterpret_cast<DestroyConfigFn>(dlsym(handle_, "aclprofDestroyConfig"));
start = reinterpret_cast<StartFn>(dlsym(handle_, "aclprofStart"));
stop = reinterpret_cast<StopFn>(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<unsigned long long>(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<uint32_t>(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
Loading