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