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 : {
29 0 : const char* profilingToStdOut = nullptr;
30 0 : MM_SYS_GET_ENV(MM_ENV_GE_PROFILING_TO_STD_OUT, profilingToStdOut);
31 0 : return profilingToStdOut != nullptr;
32 : }
33 :
34 : static const std::map<acl::AclTdtQueueProfType, std::string> TDT_QUEUE_PROF_TYPE_TO_NAMES = {
35 : {acl::AclTdtQueueProfType::AcltdtEnqueue, "acltdtEnqueue"},
36 : {acl::AclTdtQueueProfType::AcltdtDequeue, "acltdtDequeue"},
37 : {acl::AclTdtQueueProfType::AcltdtEnqueueData, "acltdtEnqueueData"},
38 : {acl::AclTdtQueueProfType::AcltdtDequeueData, "acltdtDequeueData"},
39 : };
40 :
41 2 : static aclError RegisterProfType()
42 : {
43 6 : for (auto& iter : TDT_QUEUE_PROF_TYPE_TO_NAMES) {
44 5 : const uint32_t typeId = static_cast<uint32_t>(iter.first);
45 5 : const auto ret = MsprofRegTypeInfo(MSPROF_REPORT_ACL_LEVEL, typeId, iter.second.c_str());
46 5 : if (ret != MSPROF_ERROR_NONE) {
47 1 : ACL_LOG_CALL_ERROR("Register api type [%s(%u)] failed = %d", iter.second.c_str(), typeId, ret);
48 1 : return ACL_ERROR_PROFILING_FAILURE;
49 : }
50 : }
51 1 : return ACL_SUCCESS;
52 : }
53 :
54 2 : static aclError AddDeviceList(const uint32_t* const deviceIdList, const uint32_t deviceNums)
55 : {
56 2 : ACL_REQUIRES_NOT_NULL(deviceIdList);
57 4 : for (size_t devId = 0U; devId < deviceNums; devId++) {
58 2 : if (g_deviceList.count(*(deviceIdList + devId)) == 0U) {
59 2 : (void)g_deviceList.insert(*(deviceIdList + devId));
60 2 : ACL_LOG_INFO("device id %u is successfully added in acl profiling", *(deviceIdList + devId));
61 : }
62 : }
63 2 : return ACL_SUCCESS;
64 : }
65 :
66 2 : static aclError RemoveDeviceList(const uint32_t* const deviceIdList, const uint32_t deviceNums)
67 : {
68 2 : ACL_REQUIRES_NOT_NULL(deviceIdList);
69 4 : for (size_t devId = 0U; devId < deviceNums; devId++) {
70 2 : const auto iter = g_deviceList.find(*(deviceIdList + devId));
71 2 : if (iter != g_deviceList.end()) {
72 2 : (void)g_deviceList.erase(iter);
73 2 : ACL_LOG_INFO("device id %u is successfully deleted from acl profiling", *(deviceIdList + devId));
74 : }
75 : }
76 2 : return ACL_SUCCESS;
77 : }
78 :
79 2 : static aclError ProfInnerStart(const rtProfCommandHandle_t* const profilerConfig)
80 : {
81 2 : ACL_LOG_INFO("start to execute ProfInnerStart");
82 2 : if (!g_profRun) {
83 2 : (void)RegisterProfType();
84 2 : g_profRun = true;
85 : }
86 2 : (void)AddDeviceList(profilerConfig->devIdList, profilerConfig->devNums);
87 2 : ACL_LOG_INFO("successfully execute ProfInnerStart");
88 2 : return ACL_SUCCESS;
89 : }
90 :
91 2 : static aclError ProfInnerStop(const rtProfCommandHandle_t* const profilerConfig)
92 : {
93 2 : ACL_LOG_INFO("start to execute ProfInnerStop");
94 2 : (void)RemoveDeviceList(profilerConfig->devIdList, profilerConfig->devNums);
95 :
96 2 : if (g_deviceList.empty() && g_profRun) {
97 2 : g_profRun = false;
98 : }
99 2 : ACL_LOG_INFO("successfully execute ProfInnerStop");
100 2 : return ACL_SUCCESS;
101 : }
102 :
103 4 : static aclError ProcessProfData(void* const data, const uint32_t len)
104 : {
105 4 : ACL_LOG_INFO("start to execute ProcessProfData");
106 4 : const std::lock_guard<std::mutex> lk(g_profMutex);
107 4 : ACL_REQUIRES_NOT_NULL(data);
108 4 : constexpr size_t commandLen = sizeof(rtProfCommandHandle_t);
109 4 : if (len < commandLen) {
110 0 : const std::string lenVal = std::to_string(len);
111 0 : std::string errMsg = acl::AclErrorLogManager::FormatStr("len should not be smaller than %zu", commandLen);
112 0 : ACL_LOG_ERROR("[Check][Len]len[%u] is invalid, it should not be smaller than %zu", len, commandLen);
113 0 : acl::AclErrorLogManager::ReportInputError(
114 0 : acl::INVALID_PARAM_REASON_MSG, std::vector<const char*>({"func", "value", "param", "reason"}),
115 0 : std::vector<const char*>(
116 0 : {"Processing profiling configuration data", lenVal.c_str(), "len", errMsg.c_str()}));
117 0 : return ACL_ERROR_INVALID_PARAM;
118 0 : }
119 4 : rtProfCommandHandle_t* const profilerConfig = static_cast<rtProfCommandHandle_t*>(data);
120 4 : aclError ret = ACL_SUCCESS;
121 4 : const uint64_t profSwitch = profilerConfig->profSwitch;
122 4 : const uint32_t type = profilerConfig->type;
123 4 : if (((profSwitch & ACL_PROF_ACL_API) != 0U) && (type == START_PROFILING)) {
124 2 : ret = ProfInnerStart(profilerConfig);
125 : }
126 4 : if (((profSwitch & ACL_PROF_ACL_API) != 0U) && (type == STOP_PROFILING)) {
127 2 : ret = ProfInnerStop(profilerConfig);
128 : }
129 :
130 4 : return ret;
131 4 : }
132 :
133 : class AclRegProfCallback {
134 : public:
135 1 : AclRegProfCallback()
136 : {
137 1 : const auto profRet = MsprofRegisterCallback(ASCENDCL, &acl::AclTdtQueueProfCtrlHandle);
138 1 : if (profRet != 0) {
139 1 : ACL_LOG_ERROR("can not register Callback, prof result = %d", profRet);
140 : }
141 1 : }
142 : ~AclRegProfCallback() = default;
143 : };
144 : static AclRegProfCallback g_profCbReg;
145 : } // namespace
146 :
147 : namespace acl {
148 4 : aclError AclTdtQueueProfCtrlHandle(uint32_t dataType, void* data, uint32_t dataLen)
149 : {
150 4 : ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(data);
151 :
152 4 : if (dataType == RT_PROF_CTRL_SWITCH) {
153 4 : const aclError ret = ProcessProfData(data, dataLen);
154 4 : if (ret != ACL_SUCCESS) {
155 0 : ACL_LOG_INNER_ERROR("[Process][ProfSwitch]failed to call ProcessProfData, result is %u.", ret);
156 0 : return ret;
157 : }
158 4 : return ACL_SUCCESS;
159 : }
160 :
161 0 : ACL_LOG_INFO("get unsupported dataType %u while processing profiling data", dataType);
162 0 : return ACL_SUCCESS;
163 : }
164 :
165 4 : AclTdtQueueProfilingReporter::AclTdtQueueProfilingReporter(const AclTdtQueueProfType apiId) : aclApi_(apiId)
166 : {
167 4 : if (g_profRun && (!IsDumpToStdEnabled())) {
168 0 : startTime_ = MsprofSysCycleTime();
169 : }
170 4 : }
171 :
172 4 : AclTdtQueueProfilingReporter::~AclTdtQueueProfilingReporter() noexcept
173 : {
174 4 : if (g_profRun && (!IsDumpToStdEnabled()) && (startTime_ != 0UL)) {
175 : // 1000 ^ 3 converts second to nanosecond
176 0 : const uint64_t endTime = MsprofSysCycleTime();
177 0 : MsprofApi api{};
178 0 : api.beginTime = startTime_;
179 0 : api.endTime = endTime;
180 0 : thread_local static const auto tid = mmGetTid();
181 0 : api.threadId = static_cast<uint32_t>(tid);
182 0 : api.level = MSPROF_REPORT_ACL_LEVEL;
183 0 : api.type = static_cast<uint32_t>(aclApi_);
184 0 : (void)MsprofReportApi(true, &api);
185 : }
186 4 : }
187 : } // namespace acl
|