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