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 1 : static aclError RegisterProfType()
42 : {
43 5 : for (auto& iter : TDT_QUEUE_PROF_TYPE_TO_NAMES) {
44 4 : const uint32_t typeId = static_cast<uint32_t>(iter.first);
45 4 : const auto ret = MsprofRegTypeInfo(MSPROF_REPORT_ACL_LEVEL, typeId, iter.second.c_str());
46 4 : if (ret != MSPROF_ERROR_NONE) {
47 0 : ACL_LOG_CALL_ERROR("Registered api type [%u] failed = %d", typeId, ret);
48 0 : return ACL_ERROR_PROFILING_FAILURE;
49 : }
50 : }
51 1 : return ACL_SUCCESS;
52 : }
53 :
54 1 : static aclError AddDeviceList(const uint32_t* const deviceIdList, const uint32_t deviceNums)
55 : {
56 1 : ACL_REQUIRES_NOT_NULL(deviceIdList);
57 2 : for (size_t devId = 0U; devId < deviceNums; devId++) {
58 1 : if (g_deviceList.count(*(deviceIdList + devId)) == 0U) {
59 1 : (void)g_deviceList.insert(*(deviceIdList + devId));
60 1 : ACL_LOG_INFO("device id %u is successfully added in acl profiling", *(deviceIdList + devId));
61 : }
62 : }
63 1 : return ACL_SUCCESS;
64 : }
65 :
66 1 : static aclError RemoveDeviceList(const uint32_t* const deviceIdList, const uint32_t deviceNums)
67 : {
68 1 : ACL_REQUIRES_NOT_NULL(deviceIdList);
69 2 : for (size_t devId = 0U; devId < deviceNums; devId++) {
70 1 : const auto iter = g_deviceList.find(*(deviceIdList + devId));
71 1 : if (iter != g_deviceList.end()) {
72 1 : (void)g_deviceList.erase(iter);
73 1 : ACL_LOG_INFO("device id %u is successfully deleted from acl profiling", *(deviceIdList + devId));
74 : }
75 : }
76 1 : return ACL_SUCCESS;
77 : }
78 :
79 1 : static aclError ProfInnerStart(const rtProfCommandHandle_t* const profilerConfig)
80 : {
81 1 : ACL_LOG_INFO("start to execute ProfInnerStart");
82 1 : if (!g_profRun) {
83 1 : (void)RegisterProfType();
84 1 : g_profRun = true;
85 : }
86 1 : (void)AddDeviceList(profilerConfig->devIdList, profilerConfig->devNums);
87 1 : ACL_LOG_INFO("successfully execute ProfInnerStart");
88 1 : return ACL_SUCCESS;
89 : }
90 :
91 1 : static aclError ProfInnerStop(const rtProfCommandHandle_t* const profilerConfig)
92 : {
93 1 : ACL_LOG_INFO("start to execute ProfInnerStop");
94 1 : (void)RemoveDeviceList(profilerConfig->devIdList, profilerConfig->devNums);
95 :
96 1 : if (g_deviceList.empty() && g_profRun) {
97 1 : g_profRun = false;
98 : }
99 1 : ACL_LOG_INFO("successfully execute ProfInnerStop");
100 1 : return ACL_SUCCESS;
101 : }
102 :
103 2 : static aclError ProcessProfData(void* const data, const uint32_t len)
104 : {
105 2 : ACL_LOG_INFO("start to execute ProcessProfData");
106 2 : const std::lock_guard<std::mutex> lk(g_profMutex);
107 2 : ACL_REQUIRES_NOT_NULL(data);
108 2 : constexpr size_t commandLen = sizeof(rtProfCommandHandle_t);
109 2 : 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 2 : rtProfCommandHandle_t* const profilerConfig = static_cast<rtProfCommandHandle_t*>(data);
120 2 : aclError ret = ACL_SUCCESS;
121 2 : const uint64_t profSwitch = profilerConfig->profSwitch;
122 2 : const uint32_t type = profilerConfig->type;
123 2 : if (((profSwitch & ACL_PROF_ACL_API) != 0U) && (type == START_PROFILING)) {
124 1 : ret = ProfInnerStart(profilerConfig);
125 : }
126 2 : if (((profSwitch & ACL_PROF_ACL_API) != 0U) && (type == STOP_PROFILING)) {
127 1 : ret = ProfInnerStop(profilerConfig);
128 : }
129 :
130 2 : return ret;
131 2 : }
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 2 : aclError AclTdtQueueProfCtrlHandle(uint32_t dataType, void* data, uint32_t dataLen)
149 : {
150 2 : ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(data);
151 :
152 2 : if (dataType == RT_PROF_CTRL_SWITCH) {
153 2 : const aclError ret = ProcessProfData(data, dataLen);
154 2 : 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 2 : 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
|