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 <atomic>
15 : #include <functional>
16 : #include <cstring>
17 : #include <regex.h>
18 : #include <csignal>
19 : #include <unistd.h>
20 : #include <sys/time.h>
21 : #include <sys/wait.h>
22 : #include "metadef_types.h"
23 : #include "aicpu_context.h"
24 : #include "aicpusd_feature_ctrl.h"
25 : #include "aicpusd_status.h"
26 : #include "aicpu_event_struct.h"
27 : #include "profiling_adp.h"
28 : #include "securec.h"
29 :
30 : namespace AicpuSchedule {
31 :
32 : constexpr int32_t MAX_ENV_CHAR_NUM = 1024;
33 : const std::string ENV_NAME_HOME = "HOME";
34 : const std::string ENV_NAME_BLOCK_CFG_PATH = "BLOCK_CFG_PATH";
35 : const std::string ENV_NAME_DATAMASTER_RUN_MODE = "DATAMASTER_RUN_MODE";
36 : const std::string ENV_NAME_AICPU_MODEL_TIMEOUT = "AICPU_MODEL_TIMEOUT";
37 : const std::string ENV_NAME_PROCMGR_AICPU_CPUSET = "PROCMGR_AICPU_CPUSET";
38 : const std::string ENV_NAME_LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
39 : const std::string ENV_NAME_REG_ASCEND_MONITOR = "REGISTER_TO_ASCENDMONITOR";
40 : const std::string ENV_NAME_CUST_SO_PATH = "ASCEND_CUST_AICPU_KERNEL_CACHE_PATH";
41 : class ScopeGuard {
42 : public:
43 82 : explicit ScopeGuard(const std::function<void()> exitScope) : exitScope_(exitScope) {}
44 :
45 82 : ~ScopeGuard()
46 : {
47 : try {
48 82 : exitScope_();
49 0 : } catch (std::exception& funcException) {
50 0 : aicpusd_err("ScopeGuard Destruct Failed, %s", funcException.what());
51 0 : }
52 82 : }
53 :
54 : private:
55 : ScopeGuard(ScopeGuard const&) = delete;
56 : ScopeGuard& operator=(ScopeGuard const&) = delete;
57 : ScopeGuard(ScopeGuard&&) = delete;
58 : ScopeGuard& operator=(ScopeGuard&&) = delete;
59 :
60 : std::function<void()> exitScope_;
61 : };
62 :
63 254 : inline uint64_t TickInterval2Microsecond(const uint64_t tickStart, const uint64_t tickEnd, const uint64_t tickFreq)
64 : {
65 254 : if ((tickFreq == 0ULL) || (tickEnd <= tickStart)) {
66 3 : return 0UL;
67 : }
68 : // tickFreq is record by second, to microsecond need multiply 1000000
69 251 : return ((tickEnd - tickStart) * 1000000U) / tickFreq;
70 : }
71 : typedef struct {
72 : uint64_t taskId;
73 : uint64_t streamId;
74 : uint32_t threadIndex;
75 : uint32_t deviceId;
76 : } ProfIdentity;
77 :
78 : class AicpuUtil {
79 : public:
80 : /**
81 : * @ingroup AicpusdUtil
82 : * @brief it is used to uniformly normalized error code.
83 : * @param [in] errCode: original error code.
84 : * @return uniformly normalized error code
85 : */
86 124 : static int32_t TransformInnerErrCode(const int32_t errCode)
87 : {
88 124 : return ((errCode > AICPU_SCHEDULE_ERROR_RESERVED) || (errCode < AICPU_SCHEDULE_OK)) ?
89 : AICPU_SCHEDULE_ERROR_INNER_ERROR :
90 124 : errCode;
91 : }
92 :
93 128 : static void SetProfData(
94 : const std::shared_ptr<aicpu::ProfMessage>& profMsg, const aicpu::aicpuProfContext_t& aicpuProfCtx,
95 : const ProfIdentity& profIdentity)
96 : {
97 128 : if (profMsg != nullptr) {
98 : // Phase of determining whether the operator is an asynchronous operator
99 127 : std::string phaseOneValue;
100 127 : bool isPhaseOne = false;
101 127 : const auto ret = aicpu::GetThreadLocalCtx(aicpu::CONTEXT_KEY_PHASE_ONE_FLAG, phaseOneValue);
102 128 : if ((ret == aicpu::AICPU_ERROR_NONE) && (phaseOneValue == "True")) {
103 2 : isPhaseOne = true;
104 : }
105 : // The profile is not written in the first phase.
106 128 : if (!isPhaseOne) {
107 126 : const uint64_t tickAfterRun = aicpu::GetSystemTick();
108 127 : const uint64_t tickFreq = aicpu::GetSystemTickFreq();
109 : const uint64_t dispatchTime =
110 127 : TickInterval2Microsecond(aicpuProfCtx.drvSubmitTick, aicpuProfCtx.tickBeforeRun, tickFreq);
111 127 : const uint64_t totalTime = TickInterval2Microsecond(aicpuProfCtx.drvSubmitTick, tickAfterRun, tickFreq);
112 : (void)profMsg->SetAicpuMagicNumber(static_cast<uint16_t>(MSPROF_DATA_HEAD_MAGIC_NUM))
113 : ->SetAicpuDataTag(static_cast<uint16_t>(MSPROF_AICPU_DATA_TAG))
114 127 : ->SetStreamId(static_cast<uint16_t>(profIdentity.streamId))
115 127 : ->SetTaskId(static_cast<uint16_t>(profIdentity.taskId))
116 127 : ->SetThreadId(profIdentity.threadIndex)
117 127 : ->SetDeviceId(profIdentity.deviceId)
118 127 : ->SetKernelType(aicpuProfCtx.kernelType)
119 127 : ->SetSubmitTick(aicpuProfCtx.drvSubmitTick)
120 127 : ->SetScheduleTick(aicpuProfCtx.drvSchedTick)
121 127 : ->SetTickBeforeRun(aicpuProfCtx.tickBeforeRun)
122 : ->SetTickAfterRun(tickAfterRun)
123 : ->SetDispatchTime(static_cast<uint32_t>(dispatchTime))
124 : ->SetTotalTime(static_cast<uint32_t>(totalTime))
125 127 : ->SetVersion(aicpu::AICPU_PROF_VERSION);
126 : }
127 126 : (void)aicpu::SetProfHandle(nullptr);
128 126 : (void)aicpu::SetThreadLocalCtx(aicpu::CONTEXT_KEY_PHASE_ONE_FLAG, "False");
129 128 : }
130 128 : }
131 :
132 15 : static int32_t NumElements(const int64_t* const shape, const int64_t dimSize, int64_t& elementNum)
133 : {
134 15 : if (shape == nullptr) {
135 2 : aicpusd_err("Shape is nullptr.");
136 2 : return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
137 : }
138 :
139 13 : int64_t num = 1;
140 22 : for (int64_t i = 0; i < dimSize; i++) {
141 11 : const int64_t dim = shape[i];
142 11 : if (dim < 0) {
143 2 : aicpusd_err("Shape[%lld] value[%lld] is invalid, must be >= 0.", i, dim);
144 2 : return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
145 : }
146 9 : num = (num * dim);
147 9 : if (num < 0) {
148 0 : aicpusd_err("Shape total element num is invalid, must be < INT64_MAX.");
149 0 : return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
150 : }
151 : }
152 11 : elementNum = num;
153 11 : return AICPU_SCHEDULE_OK;
154 : }
155 :
156 13 : static int32_t CalcDataSizeByShape(
157 : const int64_t* const shape, const int64_t dimSize, const int64_t dtype, int64_t& dataSize)
158 : {
159 13 : int64_t elementNum = 0;
160 13 : const int32_t ret = NumElements(shape, dimSize, elementNum);
161 13 : if (ret != AICPU_SCHEDULE_OK) {
162 2 : return ret;
163 : }
164 :
165 11 : const int32_t elementSize = ge::GetSizeByDataType(static_cast<ge::DataType>(dtype));
166 11 : if (elementSize < 0) {
167 1 : aicpusd_err("CalcDataSizeByShape failed, elementSize[%d] must be >= 0.", elementSize);
168 1 : return AICPU_SCHEDULE_ERROR_PARAMETER_NOT_VALID;
169 : }
170 :
171 10 : dataSize = elementNum * static_cast<int64_t>(elementSize);
172 10 : return AICPU_SCHEDULE_OK;
173 : }
174 :
175 : /**
176 : * @ingroup AicpuUtil
177 : * @brief it is used to check exception by read FPSR Register.
178 : * @param [out] result : exception type.
179 : * @return has any exception, true if has
180 : */
181 : static bool CheckOverflow(int32_t& result)
182 : {
183 : (void)result;
184 : #if (defined __ARM_ARCH) || (defined PLATFORM_AARCH64)
185 : int64_t regContent;
186 : __asm volatile("MRS %0, FPSR" : "=r"(regContent) : : "memory");
187 : aicpusd_info("Read FPSR:[%d].", regContent);
188 : if (regContent & (1UL << 3UL)) { // UFC(3)
189 : result = AICPU_SCHEDULE_ERROR_UNDERFLOW;
190 : return true;
191 : } else if (regContent & (1UL << 2UL)) { // OFC(2)
192 : result = AICPU_SCHEDULE_ERROR_OVERFLOW;
193 : return true;
194 : } else if (regContent & (1UL << 1UL)) { // DZC(1)
195 : result = AICPU_SCHEDULE_ERROR_DIVISIONZERO;
196 : return true;
197 : }
198 : #endif
199 : return false;
200 : }
201 :
202 : /**
203 : * @ingroup AicpuUtil
204 : * @brief it is used to reset FPSR Register.
205 : */
206 : static void ResetFpsr()
207 : {
208 : #if (defined __ARM_ARCH) || (defined PLATFORM_AARCH64)
209 : aicpusd_info("Reset FPSR.");
210 : __asm volatile("BIC x0, x0, #0xffffffff \n\t"
211 : "MSR FPSR, x0" ::
212 : : "x0");
213 : #endif
214 : }
215 :
216 : /**
217 : * @ingroup AicpuUtil
218 : * @brief Get env value by name
219 : * @param [in] env : env name
220 : * @param [in] val : env value
221 : * @return bool: true, if env val is not nullptr; otherwise, false
222 : */
223 225 : __attribute__((visibility("default"))) static bool GetEnvVal(const std::string& env, std::string& val)
224 : {
225 225 : if (env.empty()) {
226 0 : return false;
227 : }
228 :
229 225 : const char* const tmpVal = std::getenv(env.c_str());
230 225 : if ((tmpVal == nullptr) || (strnlen(tmpVal, MAX_ENV_CHAR_NUM) >= MAX_ENV_CHAR_NUM)) {
231 131 : val = "";
232 131 : return false;
233 : }
234 :
235 94 : val = tmpVal;
236 94 : return true;
237 : }
238 :
239 : /**
240 : * @ingroup AicpuUtil
241 : * @brief Is env value is same as expected value
242 : * @param [in] env : env name
243 : * @param [in] expectVal : expected env value
244 : * @return bool: true, if env val is same as expected value; otherwise, false
245 : */
246 99 : __attribute__((visibility("default"))) static bool IsEnvValEqual(
247 : const std::string& env, const std::string& expectVal)
248 : {
249 99 : std::string getedEnvVal;
250 99 : const bool ret = GetEnvVal(env, getedEnvVal);
251 99 : if (!ret) {
252 70 : return false;
253 : }
254 :
255 29 : return (getedEnvVal == expectVal) ? true : false;
256 99 : }
257 :
258 8 : static inline bool IsUint64MulOverflow(const uint64_t num1, const uint64_t num2)
259 : {
260 8 : if ((num1 == 0UL) || (num2 == 0UL)) {
261 1 : return false;
262 : }
263 :
264 7 : if ((UINT64_MAX / num1) < num2) {
265 2 : return true;
266 : }
267 :
268 5 : return false;
269 : }
270 :
271 196 : static bool TransStrToInt(const std::string& para, int32_t& value)
272 : {
273 : try {
274 196 : value = std::stoi(para);
275 9 : } catch (...) {
276 9 : return false;
277 9 : }
278 :
279 187 : return true;
280 : }
281 :
282 42 : static bool TransStrToUint(const std::string& para, uint32_t& value)
283 : {
284 : try {
285 42 : value = std::stoul(para);
286 2 : } catch (...) {
287 2 : return false;
288 2 : }
289 :
290 40 : return true;
291 : }
292 :
293 3 : static bool TransStrToull(const std::string& para, uint64_t& value)
294 : {
295 : try {
296 3 : value = std::stoull(para);
297 1 : } catch (...) {
298 1 : return false;
299 1 : }
300 :
301 2 : return true;
302 : }
303 :
304 : /**
305 : * @ingroup AicpuUtil
306 : * @brief judge the string matching pattern
307 : * @param [in] str : file name
308 : * @param [in] mode : pattern
309 : * @return check code
310 : */
311 2 : static bool ValidateStr(const std::string& str, const std::string& mode)
312 : {
313 : regex_t reg;
314 2 : int32_t ret = regcomp(®, mode.c_str(), REG_EXTENDED | REG_NOSUB);
315 2 : if (ret != 0) {
316 1 : return false;
317 : }
318 1 : ret = regexec(®, str.c_str(), static_cast<size_t>(0), nullptr, 0);
319 1 : if (ret != 0) {
320 1 : regfree(®);
321 1 : return false;
322 : }
323 :
324 0 : regfree(®);
325 0 : return true;
326 : }
327 :
328 3 : static int32_t ExecuteCmd(const std::string& cmd)
329 : {
330 : /**
331 : * system() may fail due to "No child processes".
332 : * if SIGCHLD is set to SIG_IGN, waitpid() may report ECHILD error because it cannot find the child process.
333 : * The reason is that the system() relies on a feature of the system, that is,
334 : * when the kernel initializes the process, the processing mode of SIGCHLD signal is SIG_IGN.
335 : */
336 3 : if (cmd.empty()) {
337 1 : return -1;
338 : }
339 :
340 2 : sighandler_t const oldHandler = signal(SIGCHLD, SIG_DFL);
341 2 : int32_t status = 0;
342 2 : int32_t pid = 0;
343 2 : if ((pid = vfork()) < 0) {
344 1 : status = -1;
345 2 : } else if (pid == 0) {
346 1 : (void)execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
347 0 : constexpr int32_t executeCmdErr = 127; // 与system实现保持一致
348 0 : _exit(executeCmdErr);
349 : } else {
350 1 : while (waitpid(pid, &status, 0) < 0) {
351 0 : if (errno != EINTR) {
352 0 : status = -1;
353 0 : break;
354 : }
355 : }
356 : }
357 2 : (void)signal(SIGCHLD, oldHandler);
358 2 : return status;
359 : }
360 :
361 : static std::string GetDTypeString(const ge::DataType curDtype);
362 :
363 1 : static void UpdateMinData(uint64_t& dstData, const uint64_t srcData)
364 : {
365 1 : if (((dstData > srcData) && (srcData != 0UL)) || (dstData == 0UL)) {
366 1 : dstData = srcData;
367 : }
368 1 : }
369 1 : static void UpdateMaxAndSubMaxData(uint64_t& maxData, uint64_t& subMaxData, const uint64_t srcData)
370 : {
371 1 : if (srcData > maxData) {
372 0 : subMaxData = maxData;
373 0 : maxData = srcData;
374 1 : } else if (srcData > subMaxData) {
375 0 : subMaxData = srcData;
376 : } else {
377 : // do nothing
378 : }
379 1 : }
380 :
381 4 : static bool BiggerMemCpy(void* dstAddr, const size_t dstLen, const void* srcAddr, const size_t srcLen)
382 : {
383 4 : if ((dstAddr == nullptr) || (srcAddr == nullptr)) {
384 2 : aicpusd_err("BiggerMemCpy input param is null.");
385 2 : return false;
386 : }
387 :
388 2 : if (dstLen < srcLen) {
389 0 : aicpusd_err("BiggerMemCpy dstLen is[%zu] less than srcLen[%zu].", dstLen, srcLen);
390 0 : return false;
391 : }
392 :
393 2 : size_t remainSize = srcLen;
394 2 : while (remainSize > SECUREC_MEM_MAX_LEN) {
395 0 : const auto eRet = memcpy_s(dstAddr, SECUREC_MEM_MAX_LEN, srcAddr, SECUREC_MEM_MAX_LEN);
396 0 : if (eRet != EOK) {
397 0 : aicpusd_err("memcpy_s fail, ret is %d.", eRet);
398 0 : return false;
399 : }
400 0 : remainSize -= SECUREC_MEM_MAX_LEN;
401 0 : srcAddr = ValueToPtr(PtrToValue(srcAddr) + SECUREC_MEM_MAX_LEN);
402 0 : dstAddr = ValueToPtr(PtrToValue(dstAddr) + SECUREC_MEM_MAX_LEN);
403 : }
404 2 : if (remainSize != 0U) {
405 2 : const auto eRet = memcpy_s(dstAddr, remainSize, srcAddr, remainSize);
406 2 : if (eRet != EOK) {
407 0 : aicpusd_err("memcpy_s fail, size is %zu, ret is %d.", remainSize, eRet);
408 0 : return false;
409 : }
410 : }
411 2 : return true;
412 : }
413 :
414 31 : static bool IsFpga()
415 : {
416 35 : static const bool IS_FPGA = AicpuUtil::IsEnvValEqual(ENV_NAME_DATAMASTER_RUN_MODE, "1");
417 31 : return IS_FPGA;
418 : }
419 :
420 : /**
421 : * @ingroup AicpuUtil
422 : * @brief it use to check timeout value send by ts.
423 : * @param [in] timeout : the timeout value.
424 : * @return bool: true if is valid value, otherwise false
425 : */
426 12 : static inline bool IsValidTimeoutVal(const uint32_t timeout)
427 : {
428 12 : if (timeout == 0U) {
429 1 : aicpusd_err("Invalid timeout value send by ts which cannot be zero.");
430 1 : return false;
431 : }
432 :
433 11 : const uint64_t sysTickFreq = aicpu::GetSystemTickFreq();
434 11 : if (sysTickFreq > (UINT64_MAX / static_cast<uint64_t>(timeout))) {
435 2 : aicpusd_err(
436 : "Invalid timeout[%u] value send by ts resulting in unsigned long reverse. freq[%lu]", timeout,
437 : sysTickFreq);
438 2 : return false;
439 : }
440 :
441 9 : return true;
442 : }
443 :
444 : /**
445 : * @ingroup AicpuUtil
446 : * @brief is use to check cust aicpu thread mode
447 : * @return AICPU_SCHEDULE_OK: success, other: error code
448 : */
449 3 : static inline int32_t CheckCustAicpuThreadMode()
450 : {
451 3 : uint32_t runMode = 0U;
452 3 : const aicpu::status_t status = aicpu::GetAicpuRunMode(runMode);
453 3 : if (status != aicpu::AICPU_ERROR_NONE) {
454 1 : aicpusd_err("Get current aicpu ctx failed.");
455 1 : return AICPU_SCHEDULE_ERROR_INNER_ERROR;
456 : }
457 :
458 2 : if (runMode != aicpu::AicpuRunMode::THREAD_MODE) {
459 1 : aicpusd_err("Cust aicpu process does not exist.");
460 1 : aicpusd_err("Only with thread mode, cust aicpu kernel can run in aicpu-sd.");
461 1 : return AICPU_SCHEDULE_ERROR_INNER_ERROR;
462 : }
463 :
464 1 : return AICPU_SCHEDULE_OK;
465 : }
466 :
467 : private:
468 : AicpuUtil() = default;
469 : ~AicpuUtil() = default;
470 :
471 : AicpuUtil(AicpuUtil const&) = delete;
472 : AicpuUtil& operator=(AicpuUtil const&) = delete;
473 : AicpuUtil(AicpuUtil&&) = delete;
474 : AicpuUtil& operator=(AicpuUtil&&) = delete;
475 : };
476 :
477 : class SpinLock {
478 : public:
479 125 : SpinLock() = default;
480 :
481 : ~SpinLock() = default;
482 :
483 544976 : void Lock()
484 : {
485 1089952 : while (lock_.test_and_set()) {
486 : }
487 544976 : }
488 :
489 544976 : void Unlock() { lock_.clear(); }
490 :
491 : private:
492 : SpinLock(const SpinLock&) = delete;
493 : SpinLock& operator=(const ScopeGuard&) = delete;
494 : SpinLock(SpinLock&&) = delete;
495 : SpinLock& operator=(SpinLock&&) = delete;
496 :
497 : std::atomic_flag lock_ = ATOMIC_FLAG_INIT;
498 : };
499 :
500 63 : inline uint64_t GetCurrentTime()
501 : {
502 63 : uint64_t ret = 0U;
503 : struct timeval tv;
504 63 : if (gettimeofday(&tv, nullptr) == 0) {
505 63 : ret = (static_cast<uint64_t>(tv.tv_sec) * 1000000UL) + static_cast<uint64_t>(tv.tv_usec);
506 : }
507 :
508 63 : return ret;
509 : }
510 :
511 : } // namespace AicpuSchedule
512 :
513 : #endif // COMMON_AICPUSD_UTIL_H
|