Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "prof_api_reg.h"
12 : #include <mutex>
13 : #include <unordered_set>
14 : #include <map>
15 : #include "mmpa/mmpa_api.h"
16 : #include "runtime/base.h"
17 : #include "common/log_inner.h"
18 :
19 : namespace {
20 : static bool g_profRun = false;
21 : static std::mutex g_profMutex;
22 : static std::unordered_set<uint32_t> g_deviceList;
23 : constexpr uint64_t ACL_PROF_ACL_API = 0x0001U;
24 : constexpr uint32_t START_PROFILING = 1U;
25 : constexpr uint32_t STOP_PROFILING = 2U;
26 :
27 0 : static bool IsDumpToStdEnabled() {
28 0 : const char *profilingToStdOut = nullptr;
29 0 : MM_SYS_GET_ENV(MM_ENV_GE_PROFILING_TO_STD_OUT, profilingToStdOut);
30 0 : return profilingToStdOut != nullptr;
31 : }
32 :
33 : static const std::map<acl::AclTdtQueueProfType, std::string> TDT_QUEUE_PROF_TYPE_TO_NAMES = {
34 : {acl::AclTdtQueueProfType::AcltdtEnqueue, "acltdtEnqueue"},
35 : {acl::AclTdtQueueProfType::AcltdtDequeue, "acltdtDequeue"},
36 : {acl::AclTdtQueueProfType::AcltdtEnqueueData, "acltdtEnqueueData"},
37 : {acl::AclTdtQueueProfType::AcltdtDequeueData, "acltdtDequeueData"},
38 : };
39 :
40 1 : static aclError RegisterProfType() {
41 5 : for (auto &iter : TDT_QUEUE_PROF_TYPE_TO_NAMES) {
42 4 : const uint32_t typeId = static_cast<uint32_t>(iter.first);
43 4 : const auto ret = MsprofRegTypeInfo(MSPROF_REPORT_ACL_LEVEL, typeId, iter.second.c_str());
44 4 : if (ret != MSPROF_ERROR_NONE) {
45 0 : ACL_LOG_CALL_ERROR("Registered api type [%u] failed = %d", typeId, ret);
46 0 : return ACL_ERROR_PROFILING_FAILURE;
47 : }
48 : }
49 1 : return ACL_SUCCESS;
50 : }
51 :
52 1 : static aclError AddDeviceList(const uint32_t *const deviceIdList, const uint32_t deviceNums)
53 : {
54 1 : ACL_REQUIRES_NOT_NULL(deviceIdList);
55 2 : for (size_t devId = 0U; devId < deviceNums; devId++) {
56 1 : if (g_deviceList.count(*(deviceIdList + devId)) == 0U) {
57 1 : (void)g_deviceList.insert(*(deviceIdList + devId));
58 1 : ACL_LOG_INFO("device id %u is successfully added in acl profiling", *(deviceIdList + devId));
59 : }
60 : }
61 1 : return ACL_SUCCESS;
62 : }
63 :
64 1 : static aclError RemoveDeviceList(const uint32_t *const deviceIdList, const uint32_t deviceNums)
65 : {
66 1 : ACL_REQUIRES_NOT_NULL(deviceIdList);
67 2 : for (size_t devId = 0U; devId < deviceNums; devId++) {
68 1 : const auto iter = g_deviceList.find(*(deviceIdList + devId));
69 1 : if (iter != g_deviceList.end()) {
70 1 : (void)g_deviceList.erase(iter);
71 1 : ACL_LOG_INFO("device id %u is successfully deleted from acl profiling", *(deviceIdList + devId));
72 : }
73 : }
74 1 : return ACL_SUCCESS;
75 : }
76 :
77 1 : static aclError ProfInnerStart(const rtProfCommandHandle_t *const profilerConfig)
78 : {
79 1 : ACL_LOG_INFO("start to execute ProfInnerStart");
80 1 : if (!g_profRun) {
81 1 : (void)RegisterProfType();
82 1 : g_profRun = true;
83 : }
84 1 : (void)AddDeviceList(profilerConfig->devIdList, profilerConfig->devNums);
85 1 : ACL_LOG_INFO("successfully execute ProfInnerStart");
86 1 : return ACL_SUCCESS;
87 : }
88 :
89 1 : static aclError ProfInnerStop(const rtProfCommandHandle_t *const profilerConfig)
90 : {
91 1 : ACL_LOG_INFO("start to execute ProfInnerStop");
92 1 : (void)RemoveDeviceList(profilerConfig->devIdList, profilerConfig->devNums);
93 :
94 1 : if (g_deviceList.empty() && g_profRun) {
95 1 : g_profRun = false;
96 : }
97 1 : ACL_LOG_INFO("successfully execute ProfInnerStop");
98 1 : return ACL_SUCCESS;
99 : }
100 :
101 2 : static aclError ProcessProfData(void *const data, const uint32_t len)
102 : {
103 2 : ACL_LOG_INFO("start to execute ProcessProfData");
104 2 : const std::lock_guard<std::mutex> lk(g_profMutex);
105 2 : ACL_REQUIRES_NOT_NULL(data);
106 2 : constexpr size_t commandLen = sizeof(rtProfCommandHandle_t);
107 2 : if (len < commandLen) {
108 0 : const std::string lenVal = std::to_string(len);
109 0 : std::string errMsg = acl::AclErrorLogManager::FormatStr("len should not be smaller than %zu", commandLen);
110 0 : ACL_LOG_ERROR("[Check][Len]len[%u] is invalid, it should not be smaller than %zu", len, commandLen);
111 0 : acl::AclErrorLogManager::ReportInputError(acl::INVALID_PARAM_REASON_MSG,
112 0 : std::vector<const char *>({"func", "value", "param", "reason"}),
113 0 : std::vector<const char *>({"Processing profiling configuration data", lenVal.c_str(), "len", errMsg.c_str()}));
114 0 : return ACL_ERROR_INVALID_PARAM;
115 0 : }
116 2 : rtProfCommandHandle_t *const profilerConfig = static_cast<rtProfCommandHandle_t *>(data);
117 2 : aclError ret = ACL_SUCCESS;
118 2 : const uint64_t profSwitch = profilerConfig->profSwitch;
119 2 : const uint32_t type = profilerConfig->type;
120 2 : if (((profSwitch & ACL_PROF_ACL_API) != 0U) && (type == START_PROFILING)) {
121 1 : ret = ProfInnerStart(profilerConfig);
122 : }
123 2 : if (((profSwitch & ACL_PROF_ACL_API) != 0U) && (type == STOP_PROFILING)) {
124 1 : ret = ProfInnerStop(profilerConfig);
125 : }
126 :
127 2 : return ret;
128 2 : }
129 :
130 : class AclRegProfCallback {
131 : public:
132 1 : AclRegProfCallback() {
133 1 : const auto profRet = MsprofRegisterCallback(ASCENDCL, &acl::AclTdtQueueProfCtrlHandle);
134 1 : if (profRet != 0) {
135 1 : ACL_LOG_ERROR("can not register Callback, prof result = %d", profRet);
136 : }
137 1 : }
138 : ~AclRegProfCallback() = default;
139 : };
140 : static AclRegProfCallback g_profCbReg;
141 : }
142 :
143 : namespace acl {
144 2 : aclError AclTdtQueueProfCtrlHandle(uint32_t dataType, void *data, uint32_t dataLen)
145 : {
146 2 : ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(data);
147 :
148 2 : if (dataType == RT_PROF_CTRL_SWITCH) {
149 2 : const aclError ret = ProcessProfData(data, dataLen);
150 2 : if (ret != ACL_SUCCESS) {
151 0 : ACL_LOG_INNER_ERROR("[Process][ProfSwitch]failed to call ProcessProfData, result is %u.", ret);
152 0 : return ret;
153 : }
154 2 : return ACL_SUCCESS;
155 : }
156 :
157 0 : ACL_LOG_INFO("get unsupported dataType %u while processing profiling data", dataType);
158 0 : return ACL_SUCCESS;
159 : }
160 :
161 4 : AclTdtQueueProfilingReporter::AclTdtQueueProfilingReporter(const AclTdtQueueProfType apiId) : aclApi_(apiId)
162 : {
163 4 : if (g_profRun && (!IsDumpToStdEnabled())) {
164 0 : startTime_ = MsprofSysCycleTime();
165 : }
166 4 : }
167 :
168 4 : AclTdtQueueProfilingReporter::~AclTdtQueueProfilingReporter() noexcept
169 : {
170 4 : if (g_profRun && (!IsDumpToStdEnabled()) && (startTime_ != 0UL)) {
171 : // 1000 ^ 3 converts second to nanosecond
172 0 : const uint64_t endTime = MsprofSysCycleTime();
173 0 : MsprofApi api{};
174 0 : api.beginTime = startTime_;
175 0 : api.endTime = endTime;
176 0 : thread_local static const auto tid = mmGetTid();
177 0 : api.threadId = static_cast<uint32_t>(tid);
178 0 : api.level = MSPROF_REPORT_ACL_LEVEL;
179 0 : api.type = static_cast<uint32_t>(aclApi_);
180 0 : (void)MsprofReportApi(true, &api);
181 : }
182 4 : }
183 : } // namespace acl
|