LCOV - code coverage report
Current view: top level - server - bind_cpu_utils.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.0 % 217 204
Test Date: 2026-08-12 11:05:07 Functions: 100.0 % 13 13

            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 "bind_cpu_utils.h"
      12              : #include <sstream>
      13              : #include <fcntl.h>
      14              : #include <semaphore.h>
      15              : #include <cstring>
      16              : #include <signal.h>
      17              : #include <stdlib.h>
      18              : #include "qs_interface_process.h"
      19              : #include "driver/ascend_hal.h"
      20              : #include "common/bqs_log.h"
      21              : #include "bqs_proc_mgr_sys_operator_agent.h"
      22              : #include "common/bqs_feature_ctrl.h"
      23              : #include "queue_schedule_feature_ctrl.h"
      24              : 
      25              : namespace bqs {
      26              : namespace {
      27              : sem_t g_sem;
      28              : bool g_semInited = false;
      29              : } // namespace
      30              : 
      31           13 : static drvError_t GetCpuInfo(const uint32_t deviceId, CpuInfo& cpuInfo)
      32              : {
      33           13 :     drvError_t ret = halGetDeviceInfo(
      34              :         deviceId, static_cast<int32_t>(MODULE_TYPE_CCPU), static_cast<int32_t>(INFO_TYPE_CORE_NUM), &(cpuInfo.ccpuNum));
      35           13 :     if (ret != DRV_ERROR_NONE) {
      36            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      37            1 :         return ret;
      38              :     }
      39              : 
      40           12 :     ret = halGetDeviceInfo(
      41              :         deviceId, static_cast<int32_t>(MODULE_TYPE_DCPU), static_cast<int32_t>(INFO_TYPE_CORE_NUM), &(cpuInfo.dcpuNum));
      42           12 :     if (ret != DRV_ERROR_NONE) {
      43            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      44            1 :         return ret;
      45              :     }
      46              : 
      47           11 :     ret = halGetDeviceInfo(
      48              :         deviceId, static_cast<int32_t>(MODULE_TYPE_AICPU), static_cast<int32_t>(INFO_TYPE_CORE_NUM),
      49              :         &(cpuInfo.aicpuNum));
      50           11 :     if (ret != DRV_ERROR_NONE) {
      51            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      52            1 :         return ret;
      53              :     }
      54              : 
      55           10 :     ret = halGetDeviceInfo(
      56              :         deviceId, static_cast<int32_t>(MODULE_TYPE_TSCPU), static_cast<int32_t>(INFO_TYPE_CORE_NUM),
      57              :         &(cpuInfo.tscpuNum));
      58           10 :     if (ret != DRV_ERROR_NONE) {
      59            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      60            1 :         return ret;
      61              :     }
      62              : 
      63            9 :     ret = halGetDeviceInfo(
      64              :         deviceId, static_cast<int32_t>(MODULE_TYPE_CCPU), static_cast<int32_t>(INFO_TYPE_OS_SCHED),
      65              :         &(cpuInfo.ccpuOsSched));
      66            9 :     if (ret != DRV_ERROR_NONE) {
      67            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      68            1 :         return ret;
      69              :     }
      70              : 
      71            8 :     ret = halGetDeviceInfo(
      72              :         deviceId, static_cast<int32_t>(MODULE_TYPE_DCPU), static_cast<int32_t>(INFO_TYPE_OS_SCHED),
      73              :         &(cpuInfo.dcpuOsSched));
      74            8 :     if (ret != DRV_ERROR_NONE) {
      75            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      76            1 :         return ret;
      77              :     }
      78              : 
      79            7 :     ret = halGetDeviceInfo(
      80              :         deviceId, static_cast<int32_t>(MODULE_TYPE_AICPU), static_cast<int32_t>(INFO_TYPE_OS_SCHED),
      81              :         &(cpuInfo.aicpuOsSched));
      82            7 :     if (ret != DRV_ERROR_NONE) {
      83            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      84            1 :         return ret;
      85              :     }
      86              : 
      87            6 :     ret = halGetDeviceInfo(
      88              :         deviceId, static_cast<int32_t>(MODULE_TYPE_TSCPU), static_cast<int32_t>(INFO_TYPE_OS_SCHED),
      89              :         &(cpuInfo.tscpuOsSched));
      90            6 :     if (ret != DRV_ERROR_NONE) {
      91            1 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceId, static_cast<int32_t>(ret));
      92            1 :         return ret;
      93              :     }
      94              : 
      95            5 :     return ret;
      96              : }
      97              : 
      98            2 : BqsStatus BindCpuUtils::InitSem()
      99              : {
     100            2 :     if (!g_semInited) {
     101            2 :         const int32_t semInitRet = sem_init(&g_sem, 0, 0U);
     102            2 :         if (semInitRet == -1) {
     103            1 :             BQS_LOG_ERROR("sem init failed, %s", strerror(errno));
     104            1 :             return BQS_STATUS_INNER_ERROR;
     105              :         }
     106            1 :         g_semInited = true;
     107              :     }
     108            1 :     return BQS_STATUS_OK;
     109              : }
     110              : 
     111            2 : BqsStatus BindCpuUtils::WaitSem()
     112              : {
     113            2 :     if (g_semInited) {
     114            2 :         const int32_t semWaitRet = sem_wait(&g_sem);
     115            2 :         if (semWaitRet == -1) {
     116            1 :             BQS_LOG_ERROR("sem wait failed, %s", strerror(errno));
     117            1 :             return BQS_STATUS_INNER_ERROR;
     118              :         }
     119            1 :         return BQS_STATUS_OK;
     120              :     }
     121            0 :     BQS_LOG_ERROR("sem wait failed, sem not init");
     122            0 :     return BQS_STATUS_INNER_ERROR;
     123              : }
     124              : 
     125            2 : BqsStatus BindCpuUtils::PostSem()
     126              : {
     127            2 :     if (g_semInited) {
     128            2 :         const int32_t semPostRet = sem_post(&g_sem);
     129            2 :         if (semPostRet == -1) {
     130            1 :             BQS_LOG_ERROR("sem post failed, %s", strerror(errno));
     131            1 :             return BQS_STATUS_INNER_ERROR;
     132              :         }
     133            1 :         return BQS_STATUS_OK;
     134              :     }
     135            0 :     BQS_LOG_ERROR("sem post failed, sem not init");
     136            0 :     return BQS_STATUS_INNER_ERROR;
     137              : }
     138              : 
     139            1 : void BindCpuUtils::DestroySem()
     140              : {
     141            1 :     if (g_semInited) {
     142            1 :         (void)sem_destroy(&g_sem);
     143            1 :         g_semInited = false;
     144              :     }
     145            1 : }
     146              : 
     147            4 : BqsStatus BindCpuUtils::WriteTidToCpuSet()
     148              : {
     149            4 :     const pid_t tid = static_cast<pid_t>(GetTid());
     150            4 :     std::string command = "cd /var/ && sudo ./add_aicpu_tid_to_tasks.sh";
     151            4 :     command = command + " " + std::to_string(static_cast<uint64_t>(tid));
     152              :     // system() may fail due to  "No child processes".
     153              :     // if SIGCHLD is set to SIG_IGN, waitpid() may report ECHILD error because it cannot find the child process.
     154              :     // The reason is that the system() relies on a feature of the system, that is,
     155              :     // when the kernel initializes the process, the processing mode of SIGCHLD signal is SIG_IGN.
     156            4 :     const int32_t ret = system(command.c_str());
     157            4 :     if (ret != 0) {
     158            1 :         BQS_LOG_WARN(
     159              :             "write tid[%d] to /sys/fs/cgroup/cpuset/AICPU/tasks failed, ret[%d], strerror[%s]", tid, ret,
     160              :             strerror(errno));
     161            1 :         return BQS_STATUS_INNER_ERROR;
     162              :     }
     163              : 
     164            3 :     return BQS_STATUS_OK;
     165            4 : }
     166              : 
     167            4 : BqsStatus BindCpuUtils::BindAicpuBySelf(uint32_t bindCpuIndex)
     168              : {
     169              :     // On device, it must write tid to aicpu set file, when you need bind aicpu.
     170            4 :     const BqsStatus writeRet = WriteTidToCpuSet();
     171            4 :     if (writeRet != BQS_STATUS_OK) {
     172            1 :         BQS_LOG_WARN(
     173              :             "Write tid to cpuset file failed, maybe cause bind cpu failed, ret=%d.", static_cast<int32_t>(writeRet));
     174              :     }
     175              : 
     176              :     cpu_set_t mask;
     177            4 :     CPU_ZERO(&mask);
     178            4 :     CPU_SET(bindCpuIndex, &mask);
     179            4 :     int32_t ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask);
     180            4 :     if (ret != 0) {
     181            1 :         BQS_LOG_ERROR("Set affinity with cpu[%u] failed, ret=%d.", bindCpuIndex, ret);
     182            1 :         return BQS_STATUS_INNER_ERROR;
     183              :     }
     184              : 
     185            3 :     CPU_ZERO(&mask);
     186              :     // check set result
     187            3 :     ret = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &mask);
     188            3 :     if (ret != 0) {
     189            1 :         BQS_LOG_ERROR("Getaffinity failed, ret=%d", ret);
     190            1 :         return BQS_STATUS_INNER_ERROR;
     191              :     }
     192              :     // check bind result
     193            2 :     if (CPU_ISSET(bindCpuIndex, &mask) == 0U) {
     194            1 :         BQS_LOG_INFO("Check CPU_ISSET with cpu[%u] not success", bindCpuIndex);
     195            1 :         return BQS_STATUS_INNER_ERROR;
     196              :     }
     197            1 :     BQS_LOG_INFO("Set affinity with cpu[%u] successful", bindCpuIndex);
     198            1 :     return BQS_STATUS_OK;
     199              : }
     200              : 
     201            4 : BqsStatus BindCpuUtils::SetThreadAffinity(const pthread_t& threadId, const std::vector<uint32_t>& cpuIds)
     202              : {
     203              :     cpu_set_t cpuset;
     204            4 :     CPU_ZERO(&cpuset);
     205            7 :     for (const auto cpuId : cpuIds) {
     206            3 :         CPU_SET(cpuId, &cpuset);
     207            3 :         BQS_LOG_INFO("prepare bind threadId=%lu to cpuId=%u", threadId, static_cast<uint32_t>(cpuId));
     208              :     }
     209            4 :     BQS_LOG_RUN_INFO("begin call pthread_setaffinity_np threadId=%lu", threadId);
     210              :     // 设置线程亲和性
     211            4 :     int32_t ret = pthread_setaffinity_np(threadId, sizeof(cpu_set_t), &cpuset);
     212            4 :     if (ret != 0) {
     213            2 :         BQS_LOG_ERROR("BindCpu threadId=%lu setaffinity failed, ret=%d", threadId, ret);
     214            2 :         return BQS_STATUS_INNER_ERROR;
     215              :     }
     216              :     // 检查线程实际亲和性
     217            2 :     ret = pthread_getaffinity_np(threadId, sizeof(cpu_set_t), &cpuset);
     218            2 :     if (ret != 0) {
     219            1 :         BQS_LOG_ERROR("BindCpu threadId=%lu getaffinity failed, ret=%d", threadId, ret);
     220            1 :         return BQS_STATUS_INNER_ERROR;
     221              :     }
     222         1025 :     for (int32_t cpuId = 0; cpuId < CPU_SETSIZE; cpuId++) {
     223         1024 :         if (CPU_ISSET(cpuId, &cpuset) != 0) {
     224            1 :             BQS_LOG_INFO("BindCpu threadId=%lu to cpuId=%d success", threadId, static_cast<int32_t>(cpuId));
     225              :         }
     226              :     }
     227            1 :     return BQS_STATUS_OK;
     228              : }
     229              : 
     230            2 : BqsStatus BindCpuUtils::BindAicpuByPm(const uint32_t bindCpuIndex)
     231              : {
     232            2 :     const pid_t tid = static_cast<pid_t>(GetTid());
     233              : 
     234            2 :     std::vector<uint32_t> coreAffinity;
     235            2 :     coreAffinity.push_back(bindCpuIndex);
     236            2 :     const auto ret = ProcMgrBindThread(tid, coreAffinity);
     237            2 :     if (ret != 0U) {
     238            1 :         BQS_LOG_ERROR("set affinity failed ret[%d], aicpu bindCpuIndex[%u], tid[%u]", ret, bindCpuIndex, tid);
     239            1 :         return BQS_STATUS_INNER_ERROR;
     240              :     }
     241            1 :     return BQS_STATUS_OK;
     242            2 : }
     243              : 
     244            6 : BqsStatus BindCpuUtils::BindAicpu(const uint32_t bindCpuIndex)
     245              : {
     246            6 :     std::string cpuSetFlag;
     247            6 :     const char* const envValue = std::getenv("PROCMGR_AICPU_CPUSET");
     248            6 :     if (envValue != nullptr) {
     249            8 :         cpuSetFlag = std::string(envValue);
     250              :     }
     251              : 
     252            6 :     BqsStatus res = BQS_STATUS_OK;
     253            6 :     if (cpuSetFlag == "1") {
     254            2 :         res = BindAicpuByPm(bindCpuIndex);
     255            2 :         BQS_LOG_RUN_INFO(
     256              :             "Qs bind tid by pm, cpuSetFlag:[%s], index[%u], res[%d].", cpuSetFlag.c_str(), bindCpuIndex,
     257              :             static_cast<int32_t>(res));
     258              :     } else {
     259            4 :         res = BindAicpuBySelf(bindCpuIndex);
     260            4 :         BQS_LOG_RUN_INFO(
     261              :             "Qs bind tid by self, cpuSetFlag:[%s] index[%u], res[%d].", cpuSetFlag.c_str(), bindCpuIndex,
     262              :             static_cast<int32_t>(res));
     263              :     }
     264            6 :     return res;
     265            6 : }
     266              : 
     267            7 : void BindCpuUtils::SetThreadFIFO(const uint32_t deviceId)
     268              : {
     269            7 :     if (QSFeatureCtrl::ShouldSetThreadFIFO(deviceId)) {
     270              :         struct sched_param param;
     271            0 :         param.sched_priority = sched_get_priority_max(SCHED_FIFO);
     272            0 :         if (param.sched_priority == -1) {
     273            0 :             BQS_LOG_WARN("QueueSchedule sched_get_priority_max failed, errno[%d].", errno);
     274            0 :         } else if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
     275            0 :             BQS_LOG_WARN("QueueSchedule sched_setscheduler failed, errno[%d].", errno);
     276              :         } else {
     277            0 :             BQS_LOG_INFO("QueueSchedule sched_setscheduler and sched_get_priority_max success.");
     278              :         }
     279              :     }
     280            7 : }
     281              : 
     282           14 : BqsStatus BindCpuUtils::GetDevCpuInfo(
     283              :     const uint32_t deviceId, std::vector<uint32_t>& aiCpuIds, std::vector<uint32_t>& ctrlCpuIds,
     284              :     uint32_t& coreNumPerDev, uint32_t& aicpuNum, uint32_t& aicpuBaseId)
     285              : {
     286           14 :     CpuInfo cpuInfo = {};
     287           14 :     uint32_t deviceIdTmp = deviceId;
     288              :     uint32_t ret;
     289           14 :     if (FeatureCtrl::IsVfModeDie1(deviceId)) {
     290            2 :         int64_t pfDeviceId = 0;
     291            2 :         ret = halGetDeviceInfo(deviceId, MODULE_TYPE_SYSTEM, INFO_TYPE_PHY_DIE_ID, &pfDeviceId);
     292            2 :         if (ret != DRV_ERROR_NONE) {
     293            1 :             BQS_LOG_ERROR("halGetDeviceInfo get pfDeviceId fail in device[%d], ret[%d]", deviceId, ret);
     294            1 :             return BQS_STATUS_DRIVER_ERROR;
     295              :         }
     296            1 :         deviceIdTmp = static_cast<uint32_t>(pfDeviceId);
     297              :     }
     298           13 :     ret = GetCpuInfo(deviceIdTmp, cpuInfo);
     299           13 :     if (ret != DRV_ERROR_NONE) {
     300            8 :         BQS_LOG_ERROR("get device[%u] cpu info failed, ret = %d.", deviceIdTmp, ret);
     301            8 :         return BQS_STATUS_DRIVER_ERROR;
     302              :     }
     303            5 :     coreNumPerDev = static_cast<uint32_t>(cpuInfo.ccpuNum) * static_cast<uint32_t>(cpuInfo.ccpuOsSched) +
     304            5 :                     static_cast<uint32_t>(cpuInfo.dcpuNum) * static_cast<uint32_t>(cpuInfo.dcpuOsSched) +
     305            5 :                     static_cast<uint32_t>(cpuInfo.aicpuNum) * static_cast<uint32_t>(cpuInfo.aicpuOsSched) +
     306            5 :                     static_cast<uint32_t>(cpuInfo.tscpuNum) * static_cast<uint32_t>(cpuInfo.tscpuOsSched);
     307            5 :     BQS_LOG_INFO("get device[%u] cpu num [%u] success", deviceIdTmp, coreNumPerDev);
     308            5 :     if (FeatureCtrl::IsAosCore()) {
     309            1 :         aicpuNum = static_cast<uint32_t>(cpuInfo.aicpuNum);
     310            1 :         aicpuBaseId = 0U;
     311            1 :         if (cpuInfo.ccpuOsSched != 0U) {
     312            1 :             aicpuBaseId += cpuInfo.ccpuNum;
     313              :         }
     314            1 :         if (cpuInfo.dcpuOsSched != 0U) {
     315            1 :             aicpuBaseId += cpuInfo.dcpuNum;
     316              :         }
     317            1 :         BQS_LOG_INFO(
     318              :             "get device[%u] aicpu cpu info success, aicpuBaseId[%u], aicpuNum[%u]", deviceIdTmp, aicpuBaseId, aicpuNum);
     319              :     } else {
     320            4 :         int64_t aicpuNumTmp = 0;
     321            4 :         int64_t aicpuBitMap = 0;
     322            4 :         if (FeatureCtrl::IsVfModeCheckedByDeviceId(deviceId)) {
     323            2 :             ret = halGetDeviceInfo(deviceId, MODULE_TYPE_AICPU, INFO_TYPE_PF_CORE_NUM, &aicpuNumTmp) +
     324            2 :                   halGetDeviceInfo(deviceId, MODULE_TYPE_AICPU, INFO_TYPE_PF_OCCUPY, &aicpuBitMap);
     325              :         } else {
     326            2 :             ret = halGetDeviceInfo(deviceId, MODULE_TYPE_AICPU, INFO_TYPE_CORE_NUM, &aicpuNumTmp) +
     327            2 :                   halGetDeviceInfo(deviceId, MODULE_TYPE_AICPU, INFO_TYPE_OCCUPY, &aicpuBitMap);
     328              :         }
     329            4 :         BQS_LOG_INFO(
     330              :             "get device[%u] aicpu cpu info success, aicpuBitMap[%ld], aicpuNum[%ld]", deviceId, aicpuBitMap,
     331              :             aicpuNumTmp);
     332            4 :         aicpuNum = aicpuNumTmp;
     333            4 :         aiCpuIds.clear();
     334            4 :         uint32_t id = 0;
     335            8 :         while (aicpuBitMap != 0) {
     336            4 :             if ((static_cast<uint64_t>(aicpuBitMap) & static_cast<uint64_t>(0x1)) != 0) {
     337            4 :                 aiCpuIds.push_back(id);
     338              :             }
     339            4 :             aicpuBitMap = static_cast<uint64_t>(aicpuBitMap) >> 1;
     340            4 :             id++;
     341              :         }
     342              :     }
     343              : 
     344            5 :     BQS_LOG_INFO(
     345              :         "get device[%u] ctrl cpu info success, ccpuNum[%ld], ccpuOsSched[%ld]", deviceId, cpuInfo.ccpuNum,
     346              :         cpuInfo.ccpuOsSched);
     347            5 :     if (cpuInfo.ccpuOsSched > 0L && !FeatureCtrl::IsVfModeDie1(deviceId)) {
     348            8 :         for (auto i = 0L; i < cpuInfo.ccpuNum; i++) {
     349            4 :             ctrlCpuIds.emplace_back(coreNumPerDev * deviceId + static_cast<uint32_t>(i));
     350              :         }
     351              :     }
     352            5 :     return BQS_STATUS_OK;
     353              : }
     354              : 
     355            7 : bool BindCpuUtils::AddToCgroup(const uint32_t deviceId, const uint32_t vfId)
     356              : {
     357            7 :     if (!QSFeatureCtrl::ShouldAddToCGroup(deviceId)) {
     358            0 :         return true;
     359              :     }
     360              : 
     361            7 :     BQS_LOG_RUN_INFO("AddToCgroup, deviceId = %u, vfId = %u", deviceId, vfId);
     362            7 :     const int32_t pid = drvDeviceGetBareTgid();
     363           14 :     std::string command = "cd /var/ && sudo ./tsdaemon_add_to_usermemory.sh";
     364            7 :     const std::string pathStr = "/var/tsdaemon_add_to_usermemory.sh";
     365            7 :     if (access(pathStr.c_str(), F_OK) != 0) {
     366            7 :         command = "cd /usr/local/Ascend/driver/tools/ && sudo ./tsdaemon_add_to_usermemory.sh";
     367              :     }
     368            7 :     (void)command.append(" memory ")
     369            7 :         .append(std::to_string(pid))
     370            7 :         .append(" ")
     371           14 :         .append(std::to_string(deviceId))
     372            7 :         .append(" ")
     373            7 :         .append(std::to_string(vfId));
     374            7 :     const sighandler_t oldHandler = signal(SIGCHLD, SIG_DFL);
     375              : 
     376              :     // system() may fail due to  "No child processes".
     377              :     // if SIGCHLD is set to SIG_IGN, waitpid() may report ECHILD error because it cannot find the child process.
     378              :     // The reason is that the system() relies on a feature of the system, that is,
     379              :     // when the kernel initializes the process, the processing mode of SIGCHLD signal is SIG_IGN.
     380            7 :     const int32_t ret = system(command.c_str());
     381            7 :     (void)signal(SIGCHLD, oldHandler);
     382            7 :     if (ret != 0) {
     383            0 :         BQS_LOG_ERROR("Add to cgroup failed, ret:[%d], cmd:[%s]", ret, command.c_str());
     384            0 :         return false;
     385              :     }
     386            7 :     BQS_LOG_RUN_INFO("Add to cgroup successfully, cmd:[%s].", command.c_str());
     387            7 :     return true;
     388            7 : }
     389              : } // namespace bqs
        

Generated by: LCOV version 2.0-1