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, ¤tRuntimeVersion_);
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
|