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 : #ifndef COMMON_AICPUSD_UTIL_H
12 : #define COMMON_AICPUSD_UTIL_H
13 :
14 : #include <signal.h>
15 : #include <sys/wait.h>
16 : #include <functional>
17 : #include <string.h>
18 : #include "aicpusd_status.h"
19 : #include "aicpusd_info.h"
20 : #include "profiling_adp.h"
21 : #include "aicpu_context.h"
22 : #include "aicpusd_drv_manager.h"
23 :
24 : namespace AicpuSchedule {
25 : constexpr int32_t MAX_ENV_CHAR_NUM = 1024;
26 : const std::string ENV_NAME_PROCMGR_AICPU_CPUSET = "PROCMGR_AICPU_CPUSET";
27 :
28 22 : inline uint64_t TickInterval2Microsecond(const uint64_t tickStart,
29 : const uint64_t tickEnd,
30 : const uint64_t tickFreq)
31 : {
32 22 : if ((tickFreq == 0UL) || (tickEnd <= tickStart)) {
33 19 : return 0UL;
34 : }
35 : // tickFreq is record by second, to microsecond need multiply 1000000
36 3 : return ((tickEnd - tickStart) * 1000000UL) / tickFreq;
37 : }
38 :
39 : class AicpuUtil {
40 : public:
41 2 : static int32_t ExecuteCmd(const std::string &cmd)
42 : {
43 : /**
44 : * system() may fail due to "No child processes".
45 : * if SIGCHLD is set to SIG_IGN, waitpid() may report ECHILD error because it cannot find the child process.
46 : * The reason is that the system() relies on a feature of the system, that is,
47 : * when the kernel initializes the process, the processing mode of SIGCHLD signal is SIG_IGN.
48 : */
49 2 : if (cmd.empty()) {
50 1 : return -1;
51 : }
52 :
53 1 : const sighandler_t oldHandler = signal(SIGCHLD, SIG_DFL);
54 1 : int32_t status = 0;
55 1 : int32_t pid = 0;
56 1 : if ((pid = vfork()) < 0) {
57 1 : status = -1;
58 0 : } else if (pid == 0) {
59 0 : (void)execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
60 0 : constexpr int32_t executeCmdErr = 127;
61 0 : _exit(executeCmdErr);
62 : } else {
63 0 : while (waitpid(pid, &status, 0) < 0) {
64 0 : if (errno != EINTR) {
65 0 : status = -1;
66 0 : break;
67 : }
68 : }
69 : }
70 1 : (void)signal(SIGCHLD, oldHandler);
71 1 : return status;
72 : }
73 11 : static void SetProfData(const std::shared_ptr<aicpu::ProfMessage> profMsg,
74 : const aicpu::aicpuProfContext_t &aicpuProfCtx,
75 : const uint32_t threadIndex,
76 : const uint64_t streamId,
77 : const uint64_t taskId)
78 : {
79 11 : if (profMsg == nullptr) {
80 0 : return;
81 : }
82 :
83 11 : const uint64_t tickAfterRun = aicpu::GetSystemTick();
84 11 : const uint64_t tickFreq = aicpu::GetSystemTickFreq();
85 11 : const uint64_t dispatchTime = TickInterval2Microsecond(aicpuProfCtx.drvSubmitTick,
86 11 : aicpuProfCtx.tickBeforeRun,
87 : tickFreq);
88 11 : const uint64_t totalTime = TickInterval2Microsecond(aicpuProfCtx.drvSubmitTick,
89 : tickAfterRun,
90 : tickFreq);
91 :
92 : (void)profMsg->SetAicpuMagicNumber(static_cast<uint16_t>(MSPROF_DATA_HEAD_MAGIC_NUM))
93 : ->SetAicpuDataTag(static_cast<uint16_t>(MSPROF_AICPU_DATA_TAG))
94 : ->SetStreamId(static_cast<uint16_t>(streamId))
95 : ->SetTaskId(static_cast<uint16_t>(taskId))
96 : ->SetThreadId(threadIndex)
97 11 : ->SetDeviceId(AicpuDrvManager::GetInstance().GetDeviceId())
98 11 : ->SetKernelType(aicpuProfCtx.kernelType)
99 11 : ->SetSubmitTick(aicpuProfCtx.drvSubmitTick)
100 11 : ->SetScheduleTick(aicpuProfCtx.drvSchedTick)
101 11 : ->SetTickBeforeRun(aicpuProfCtx.tickBeforeRun)
102 : ->SetTickAfterRun(tickAfterRun)
103 : ->SetDispatchTime(static_cast<uint32_t>(dispatchTime))
104 : ->SetTotalTime(static_cast<uint32_t>(totalTime))
105 22 : ->SetVersion(aicpu::AICPU_PROF_VERSION);
106 :
107 11 : (void)aicpu::SetProfHandle(nullptr);
108 : }
109 : /**
110 : * @ingroup AicpusdUtil
111 : * @brief it is used to uniformly normalized error code.
112 : * @param [in] errCode: original error code.
113 : * @return uniformly normalized error code
114 : */
115 10 : static int32_t TransformInnerErrCode(const int32_t errCode)
116 : {
117 10 : return ((errCode > AICPU_SCHEDULE_ERROR_RESERVED) || (errCode < AICPU_SCHEDULE_OK)) ?
118 10 : AICPU_SCHEDULE_ERROR_INNER_ERROR : errCode;
119 : }
120 :
121 : /**
122 : * @ingroup AicpuUtil
123 : * @brief it is used to check exception by read FPSR Register.
124 : * @param [out] result : exception type.
125 : * @return has any exception, true if has
126 : */
127 : static bool CheckOverflow(int32_t &result)
128 : {
129 : #if (defined __ARM_ARCH) || (defined PLATFORM_AARCH64)
130 : int64_t regContent;
131 : __asm volatile(
132 : "MRS %0, FPSR"
133 : : "=r" (regContent)
134 : :
135 : : "memory"
136 : );
137 : aicpusd_info("Custom Scheduler Read FPSR:[%d].", regContent);
138 : if ((regContent & (1 << 3)) != 0) { // UFC(3)
139 : result = AICPU_SCHEDULE_ERROR_UNDERFLOW;
140 : return true;
141 : } else if ((regContent & (1 << 2)) != 0) { // OFC(2)
142 : result = AICPU_SCHEDULE_ERROR_OVERFLOW;
143 : return true;
144 : } else if ((regContent & (1 << 1)) != 0) { // DZC(1)
145 : result = AICPU_SCHEDULE_ERROR_DIVISIONZERO;
146 : return true;
147 : }
148 : #endif
149 : return false;
150 : }
151 :
152 : /**
153 : * @ingroup AicpuUtil
154 : * @brief it is used to reset FPSR Register.
155 : */
156 1 : static void ResetFpsr()
157 : {
158 : #if (defined __ARM_ARCH) || (defined PLATFORM_AARCH64)
159 : aicpusd_info("Custom Scheduler Reset FPSR.");
160 : __asm volatile(
161 : "BIC x0, x0, #0xffffffff \n\t"
162 : "MSR FPSR, x0":::"x0"
163 : );
164 : #endif
165 1 : }
166 :
167 67 : static bool TransStrToUint(const std::string ¶, uint32_t &value)
168 : {
169 : try {
170 67 : value = std::stoul(para);
171 3 : } catch (...) {
172 3 : return false;
173 3 : }
174 :
175 64 : return true;
176 : }
177 :
178 206 : static bool TransStrToInt(const std::string ¶, int32_t &value)
179 : {
180 : try {
181 206 : value = std::stoi(para);
182 9 : } catch (...) {
183 9 : return false;
184 9 : }
185 :
186 197 : return true;
187 : }
188 :
189 13 : static bool GetEnvVal(const std::string &env, std::string &val)
190 : {
191 13 : if (env.empty()) {
192 0 : return false;
193 : }
194 :
195 13 : const char *const tmpVal = std::getenv(env.c_str());
196 13 : if ((tmpVal == nullptr) || (strnlen(tmpVal, MAX_ENV_CHAR_NUM) >= MAX_ENV_CHAR_NUM)) {
197 2 : val = "";
198 2 : return false;
199 : }
200 :
201 11 : val = tmpVal;
202 11 : return true;
203 : }
204 :
205 : /**
206 : * @ingroup AicpuUtil
207 : * @brief Is env value is same as expected value
208 : * @param [in] env : env name
209 : * @param [in] expectVal : expected env value
210 : * @return bool: true, if env val is same as expected value; otherwise, false
211 : */
212 13 : static bool IsEnvValEqual(const std::string &env, const std::string &expectVal)
213 : {
214 13 : std::string getedEnvVal;
215 13 : const bool ret = GetEnvVal(env, getedEnvVal);
216 13 : if (!ret) {
217 2 : return false;
218 : }
219 :
220 11 : return (getedEnvVal == expectVal) ? true : false;
221 13 : }
222 :
223 9 : static void GetProfilingInfo(uint32_t flag, ProfilingMode &profilingMode, bool &kernelFlag)
224 : {
225 : // set or unset mode
226 9 : const bool isStart = (flag & (1U << aicpu::PROFILING_FEATURE_SWITCH)) > 0U;
227 : // if set or unset kernel profiling mode
228 9 : kernelFlag = (flag & (1U << aicpu::PROFILING_FEATURE_KERNEL_MODE)) > 0U;
229 9 : if (isStart) {
230 9 : profilingMode = PROFILING_OPEN;
231 : }
232 9 : }
233 :
234 : private:
235 : AicpuUtil() = default;
236 : ~AicpuUtil() = default;
237 :
238 : AicpuUtil(AicpuUtil const&) = delete;
239 : AicpuUtil& operator=(AicpuUtil const&) = delete;
240 : AicpuUtil(AicpuUtil&&) = delete;
241 : AicpuUtil& operator=(AicpuUtil&&) = delete;
242 : };
243 :
244 : /**
245 : * @ingroup aicpu_cust_schedule
246 : * @brief Pointer move
247 : * @param [in] T : type T, sizeof(T) mast be 1
248 : * @param [in] ptr : The pointer
249 : * @param [in] offset : Move offset
250 : * @return The pointer after move offset
251 : */
252 : template <typename T, typename = typename std::enable_if<sizeof(T) == 1UL, void>::type>
253 : inline T *MovePtrByOffset(const T * const ptr, const uint64_t offset)
254 : {
255 : return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(ptr) + offset);
256 : }
257 :
258 : class ScopeGuard {
259 : public:
260 3 : explicit ScopeGuard(const std::function<void()> exitScope)
261 3 : : exitScope_(exitScope)
262 3 : {}
263 :
264 3 : ~ScopeGuard()
265 : {
266 3 : exitScope_();
267 3 : }
268 :
269 : private:
270 : ScopeGuard(ScopeGuard const&) = delete;
271 : ScopeGuard& operator=(ScopeGuard const&) = delete;
272 : ScopeGuard(ScopeGuard&&) = delete;
273 : ScopeGuard& operator=(ScopeGuard&&) = delete;
274 :
275 : private:
276 : std::function<void()> exitScope_;
277 : };
278 : } // namespace aicpu
279 :
280 : #endif // COMMON_AICPUSD_UTIL_H
|