Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 1 | /* |
Pablo Marquez Tello | 6fe9eaf | 2024-02-29 16:36:09 +0000 | [diff] [blame] | 2 | * Copyright (c) 2021-2024 Arm Limited. |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: MIT |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to |
| 8 | * deal in the Software without restriction, including without limitation the |
| 9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
| 10 | * sell copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in all |
| 14 | * copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 22 | * SOFTWARE. |
| 23 | */ |
| 24 | #include "src/common/cpuinfo/CpuInfo.h" |
| 25 | |
| 26 | #include "arm_compute/core/Error.h" |
| 27 | #include "arm_compute/core/Log.h" |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 28 | |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 29 | #include "support/StringSupport.h" |
| 30 | #include "support/ToolchainSupport.h" |
| 31 | |
Omar Al Khatib | f5053f7 | 2024-05-09 16:06:23 +0100 | [diff] [blame^] | 32 | #include <map> |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 33 | #include <sstream> |
| 34 | |
| 35 | #if !defined(BARE_METAL) |
| 36 | #include <algorithm> |
| 37 | #include <cstring> |
| 38 | #include <fstream> |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 39 | #if !defined(_WIN64) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 40 | #include <regex.h> /* C++ std::regex takes up a lot of space in the standalone builds */ |
| 41 | #include <sched.h> |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 42 | #endif /* !defined(_WIN64) */ |
| 43 | |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 44 | #include <thread> |
| 45 | #include <unordered_map> |
| 46 | #endif /* !defined(BARE_METAL) */ |
| 47 | |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 48 | #if !defined(_WIN64) |
Kevin Lo | 7195f71 | 2022-01-07 15:46:02 +0800 | [diff] [blame] | 49 | #if !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 50 | #include <asm/hwcap.h> /* Get HWCAP bits from asm/hwcap.h */ |
| 51 | #include <sys/auxv.h> |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 52 | #elif defined(__APPLE__) && defined(__aarch64__) |
| 53 | #include <sys/sysctl.h> |
| 54 | #include <sys/types.h> |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 55 | #endif /* defined(__APPLE__) && defined(__aarch64__)) */ |
Kevin Lo | 7195f71 | 2022-01-07 15:46:02 +0800 | [diff] [blame] | 56 | #endif /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 57 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 58 | #define ARM_COMPUTE_CPU_FEATURE_HWCAP_CPUID (1 << 11) |
| 59 | #define ARM_COMPUTE_GET_FEATURE_REG(var, freg) __asm __volatile("MRS %0, " #freg : "=r"(var)) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 60 | namespace arm_compute |
| 61 | { |
| 62 | namespace cpuinfo |
| 63 | { |
| 64 | namespace |
| 65 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 66 | #if !defined(_WIN64) && !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && \ |
| 67 | (defined(__arm__) || defined(__aarch64__)) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 68 | /** Extract MIDR using CPUID information that are exposed to user-space |
| 69 | * |
| 70 | * @param[in] max_num_cpus Maximum number of possible CPUs |
| 71 | * |
| 72 | * @return std::vector<uint32_t> A list of the MIDR of each core |
| 73 | */ |
| 74 | std::vector<uint32_t> midr_from_cpuid(uint32_t max_num_cpus) |
| 75 | { |
| 76 | std::vector<uint32_t> cpus; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 77 | for (unsigned int i = 0; i < max_num_cpus; ++i) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 78 | { |
| 79 | std::stringstream str; |
| 80 | str << "/sys/devices/system/cpu/cpu" << i << "/regs/identification/midr_el1"; |
| 81 | std::ifstream file(str.str(), std::ios::in); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 82 | if (file.is_open()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 83 | { |
| 84 | std::string line; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 85 | if (bool(getline(file, line))) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 86 | { |
| 87 | cpus.emplace_back(support::cpp11::stoul(line, nullptr, support::cpp11::NumericBase::BASE_16)); |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 | return cpus; |
| 92 | } |
| 93 | |
| 94 | /** Extract MIDR by parsing the /proc/cpuinfo meta-data |
| 95 | * |
| 96 | * @param[in] max_num_cpus Maximum number of possible CPUs |
| 97 | * |
| 98 | * @return std::vector<uint32_t> A list of the MIDR of each core |
| 99 | */ |
| 100 | std::vector<uint32_t> midr_from_proc_cpuinfo(int max_num_cpus) |
| 101 | { |
| 102 | std::vector<uint32_t> cpus; |
| 103 | |
| 104 | regex_t proc_regex; |
| 105 | regex_t imp_regex; |
| 106 | regex_t var_regex; |
| 107 | regex_t part_regex; |
| 108 | regex_t rev_regex; |
| 109 | |
| 110 | memset(&proc_regex, 0, sizeof(regex_t)); |
| 111 | memset(&imp_regex, 0, sizeof(regex_t)); |
| 112 | memset(&var_regex, 0, sizeof(regex_t)); |
| 113 | memset(&part_regex, 0, sizeof(regex_t)); |
| 114 | memset(&rev_regex, 0, sizeof(regex_t)); |
| 115 | |
| 116 | int ret_status = 0; |
| 117 | // If "long-form" cpuinfo is present, parse that to populate models. |
| 118 | ret_status |= regcomp(&proc_regex, R"(^processor.*([[:digit:]]+)$)", REG_EXTENDED); |
| 119 | ret_status |= regcomp(&imp_regex, R"(^CPU implementer.*0x(..)$)", REG_EXTENDED); |
| 120 | ret_status |= regcomp(&var_regex, R"(^CPU variant.*0x(.)$)", REG_EXTENDED); |
| 121 | ret_status |= regcomp(&part_regex, R"(^CPU part.*0x(...)$)", REG_EXTENDED); |
| 122 | ret_status |= regcomp(&rev_regex, R"(^CPU revision.*([[:digit:]]+)$)", REG_EXTENDED); |
| 123 | ARM_COMPUTE_UNUSED(ret_status); |
| 124 | ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); |
| 125 | |
| 126 | std::ifstream file("/proc/cpuinfo", std::ios::in); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 127 | if (file.is_open()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 128 | { |
| 129 | std::string line; |
| 130 | int midr = 0; |
| 131 | int curcpu = -1; |
| 132 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 133 | while (bool(getline(file, line))) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 134 | { |
| 135 | std::array<regmatch_t, 2> match; |
| 136 | ret_status = regexec(&proc_regex, line.c_str(), 2, match.data(), 0); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 137 | if (ret_status == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 138 | { |
| 139 | std::string id = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); |
| 140 | int newcpu = support::cpp11::stoi(id, nullptr); |
| 141 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 142 | if (curcpu >= 0 && midr == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 143 | { |
| 144 | // Matched a new CPU ID without any description of the previous one - looks like old format. |
| 145 | return {}; |
| 146 | } |
| 147 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 148 | if (curcpu >= 0 && curcpu < max_num_cpus) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 149 | { |
| 150 | cpus.emplace_back(midr); |
| 151 | } |
| 152 | else |
| 153 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 154 | ARM_COMPUTE_LOG_INFO_MSG_CORE( |
| 155 | "Trying to populate a core id with id greater than the expected number of cores!"); |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | midr = 0; |
| 159 | curcpu = newcpu; |
| 160 | |
| 161 | continue; |
| 162 | } |
| 163 | |
| 164 | ret_status = regexec(&imp_regex, line.c_str(), 2, match.data(), 0); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 165 | if (ret_status == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 166 | { |
| 167 | std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); |
| 168 | int impv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); |
| 169 | midr |= (impv << 24); |
| 170 | |
| 171 | continue; |
| 172 | } |
| 173 | |
| 174 | ret_status = regexec(&var_regex, line.c_str(), 2, match.data(), 0); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 175 | if (ret_status == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 176 | { |
| 177 | std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); |
| 178 | int varv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); |
| 179 | midr |= (varv << 20); |
| 180 | |
| 181 | continue; |
| 182 | } |
| 183 | |
| 184 | ret_status = regexec(&part_regex, line.c_str(), 2, match.data(), 0); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 185 | if (ret_status == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 186 | { |
| 187 | std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); |
| 188 | int partv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); |
| 189 | midr |= (partv << 4); |
| 190 | |
| 191 | continue; |
| 192 | } |
| 193 | |
| 194 | ret_status = regexec(&rev_regex, line.c_str(), 2, match.data(), 0); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 195 | if (ret_status == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 196 | { |
| 197 | std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); |
| 198 | int regv = support::cpp11::stoi(subexp, nullptr); |
| 199 | midr |= (regv); |
| 200 | midr |= (0xf << 16); |
| 201 | |
| 202 | continue; |
| 203 | } |
| 204 | } |
| 205 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 206 | if (curcpu >= 0 && curcpu < max_num_cpus) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 207 | { |
| 208 | cpus.emplace_back(midr); |
| 209 | } |
| 210 | else |
| 211 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 212 | ARM_COMPUTE_LOG_INFO_MSG_CORE( |
| 213 | "Trying to populate a core id with id greater than the expected number of cores!"); |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 214 | } |
| 215 | } |
| 216 | |
| 217 | // Free allocated memory |
| 218 | regfree(&proc_regex); |
| 219 | regfree(&imp_regex); |
| 220 | regfree(&var_regex); |
| 221 | regfree(&part_regex); |
| 222 | regfree(&rev_regex); |
| 223 | |
| 224 | return cpus; |
| 225 | } |
| 226 | |
| 227 | /** Get the maximim number of CPUs in the system by parsing /sys/devices/system/cpu/present |
| 228 | * |
| 229 | * @return int Maximum number of CPUs |
| 230 | */ |
| 231 | int get_max_cpus() |
| 232 | { |
| 233 | int max_cpus = 1; |
| 234 | std::ifstream CPUspresent; |
| 235 | CPUspresent.open("/sys/devices/system/cpu/present", std::ios::in); |
| 236 | bool success = false; |
| 237 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 238 | if (CPUspresent.is_open()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 239 | { |
| 240 | std::string line; |
| 241 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 242 | if (bool(getline(CPUspresent, line))) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 243 | { |
| 244 | /* The content of this file is a list of ranges or single values, e.g. |
| 245 | * 0-5, or 1-3,5,7 or similar. As we are interested in the |
| 246 | * max valid ID, we just need to find the last valid |
| 247 | * delimiter ('-' or ',') and parse the integer immediately after that. |
| 248 | */ |
| 249 | auto startfrom = line.begin(); |
| 250 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 251 | for (auto i = line.begin(); i < line.end(); ++i) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 252 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 253 | if (*i == '-' || *i == ',') |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 254 | { |
| 255 | startfrom = i + 1; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | line.erase(line.begin(), startfrom); |
| 260 | |
| 261 | max_cpus = support::cpp11::stoi(line, nullptr) + 1; |
| 262 | success = true; |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | // Return std::thread::hardware_concurrency() as a fallback. |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 267 | if (!success) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 268 | { |
| 269 | max_cpus = std::thread::hardware_concurrency(); |
| 270 | } |
| 271 | return max_cpus; |
| 272 | } |
Omar Al Khatib | f5053f7 | 2024-05-09 16:06:23 +0100 | [diff] [blame^] | 273 | |
| 274 | const static std::map<std::string, std::vector<uint32_t>> known_configurations_with_little_cores = { |
| 275 | {"xiaomi14-pro", {379, 379, 923, 923, 923, 867, 867, 1024}}}; |
| 276 | |
| 277 | const static std::map<std::string, uint32_t> number_of_cores_to_use = {{"xiaomi14-pro", 6}}; |
| 278 | |
| 279 | #if defined(__ANDROID__) |
| 280 | std::vector<uint32_t> get_cpu_capacities() |
| 281 | { |
| 282 | std::vector<uint32_t> cpu_capacities; |
| 283 | for (int i = 0; i < get_max_cpus(); ++i) |
| 284 | { |
| 285 | std::stringstream str; |
| 286 | str << "/sys/devices/system/cpu/cpu" << i << "/cpu_capacity"; |
| 287 | std::ifstream file(str.str(), std::ios::in); |
| 288 | if (file.is_open()) |
| 289 | { |
| 290 | std::string line; |
| 291 | if (bool(getline(file, line))) |
| 292 | { |
| 293 | cpu_capacities.emplace_back(support::cpp11::stoul(line)); |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | return cpu_capacities; |
| 299 | } |
| 300 | |
| 301 | uint32_t not_little_num_cpus_internal() |
| 302 | { |
| 303 | std::vector<uint32_t> cpus_all = get_cpu_capacities(); |
| 304 | std::vector<uint32_t> cpus_not_little; |
| 305 | |
| 306 | for (auto &it : known_configurations_with_little_cores) |
| 307 | { |
| 308 | if (it.second == cpus_all) |
| 309 | { |
| 310 | return number_of_cores_to_use.find(it.first)->second; |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | std::vector<uint32_t>::iterator result = std::max_element(cpus_all.begin(), cpus_all.end()); |
| 315 | uint32_t max_capacity = *result; |
| 316 | uint32_t threshold = max_capacity / 2; |
| 317 | for (unsigned int i = 0; i < cpus_all.size(); i++) |
| 318 | { |
| 319 | if (!(cpus_all[i] < threshold)) |
| 320 | { |
| 321 | cpus_not_little.emplace_back(cpus_all[i]); |
| 322 | } |
| 323 | } |
| 324 | return cpus_not_little.size(); |
| 325 | } |
| 326 | |
| 327 | bool has_little_mid_big_internal() |
| 328 | { |
| 329 | std::vector<uint32_t> cpus_all = get_cpu_capacities(); |
| 330 | std::vector<uint32_t> cpus_not_little; |
| 331 | |
| 332 | for (auto &it : known_configurations_with_little_cores) |
| 333 | { |
| 334 | if (it.second == cpus_all) |
| 335 | { |
| 336 | return true; |
| 337 | } |
| 338 | } |
| 339 | std::sort(cpus_all.begin(), cpus_all.end()); |
| 340 | std::vector<uint32_t>::iterator ip; |
| 341 | ip = std::unique(cpus_all.begin(), cpus_all.end()); |
| 342 | cpus_all.resize(std::distance(cpus_all.begin(), ip)); |
| 343 | |
| 344 | if (cpus_all.size() == 3) |
| 345 | { |
| 346 | return true; |
| 347 | } |
| 348 | else |
| 349 | { |
| 350 | return false; |
| 351 | } |
| 352 | } |
| 353 | #endif /* defined(__ANDROID__) */ |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 354 | #elif defined(__aarch64__) && \ |
| 355 | defined(__APPLE__) /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 356 | /** Query features through sysctlbyname |
| 357 | * |
| 358 | * @return int value queried |
| 359 | */ |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 360 | int get_hw_capability(const std::string &cap) |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 361 | { |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 362 | int64_t result(0); |
| 363 | size_t size = sizeof(result); |
| 364 | sysctlbyname(cap.c_str(), &result, &size, NULL, 0); |
| 365 | return result; |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 366 | } |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 367 | #endif /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ |
Michalis Spyrou | 20fca52 | 2021-06-07 14:23:57 +0100 | [diff] [blame] | 368 | |
| 369 | #if defined(BARE_METAL) && defined(__aarch64__) |
| 370 | uint64_t get_sve_feature_reg() |
| 371 | { |
| 372 | uint64_t svefr0 = 0; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 373 | __asm __volatile(".inst 0xd5380483 // mrs x3, ID_AA64ZFR0_EL1\n" |
| 374 | "MOV %0, X3" |
| 375 | : "=r"(svefr0) |
| 376 | : |
| 377 | : "x3"); |
Michalis Spyrou | 20fca52 | 2021-06-07 14:23:57 +0100 | [diff] [blame] | 378 | return svefr0; |
| 379 | } |
| 380 | #endif /* defined(BARE_METAL) && defined(__aarch64__) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 381 | } // namespace |
| 382 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 383 | CpuInfo::CpuInfo(CpuIsaInfo isa, std::vector<CpuModel> cpus) : _isa(std::move(isa)), _cpus(std::move(cpus)) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 384 | { |
| 385 | } |
| 386 | |
| 387 | CpuInfo CpuInfo::build() |
| 388 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 389 | #if !defined(_WIN64) && !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && \ |
| 390 | (defined(__arm__) || defined(__aarch64__)) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 391 | const uint32_t hwcaps = getauxval(AT_HWCAP); |
| 392 | const uint32_t hwcaps2 = getauxval(AT_HWCAP2); |
| 393 | const uint32_t max_cpus = get_max_cpus(); |
| 394 | |
| 395 | // Populate midr values |
| 396 | std::vector<uint32_t> cpus_midr; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 397 | if (hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_CPUID) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 398 | { |
| 399 | cpus_midr = midr_from_cpuid(max_cpus); |
| 400 | } |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 401 | if (cpus_midr.empty()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 402 | { |
| 403 | cpus_midr = midr_from_proc_cpuinfo(max_cpus); |
| 404 | } |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 405 | if (cpus_midr.empty()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 406 | { |
| 407 | cpus_midr.resize(max_cpus, 0); |
| 408 | } |
| 409 | |
| 410 | // Populate isa (Assume homogeneous ISA specification) |
| 411 | CpuIsaInfo isa = init_cpu_isa_from_hwcaps(hwcaps, hwcaps2, cpus_midr.back()); |
| 412 | |
| 413 | // Convert midr to models |
| 414 | std::vector<CpuModel> cpus_model; |
| 415 | std::transform(std::begin(cpus_midr), std::end(cpus_midr), std::back_inserter(cpus_model), |
| 416 | [](uint32_t midr) -> CpuModel { return midr_to_model(midr); }); |
| 417 | |
| 418 | CpuInfo info(isa, cpus_model); |
| 419 | return info; |
| 420 | |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 421 | #elif (BARE_METAL) && \ |
| 422 | defined( \ |
| 423 | __aarch64__) /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 424 | |
| 425 | // Assume single CPU in bare metal mode. Just read the ID register and feature bits directly. |
Viet-Hoa Do | 03b2971 | 2022-06-01 11:47:14 +0100 | [diff] [blame] | 426 | uint64_t isar0 = 0, isar1 = 0, pfr0 = 0, pfr1 = 0, svefr0 = 0, midr = 0; |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 427 | ARM_COMPUTE_GET_FEATURE_REG(isar0, ID_AA64ISAR0_EL1); |
| 428 | ARM_COMPUTE_GET_FEATURE_REG(isar1, ID_AA64ISAR1_EL1); |
| 429 | ARM_COMPUTE_GET_FEATURE_REG(pfr0, ID_AA64PFR0_EL1); |
Viet-Hoa Do | 03b2971 | 2022-06-01 11:47:14 +0100 | [diff] [blame] | 430 | ARM_COMPUTE_GET_FEATURE_REG(pfr1, ID_AA64PFR1_EL1); |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 431 | ARM_COMPUTE_GET_FEATURE_REG(midr, MIDR_EL1); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 432 | if ((pfr0 >> 32) & 0xf) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 433 | { |
| 434 | svefr0 = get_sve_feature_reg(); |
| 435 | } |
| 436 | |
Viet-Hoa Do | 03b2971 | 2022-06-01 11:47:14 +0100 | [diff] [blame] | 437 | CpuIsaInfo isa = init_cpu_isa_from_regs(isar0, isar1, pfr0, pfr1, svefr0, midr); |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 438 | std::vector<CpuModel> cpus_model(1, midr_to_model(midr)); |
| 439 | CpuInfo info(isa, cpus_model); |
| 440 | return info; |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 441 | #elif defined(__aarch64__) && defined(__APPLE__) /* #elif(BARE_METAL) && defined(__aarch64__) */ |
Pablo Marquez Tello | 67c3c63 | 2023-01-23 17:00:41 +0000 | [diff] [blame] | 442 | int ncpus = get_hw_capability("hw.perflevel0.logicalcpu"); |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 443 | CpuIsaInfo isainfo; |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 444 | std::vector<CpuModel> cpus_model(ncpus); |
| 445 | isainfo.neon = get_hw_capability("hw.optional.neon"); |
| 446 | isainfo.fp16 = get_hw_capability("hw.optional.neon_fp16"); |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 447 | isainfo.dot = get_hw_capability("hw.optional.arm.FEAT_DotProd"); |
Viet-Hoa Do | 4c3f716 | 2024-05-10 15:21:01 +0100 | [diff] [blame] | 448 | isainfo.bf16 = get_hw_capability("hw.optional.arm.FEAT_BF16"); |
| 449 | isainfo.i8mm = get_hw_capability("hw.optional.arm.FEAT_I8MM"); |
Pablo Tello | 4e66d70 | 2022-03-07 18:20:12 +0000 | [diff] [blame] | 450 | CpuInfo info(isainfo, cpus_model); |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 451 | return info; |
Pablo Marquez Tello | 6fe9eaf | 2024-02-29 16:36:09 +0000 | [diff] [blame] | 452 | #elif defined(__aarch64__) && defined(_WIN64) /* #elif defined(__aarch64__) && defined(__APPLE__) */ |
| 453 | CpuIsaInfo isainfo; |
| 454 | isainfo.neon = true; |
| 455 | CpuInfo info(isainfo, {CpuModel::GENERIC}); |
| 456 | return info; |
| 457 | #else /* #elif defined(__aarch64__) && defined(_WIN64) */ |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 458 | CpuInfo info(CpuIsaInfo(), {CpuModel::GENERIC}); |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 459 | return info; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 460 | #endif /* !defined(BARE_METAL) && !defined(__APPLE__) && !defined(__OpenBSD__) && (defined(__arm__) || defined(__aarch64__)) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 461 | } |
| 462 | |
| 463 | CpuModel CpuInfo::cpu_model(uint32_t cpuid) const |
| 464 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 465 | if (cpuid < _cpus.size()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 466 | { |
| 467 | return _cpus[cpuid]; |
| 468 | } |
| 469 | return CpuModel::GENERIC; |
| 470 | } |
| 471 | |
| 472 | CpuModel CpuInfo::cpu_model() const |
| 473 | { |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 474 | #if defined(_WIN64) || defined(BARE_METAL) || defined(__APPLE__) || defined(__OpenBSD__) || \ |
| 475 | (!defined(__arm__) && !defined(__aarch64__)) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 476 | return cpu_model(0); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 477 | #else /* defined(BARE_METAL) || defined(__APPLE__) || defined(__OpenBSD__) || (!defined(__arm__) && !defined(__aarch64__)) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 478 | return cpu_model(sched_getcpu()); |
Kevin Lo | 7195f71 | 2022-01-07 15:46:02 +0800 | [diff] [blame] | 479 | #endif /* defined(BARE_METAL) || defined(__APPLE__) || defined(__OpenBSD__) || (!defined(__arm__) && !defined(__aarch64__)) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 480 | } |
| 481 | |
| 482 | uint32_t CpuInfo::num_cpus() const |
| 483 | { |
| 484 | return _cpus.size(); |
| 485 | } |
| 486 | |
Omar Al Khatib | f5053f7 | 2024-05-09 16:06:23 +0100 | [diff] [blame^] | 487 | uint32_t CpuInfo::not_little_num_cpus() const |
| 488 | { |
| 489 | #if defined(__ANDROID__) |
| 490 | return not_little_num_cpus_internal(); |
| 491 | #else /* defined(__ANDROID__) */ |
| 492 | return num_cpus(); |
| 493 | #endif /* defined(__ANDROID__) */ |
| 494 | } |
| 495 | |
| 496 | bool CpuInfo::has_little_mid_big() const |
| 497 | { |
| 498 | #if defined(__ANDROID__) |
| 499 | return has_little_mid_big_internal(); |
| 500 | #else /* defined(__ANDROID__) */ |
| 501 | return false; |
| 502 | #endif /* defined(__ANDROID__) */ |
| 503 | } |
| 504 | |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 505 | uint32_t num_threads_hint() |
| 506 | { |
| 507 | unsigned int num_threads_hint = 1; |
| 508 | |
Viet-Hoa Do | 13321f7 | 2023-02-24 17:32:27 +0000 | [diff] [blame] | 509 | #if !defined(BARE_METAL) && !defined(_WIN64) && !defined(ARM_COMPUTE_DISABLE_THREADS_HINT) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 510 | std::vector<std::string> cpus; |
| 511 | cpus.reserve(64); |
| 512 | |
| 513 | // CPU part regex |
| 514 | regex_t cpu_part_rgx; |
| 515 | memset(&cpu_part_rgx, 0, sizeof(regex_t)); |
| 516 | int ret_status = regcomp(&cpu_part_rgx, R"(.*CPU part.+/?\:[[:space:]]+([[:alnum:]]+).*)", REG_EXTENDED); |
| 517 | ARM_COMPUTE_UNUSED(ret_status); |
| 518 | ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); |
| 519 | |
| 520 | // Read cpuinfo and get occurrence of each core |
| 521 | std::ifstream cpuinfo_file("/proc/cpuinfo", std::ios::in); |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 522 | if (cpuinfo_file.is_open()) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 523 | { |
| 524 | std::string line; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 525 | while (bool(getline(cpuinfo_file, line))) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 526 | { |
| 527 | std::array<regmatch_t, 2> match; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 528 | if (regexec(&cpu_part_rgx, line.c_str(), 2, match.data(), 0) == 0) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 529 | { |
| 530 | cpus.emplace_back(line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so))); |
| 531 | } |
| 532 | } |
| 533 | } |
| 534 | regfree(&cpu_part_rgx); |
| 535 | |
| 536 | // Get min number of threads |
| 537 | std::sort(std::begin(cpus), std::end(cpus)); |
| 538 | auto least_frequent_cpu_occurences = [](const std::vector<std::string> &cpus) -> uint32_t |
| 539 | { |
| 540 | std::unordered_map<std::string, uint32_t> cpus_freq; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 541 | for (const auto &cpu : cpus) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 542 | { |
| 543 | cpus_freq[cpu]++; |
| 544 | } |
| 545 | |
| 546 | uint32_t vmin = cpus.size() + 1; |
Felix Thomasmathibalan | afd38f0 | 2023-09-27 17:46:17 +0100 | [diff] [blame] | 547 | for (const auto &cpu_freq : cpus_freq) |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 548 | { |
| 549 | vmin = std::min(vmin, cpu_freq.second); |
| 550 | } |
| 551 | return vmin; |
| 552 | }; |
| 553 | |
| 554 | // Set thread hint |
| 555 | num_threads_hint = cpus.empty() ? std::thread::hardware_concurrency() : least_frequent_cpu_occurences(cpus); |
Viet-Hoa Do | 13321f7 | 2023-02-24 17:32:27 +0000 | [diff] [blame] | 556 | #endif /* !defined(BARE_METAL) && !defined(_WIN64) && !defined(ARM_COMPUTE_DISABLE_THREADS_HINT) */ |
Georgios Pinitas | 08302c1 | 2021-06-09 10:08:27 +0100 | [diff] [blame] | 557 | |
| 558 | return num_threads_hint; |
| 559 | } |
| 560 | } // namespace cpuinfo |
Pablo Marquez Tello | 639f0f6 | 2022-01-21 15:25:27 +0000 | [diff] [blame] | 561 | } // namespace arm_compute |