LCOV - code coverage report
Current view: top level - acl/utils - cann_info_utils.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.9 % 156 145
Test Date: 2026-07-28 10:53:01 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 "utils/cann_info_utils.h"
      12              : 
      13              : #include <fstream>
      14              : #include <sys/stat.h>
      15              : #include "acl_rt_impl.h"
      16              : #include "utils/file_utils.h"
      17              : #include "common/json_parser.h"
      18              : 
      19              : namespace acl {
      20              : namespace {
      21              : #if defined(ONLY_ENABLE_ACL_UT)
      22              : constexpr const char_t* const SW_CONFIG_FILE = "tmp_run_data/ascendcl_config/swFeatureList.json";
      23              : constexpr const char_t* const RUNTIME_VERSION_PATH = "tests/tmp_run_data/share/info/runtime/version.info";
      24              : #else
      25              : constexpr const char_t* const SW_CONFIG_FILE = "data/ascendcl_config/swFeatureList.json";
      26              : constexpr const char_t* const RUNTIME_VERSION_PATH = "share/info/runtime/version.info";
      27              : #endif
      28              : constexpr const char_t* const VERSION_INFO_KEY = "Version=";
      29              : constexpr size_t MAX_INSTALL_PATH_SEARCH_DEPTH = 8U;
      30              : 
      31           12 : std::string StripTrailingSlash(const std::string& path)
      32              : {
      33           12 :     if ((path.size() > 1UL) && (path.back() == '/')) {
      34           12 :         return path.substr(0, path.size() - 1UL);
      35              :     }
      36            0 :     return path;
      37              : }
      38              : 
      39           12 : std::string GetParentDir(const std::string& path)
      40              : {
      41           12 :     const std::string strippedPath = StripTrailingSlash(path);
      42           12 :     const size_t pos = strippedPath.rfind('/');
      43           12 :     if (pos == std::string::npos) {
      44            0 :         return "";
      45              :     }
      46           12 :     return strippedPath.substr(0, pos + 1UL);
      47           12 : }
      48              : 
      49           27 : bool IsRegularFile(const std::string& path)
      50              : {
      51           27 :     struct stat fileStat = {};
      52           27 :     return (stat(path.c_str(), &fileStat) == 0) && S_ISREG(fileStat.st_mode);
      53              : }
      54              : 
      55            3 : bool FindFileFromCurrentToParents(const std::string& startDir, const std::string& relativePath, std::string& matchedDir)
      56              : {
      57            3 :     std::string currentDir = startDir;
      58           15 :     for (size_t depth = 0U; depth < MAX_INSTALL_PATH_SEARCH_DEPTH; ++depth) {
      59           15 :         if (currentDir.empty()) {
      60            3 :             return false;
      61              :         }
      62           15 :         if (IsRegularFile(currentDir + relativePath)) {
      63            3 :             matchedDir = currentDir;
      64            3 :             return true;
      65              :         }
      66           12 :         const std::string parentDir = GetParentDir(currentDir);
      67           12 :         if ((parentDir.empty()) || (parentDir == currentDir)) {
      68            0 :             return false;
      69              :         }
      70           12 :         currentDir = parentDir;
      71           12 :     }
      72            0 :     return false;
      73            3 : }
      74              : } // namespace
      75              : 
      76              : std::mutex CannInfoUtils::mutex_;
      77              : bool CannInfoUtils::initFlag_ = false;
      78              : int32_t CannInfoUtils::currentRuntimeVersion_ = UNKNOWN_VERSION;
      79              : std::string CannInfoUtils::swConfigPath_;
      80              : std::string CannInfoUtils::defaultInstallPath_;
      81              : aclCannAttr CannInfoUtils::attrArray_[MAX_CANN_ATTR_SIZE];
      82              : size_t CannInfoUtils::attrNum_ = 0;
      83              : 
      84              : std::map<aclCannAttr, CannInfo> CannInfoUtils::attrToCannInfo_ = {
      85              :     {ACL_CANN_ATTR_INF_NAN, CannInfo("INF_NAN", "SoCInfo", "support_inf_nan")},
      86              :     {ACL_CANN_ATTR_BF16, CannInfo("BF16", "SoCInfo", "support_bf16")},
      87              :     {ACL_CANN_ATTR_JIT_COMPILE, CannInfo("JIT_COMPILE", "", "")},
      88              : };
      89              : 
      90            3 : aclError CannInfoUtils::GetAttributeList(const aclCannAttr** cannAttr, size_t* num)
      91              : {
      92            3 :     const aclError ret = Initialize();
      93            3 :     if (ret != ACL_SUCCESS) {
      94            2 :         ACL_LOG_INNER_ERROR("initialize CannInfoUtils failed, ret = %d", static_cast<int32_t>(ret));
      95            2 :         return ret;
      96              :     }
      97            1 :     *cannAttr = attrArray_;
      98            1 :     *num = attrNum_;
      99            1 :     return ACL_SUCCESS;
     100              : }
     101              : 
     102           10 : aclError CannInfoUtils::GetAttribute(aclCannAttr cannAttr, int32_t* value)
     103              : {
     104           10 :     const aclError ret = Initialize();
     105           10 :     if (ret != ACL_SUCCESS) {
     106            7 :         ACL_LOG_INNER_ERROR("initialize CannInfoUtils failed, ret = %d", static_cast<int32_t>(ret));
     107            7 :         return ret;
     108              :     }
     109              : 
     110            3 :     auto iter = attrToCannInfo_.find(cannAttr);
     111            3 :     if (iter == attrToCannInfo_.end()) {
     112            1 :         ACL_LOG_WARN("find cann attr failed, attr value = %d", static_cast<int32_t>(cannAttr));
     113            1 :         return ACL_ERROR_INVALID_PARAM;
     114              :     }
     115            2 :     *value = iter->second.isAvailable;
     116            2 :     return ACL_SUCCESS;
     117              : }
     118              : 
     119           13 : aclError CannInfoUtils::Initialize()
     120              : {
     121           13 :     std::lock_guard<std::mutex> lock(mutex_);
     122           13 :     if (initFlag_) {
     123            3 :         ACL_LOG_INFO("CannInfoUtils has already initialized.");
     124            3 :         return ACL_SUCCESS;
     125              :     }
     126           10 :     ACL_LOG_INFO("Start to initialize CannInfoUtils.");
     127              :     // init config path and CANN install path
     128           10 :     auto ret = GetConfigInstallPath();
     129           10 :     if (ret != ACL_SUCCESS) {
     130            4 :         ACL_LOG_INNER_ERROR("Failed to get swFeatureList.json, please check ascendcl_config path.");
     131            4 :         return ret;
     132              :     }
     133              : 
     134              :     // parse requirments of each attributes
     135            6 :     ret = JsonParser::GetAttrConfigFromFile(swConfigPath_.c_str(), attrToCannInfo_);
     136            6 :     if (ret != ACL_SUCCESS) {
     137            0 :         ACL_LOG_INNER_ERROR("Failed to parse requirements of Cann attrs, ret = %d.", ret);
     138            0 :         return ret;
     139              :     }
     140              : 
     141              :     // parse current CannInfo
     142            6 :     const std::string runtimeVersionPath = defaultInstallPath_ + RUNTIME_VERSION_PATH;
     143            6 :     ret = ParseVersionInfo(runtimeVersionPath, &currentRuntimeVersion_);
     144            6 :     if (ret != ACL_SUCCESS) {
     145            5 :         ACL_LOG_WARN("cannot get runtime version in current environment!");
     146            5 :         return ACL_ERROR_INTERNAL_ERROR;
     147              :     }
     148              : 
     149              :     // check and update attr availability
     150            1 :     CheckAndUpdateAttrAvailability();
     151            1 :     initFlag_ = true;
     152            1 :     ACL_LOG_INFO(
     153              :         "Successfully initialized CannInfoUtils: current CannInfo[runtime = %d, attrNum = %zu]", currentRuntimeVersion_,
     154              :         attrNum_);
     155              : 
     156            1 :     return ACL_SUCCESS;
     157           13 : }
     158              : 
     159           10 : aclError CannInfoUtils::GetConfigInstallPath()
     160              : {
     161           10 :     std::string path;
     162           10 :     const aclError ret = file_utils::GetSoRealPath(path);
     163           10 :     if (ret != ACL_SUCCESS) {
     164            4 :         ACL_LOG_WARN("Failed to get libascendcl.so file path.");
     165            4 :         return ret;
     166              :     }
     167            6 :     ACL_LOG_DEBUG("current path = %s", path.c_str());
     168            6 :     const std::string soDir = path;
     169            6 :     path = path.substr(0, path.rfind('/'));
     170            6 :     path = path.substr(0, path.rfind('/') + 1UL);
     171            6 :     swConfigPath_ = path + SW_CONFIG_FILE;
     172            6 :     if (!IsRegularFile(swConfigPath_)) {
     173            1 :         std::string matchedDir;
     174            2 :         if (FindFileFromCurrentToParents(soDir, SW_CONFIG_FILE, matchedDir)) {
     175            1 :             swConfigPath_ = matchedDir + SW_CONFIG_FILE;
     176            1 :             path = matchedDir;
     177            1 :             ACL_LOG_INFO("fallback to swConfigPath = %s", swConfigPath_.c_str());
     178              :         }
     179            1 :     }
     180            6 :     ACL_LOG_DEBUG("swConfigPath = %s", swConfigPath_.c_str());
     181            6 :     path.pop_back();
     182            6 :     defaultInstallPath_ = path.substr(0, path.rfind('/') + 1UL);
     183            6 :     if (!IsRegularFile(defaultInstallPath_ + RUNTIME_VERSION_PATH)) {
     184            2 :         std::string matchedDir;
     185            4 :         if (FindFileFromCurrentToParents(soDir, RUNTIME_VERSION_PATH, matchedDir)) {
     186            2 :             defaultInstallPath_ = matchedDir;
     187            2 :             ACL_LOG_INFO("fallback to defaultInstallPath = %s", defaultInstallPath_.c_str());
     188              :         }
     189            2 :     }
     190            6 :     ACL_LOG_DEBUG("defaultInstallPath = %s", defaultInstallPath_.c_str());
     191            6 :     return ACL_SUCCESS;
     192           10 : }
     193              : 
     194            6 : aclError CannInfoUtils::ParseVersionInfo(const std::string& path, int32_t* version)
     195              : {
     196            6 :     std::ifstream ifs(path, std::ifstream::in);
     197            6 :     if (!ifs.is_open()) {
     198            0 :         ACL_LOG_WARN("Open file [%s] failed.", path.c_str());
     199            0 :         return ACL_ERROR_INTERNAL_ERROR;
     200              :     }
     201            6 :     std::string line;
     202            7 :     while (std::getline(ifs, line)) {
     203            4 :         if (line.find(VERSION_INFO_KEY) != std::string::npos) {
     204            3 :             ACL_LOG_DEBUG("Parse version success, content is [%s].", line.c_str());
     205            3 :             ifs.close();
     206            3 :             const size_t prefixLen = strlen(VERSION_INFO_KEY);
     207            3 :             line = line.substr(prefixLen);
     208            3 :             const size_t pos = line.find('.', line.find('.') + 1UL);
     209            3 :             line = line.substr(0, pos);
     210            3 :             return ParseVersionValue(line, version);
     211              :         }
     212              :     }
     213            3 :     ifs.close();
     214            3 :     ACL_LOG_WARN("cannot find valid Version info, please check path = %s", path.c_str());
     215            3 :     return ACL_ERROR_INTERNAL_ERROR;
     216            6 : }
     217              : 
     218           17 : aclError CannInfoUtils::ParseVersionValue(const std::string& str, int32_t* value)
     219              : {
     220           17 :     const size_t pos = str.find('.');
     221              :     try {
     222           19 :         const int32_t major = std::stoi(str.substr(0, pos));
     223           15 :         const int32_t minor = std::stoi(str.substr(pos + 1UL));
     224           15 :         *value = 1000 * major + 10 * minor;
     225            2 :     } catch (...) {
     226            2 :         ACL_LOG_WARN("strVal[%s] can not be converted to version value", str.c_str());
     227            2 :         return ACL_ERROR_INTERNAL_ERROR;
     228            2 :     }
     229           15 :     return ACL_SUCCESS;
     230              : }
     231              : 
     232            3 : bool CannInfoUtils::MatchVersionInfo(const CannInfo& configCannInfo)
     233              : {
     234              :     // if version is not set, skip matching and return true
     235            3 :     if (configCannInfo.minimumRuntimeVersion == UNKNOWN_VERSION) {
     236            0 :         return true;
     237              :     }
     238            3 :     return (currentRuntimeVersion_ >= configCannInfo.minimumRuntimeVersion);
     239              : }
     240              : 
     241            3 : bool CannInfoUtils::CheckNPUFeatures(const CannInfo& configInfo)
     242              : {
     243            3 :     if (configInfo.socSpecLabel.empty() || configInfo.socSpecKey.empty()) {
     244              :         // label 或 key 为空说明特性与芯片无关, 无需查询
     245            1 :         return true;
     246              :     }
     247            2 :     constexpr uint32_t kMaxValueLen = 16U;
     248            2 :     char_t value[kMaxValueLen] = {0};
     249            2 :     const auto ret = rtGetSocSpec(configInfo.socSpecLabel.c_str(), configInfo.socSpecKey.c_str(), value, kMaxValueLen);
     250            2 :     if (ret != RT_ERROR_NONE) {
     251            0 :         ACL_LOG_WARN(
     252              :             "Cannot get platform info, label = [%s], key = [%s]", configInfo.socSpecLabel.c_str(),
     253              :             configInfo.socSpecKey.c_str());
     254            0 :         return false;
     255              :     }
     256              :     // value "0" 或空 或非法内容 都认为 false
     257            2 :     const std::string strVal(value);
     258            2 :     return strVal == "1";
     259            2 : }
     260              : 
     261            1 : void CannInfoUtils::CheckAndUpdateAttrAvailability()
     262              : {
     263            4 :     for (auto& item : attrToCannInfo_) {
     264            3 :         auto& swConfigInfo = item.second;
     265            3 :         if (MatchVersionInfo(swConfigInfo) && CheckNPUFeatures(swConfigInfo)) {
     266            3 :             ACL_LOG_INFO("support cann attribute [%s]", swConfigInfo.readableAttrName.c_str());
     267            3 :             swConfigInfo.isAvailable = 1;
     268            3 :             attrArray_[attrNum_] = item.first;
     269            3 :             ++attrNum_;
     270              :         }
     271              :     }
     272            1 : }
     273              : } // namespace acl
        

Generated by: LCOV version 2.0-1