From 08302c17cd57356b35d46e17dc8d8f76672da5cf Mon Sep 17 00:00:00 2001 From: Georgios Pinitas Date: Wed, 9 Jun 2021 10:08:27 +0100 Subject: Add CPU discovery capabilities. Resolves: COMPMID-4500 Signed-off-by: Georgios Pinitas Change-Id: I008c51934ef813fb1f489b531288c4419e701955 Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/5799 Reviewed-by: Michele Di Giorgio Tested-by: Arm Jenkins Comments-Addressed: Arm Jenkins --- src/common/cpuinfo/CpuInfo.cpp | 405 +++++++++++++++++++ src/common/cpuinfo/CpuInfo.h | 113 ++++++ src/common/cpuinfo/CpuIsaInfo.cpp | 198 +++++++++ src/common/cpuinfo/CpuIsaInfo.h | 78 ++++ src/common/cpuinfo/CpuModel.cpp | 190 +++++++++ src/common/cpuinfo/CpuModel.h | 79 ++++ src/common/cpuinfo/target/CpuInfoSveUtils.cpp | 40 ++ src/common/cpuinfo/target/CpuInfoSveUtils.h | 40 ++ src/core/CPP/CPPTypes.cpp | 92 ++--- src/core/cpu/kernels/assembly/arm_gemm.hpp | 1 + src/cpu/CpuContext.cpp | 2 - src/runtime/CPP/CPPScheduler.cpp | 1 - src/runtime/CPUUtils.cpp | 556 -------------------------- src/runtime/CPUUtils.h | 51 --- src/runtime/DeviceProperties.cpp | 34 -- src/runtime/IScheduler.cpp | 5 +- src/runtime/MEMUtils.cpp | 103 ----- src/runtime/OMP/OMPScheduler.cpp | 1 - src/runtime/RuntimeContext.cpp | 9 +- 19 files changed, 1175 insertions(+), 823 deletions(-) create mode 100644 src/common/cpuinfo/CpuInfo.cpp create mode 100644 src/common/cpuinfo/CpuInfo.h create mode 100644 src/common/cpuinfo/CpuIsaInfo.cpp create mode 100644 src/common/cpuinfo/CpuIsaInfo.h create mode 100644 src/common/cpuinfo/CpuModel.cpp create mode 100644 src/common/cpuinfo/CpuModel.h create mode 100644 src/common/cpuinfo/target/CpuInfoSveUtils.cpp create mode 100644 src/common/cpuinfo/target/CpuInfoSveUtils.h delete mode 100644 src/runtime/CPUUtils.cpp delete mode 100644 src/runtime/CPUUtils.h delete mode 100644 src/runtime/DeviceProperties.cpp delete mode 100644 src/runtime/MEMUtils.cpp (limited to 'src') diff --git a/src/common/cpuinfo/CpuInfo.cpp b/src/common/cpuinfo/CpuInfo.cpp new file mode 100644 index 0000000000..436e7ea803 --- /dev/null +++ b/src/common/cpuinfo/CpuInfo.cpp @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/common/cpuinfo/CpuInfo.h" + +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Log.h" +#include "src/common/cpuinfo/target/CpuInfoSveUtils.h" +#include "support/StringSupport.h" +#include "support/ToolchainSupport.h" + +#include + +#if !defined(BARE_METAL) +#include +#include +#include +#include /* C++ std::regex takes up a lot of space in the standalone builds */ +#include +#include +#include +#endif /* !defined(BARE_METAL) */ + +#if !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) +#include /* Get HWCAP bits from asm/hwcap.h */ +#include +#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ + +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_CPUID (1 << 11) +#define ARM_COMPUTE_GET_FEATURE_REG(var, freg) __asm __volatile("MRS %0, " #freg \ + : "=r"(var)) +namespace arm_compute +{ +namespace cpuinfo +{ +namespace +{ +#if !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) +/** Extract MIDR using CPUID information that are exposed to user-space + * + * @param[in] max_num_cpus Maximum number of possible CPUs + * + * @return std::vector A list of the MIDR of each core + */ +std::vector midr_from_cpuid(uint32_t max_num_cpus) +{ + std::vector cpus; + for(unsigned int i = 0; i < max_num_cpus; ++i) + { + std::stringstream str; + str << "/sys/devices/system/cpu/cpu" << i << "/regs/identification/midr_el1"; + std::ifstream file(str.str(), std::ios::in); + if(file.is_open()) + { + std::string line; + if(bool(getline(file, line))) + { + cpus.emplace_back(support::cpp11::stoul(line, nullptr, support::cpp11::NumericBase::BASE_16)); + } + } + } + return cpus; +} + +/** Extract MIDR by parsing the /proc/cpuinfo meta-data + * + * @param[in] max_num_cpus Maximum number of possible CPUs + * + * @return std::vector A list of the MIDR of each core + */ +std::vector midr_from_proc_cpuinfo(int max_num_cpus) +{ + std::vector cpus; + + regex_t proc_regex; + regex_t imp_regex; + regex_t var_regex; + regex_t part_regex; + regex_t rev_regex; + + memset(&proc_regex, 0, sizeof(regex_t)); + memset(&imp_regex, 0, sizeof(regex_t)); + memset(&var_regex, 0, sizeof(regex_t)); + memset(&part_regex, 0, sizeof(regex_t)); + memset(&rev_regex, 0, sizeof(regex_t)); + + int ret_status = 0; + // If "long-form" cpuinfo is present, parse that to populate models. + ret_status |= regcomp(&proc_regex, R"(^processor.*([[:digit:]]+)$)", REG_EXTENDED); + ret_status |= regcomp(&imp_regex, R"(^CPU implementer.*0x(..)$)", REG_EXTENDED); + ret_status |= regcomp(&var_regex, R"(^CPU variant.*0x(.)$)", REG_EXTENDED); + ret_status |= regcomp(&part_regex, R"(^CPU part.*0x(...)$)", REG_EXTENDED); + ret_status |= regcomp(&rev_regex, R"(^CPU revision.*([[:digit:]]+)$)", REG_EXTENDED); + ARM_COMPUTE_UNUSED(ret_status); + ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); + + std::ifstream file("/proc/cpuinfo", std::ios::in); + if(file.is_open()) + { + std::string line; + int midr = 0; + int curcpu = -1; + + while(bool(getline(file, line))) + { + std::array match; + ret_status = regexec(&proc_regex, line.c_str(), 2, match.data(), 0); + if(ret_status == 0) + { + std::string id = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int newcpu = support::cpp11::stoi(id, nullptr); + + if(curcpu >= 0 && midr == 0) + { + // Matched a new CPU ID without any description of the previous one - looks like old format. + return {}; + } + + if(curcpu >= 0 && curcpu < max_num_cpus) + { + cpus.emplace_back(midr); + } + else + { + ARM_COMPUTE_LOG_INFO_MSG_CORE("Trying to populate a core id with id greater than the expected number of cores!"); + } + + midr = 0; + curcpu = newcpu; + + continue; + } + + ret_status = regexec(&imp_regex, line.c_str(), 2, match.data(), 0); + if(ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int impv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); + midr |= (impv << 24); + + continue; + } + + ret_status = regexec(&var_regex, line.c_str(), 2, match.data(), 0); + if(ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int varv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); + midr |= (varv << 20); + + continue; + } + + ret_status = regexec(&part_regex, line.c_str(), 2, match.data(), 0); + if(ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int partv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); + midr |= (partv << 4); + + continue; + } + + ret_status = regexec(&rev_regex, line.c_str(), 2, match.data(), 0); + if(ret_status == 0) + { + std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); + int regv = support::cpp11::stoi(subexp, nullptr); + midr |= (regv); + midr |= (0xf << 16); + + continue; + } + } + + if(curcpu >= 0 && curcpu < max_num_cpus) + { + cpus.emplace_back(midr); + } + else + { + ARM_COMPUTE_LOG_INFO_MSG_CORE("Trying to populate a core id with id greater than the expected number of cores!"); + } + } + + // Free allocated memory + regfree(&proc_regex); + regfree(&imp_regex); + regfree(&var_regex); + regfree(&part_regex); + regfree(&rev_regex); + + return cpus; +} + +/** Get the maximim number of CPUs in the system by parsing /sys/devices/system/cpu/present + * + * @return int Maximum number of CPUs + */ +int get_max_cpus() +{ + int max_cpus = 1; + std::ifstream CPUspresent; + CPUspresent.open("/sys/devices/system/cpu/present", std::ios::in); + bool success = false; + + if(CPUspresent.is_open()) + { + std::string line; + + if(bool(getline(CPUspresent, line))) + { + /* The content of this file is a list of ranges or single values, e.g. + * 0-5, or 1-3,5,7 or similar. As we are interested in the + * max valid ID, we just need to find the last valid + * delimiter ('-' or ',') and parse the integer immediately after that. + */ + auto startfrom = line.begin(); + + for(auto i = line.begin(); i < line.end(); ++i) + { + if(*i == '-' || *i == ',') + { + startfrom = i + 1; + } + } + + line.erase(line.begin(), startfrom); + + max_cpus = support::cpp11::stoi(line, nullptr) + 1; + success = true; + } + } + + // Return std::thread::hardware_concurrency() as a fallback. + if(!success) + { + max_cpus = std::thread::hardware_concurrency(); + } + return max_cpus; +} +#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ +} // namespace + +CpuInfo::CpuInfo(CpuIsaInfo isa, std::vector cpus) + : _isa(std::move(isa)), _cpus(std::move(cpus)) +{ +} + +CpuInfo CpuInfo::build() +{ +#if !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) + const uint32_t hwcaps = getauxval(AT_HWCAP); + const uint32_t hwcaps2 = getauxval(AT_HWCAP2); + const uint32_t max_cpus = get_max_cpus(); + + // Populate midr values + std::vector cpus_midr; + if(hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_CPUID) + { + cpus_midr = midr_from_cpuid(max_cpus); + } + if(cpus_midr.empty()) + { + cpus_midr = midr_from_proc_cpuinfo(max_cpus); + } + if(cpus_midr.empty()) + { + cpus_midr.resize(max_cpus, 0); + } + + // Populate isa (Assume homogeneous ISA specification) + CpuIsaInfo isa = init_cpu_isa_from_hwcaps(hwcaps, hwcaps2, cpus_midr.back()); + + // Convert midr to models + std::vector cpus_model; + std::transform(std::begin(cpus_midr), std::end(cpus_midr), std::back_inserter(cpus_model), + [](uint32_t midr) -> CpuModel { return midr_to_model(midr); }); + + CpuInfo info(isa, cpus_model); + return info; + +#elif(BARE_METAL) && defined(__aarch64__) /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ + + // Assume single CPU in bare metal mode. Just read the ID register and feature bits directly. + uint64_t isar0 = 0, isar1 = 0, pfr0 = 0, svefr0 = 0, midr = 0; + ARM_COMPUTE_GET_FEATURE_REG(isar0, ID_AA64ISAR0_EL1); + ARM_COMPUTE_GET_FEATURE_REG(isar1, ID_AA64ISAR1_EL1); + ARM_COMPUTE_GET_FEATURE_REG(pfr0, ID_AA64PFR0_EL1); + ARM_COMPUTE_GET_FEATURE_REG(midr, MIDR_EL1); + if((pfr0 >> 32) & 0xf) + { + svefr0 = get_sve_feature_reg(); + } + + CpuIsaInfo isa = init_cpu_isa_from_regs(isar0, isar1, pfr0, svefr0, midr); + std::vector cpus_model(1, midr_to_model(midr)); + CpuInfo info(isa, cpus_model); + return info; +#else /* #elif(BARE_METAL) && defined(__aarch64__) */ + CpuInfo info(CpuIsaInfo(), { CpuModel::GENERIC }); + return info; +#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ +} + +CpuModel CpuInfo::cpu_model(uint32_t cpuid) const +{ + if(cpuid < _cpus.size()) + { + return _cpus[cpuid]; + } + return CpuModel::GENERIC; +} + +CpuModel CpuInfo::cpu_model() const +{ +#if defined(BARE_METAL) || defined(__APPLE__) || (!defined(__arm__) && !defined(__aarch64__)) + return cpu_model(0); +#else /* defined(BARE_METAL) || defined(__APPLE__) || (!defined(__arm__) && !defined(__aarch64__)) */ + return cpu_model(sched_getcpu()); +#endif /* defined(BARE_METAL) || defined(__APPLE__) || (!defined(__arm__) && !defined(__aarch64__)) */ +} + +uint32_t CpuInfo::num_cpus() const +{ + return _cpus.size(); +} + +uint32_t num_threads_hint() +{ + unsigned int num_threads_hint = 1; + +#if !defined(BARE_METAL) + std::vector cpus; + cpus.reserve(64); + + // CPU part regex + regex_t cpu_part_rgx; + memset(&cpu_part_rgx, 0, sizeof(regex_t)); + int ret_status = regcomp(&cpu_part_rgx, R"(.*CPU part.+/?\:[[:space:]]+([[:alnum:]]+).*)", REG_EXTENDED); + ARM_COMPUTE_UNUSED(ret_status); + ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); + + // Read cpuinfo and get occurrence of each core + std::ifstream cpuinfo_file("/proc/cpuinfo", std::ios::in); + if(cpuinfo_file.is_open()) + { + std::string line; + while(bool(getline(cpuinfo_file, line))) + { + std::array match; + if(regexec(&cpu_part_rgx, line.c_str(), 2, match.data(), 0) == 0) + { + cpus.emplace_back(line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so))); + } + } + } + regfree(&cpu_part_rgx); + + // Get min number of threads + std::sort(std::begin(cpus), std::end(cpus)); + auto least_frequent_cpu_occurences = [](const std::vector &cpus) -> uint32_t + { + std::unordered_map cpus_freq; + for(const auto &cpu : cpus) + { + cpus_freq[cpu]++; + } + + uint32_t vmin = cpus.size() + 1; + for(const auto &cpu_freq : cpus_freq) + { + vmin = std::min(vmin, cpu_freq.second); + } + return vmin; + }; + + // Set thread hint + num_threads_hint = cpus.empty() ? std::thread::hardware_concurrency() : least_frequent_cpu_occurences(cpus); +#endif /* !defined(BARE_METAL) */ + + return num_threads_hint; +} +} // namespace cpuinfo +} // namespace arm_compute \ No newline at end of file diff --git a/src/common/cpuinfo/CpuInfo.h b/src/common/cpuinfo/CpuInfo.h new file mode 100644 index 0000000000..f3056d2faf --- /dev/null +++ b/src/common/cpuinfo/CpuInfo.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef SRC_COMMON_CPUINFO_H +#define SRC_COMMON_CPUINFO_H + +#include "src/common/cpuinfo/CpuIsaInfo.h" +#include "src/common/cpuinfo/CpuModel.h" + +#include +#include + +namespace arm_compute +{ +namespace cpuinfo +{ +/** Aggregate class that contains CPU related information + * + * Contains information about the numbers of the CPUs, the model of each CPU, + * ISA related information and more + * + * @note We can safely assume that the ISA is common between different clusters of cores + */ +class CpuInfo +{ +public: + /** Default constructor */ + CpuInfo() = default; + /** Construct a new Cpu Info object + * + * @param[in] isa ISA capabilities information + * @param[in] cpus CPU models information + */ + CpuInfo(CpuIsaInfo isa, std::vector cpus); + /** CpuInfo builder function from system related information + * + * @return CpuInfo A populated CpuInfo structure + */ + static CpuInfo build(); + +public: + bool has_neon() const + { + return _isa.neon; + } + bool has_sve() const + { + return _isa.sve; + } + bool has_sve2() const + { + return _isa.sve2; + } + bool has_fp16() const + { + return _isa.fp16; + } + bool has_bf16() const + { + return _isa.bf16; + } + bool has_dotprod() const + { + return _isa.dot; + } + bool has_immla() const + { + return _isa.immla; + } + bool has_fmmla() const + { + return _isa.fmmla; + } + + CpuModel cpu_model(uint32_t cpuid) const; + CpuModel cpu_model() const; + uint32_t num_cpus() const; + +private: + CpuIsaInfo _isa{}; + std::vector _cpus{}; +}; + +/** Some systems have both big and small cores, this fuction computes the minimum number of cores + * that are exactly the same on the system. To maximize performance the library attempts to process + * workloads concurrently using as many threads as big cores are available on the system. + * + * @return The minumum number of common cores. + */ +uint32_t num_threads_hint(); +} // namespace cpuinfo +} // namespace arm_compute +#endif /* SRC_COMMON_CPUINFO_H */ diff --git a/src/common/cpuinfo/CpuIsaInfo.cpp b/src/common/cpuinfo/CpuIsaInfo.cpp new file mode 100644 index 0000000000..d99f9aec29 --- /dev/null +++ b/src/common/cpuinfo/CpuIsaInfo.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/common/cpuinfo/CpuIsaInfo.h" + +#include "arm_compute/core/Error.h" +#include "src/common/cpuinfo/CpuModel.h" + +/* Arm Feature flags */ +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_HALF (1 << 1) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_NEON (1 << 12) + +/* Arm64 Feature flags */ +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMD (1 << 1) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_FPHP (1 << 9) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDHP (1 << 10) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDDP (1 << 20) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP_SVE (1 << 22) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVE2 (1 << 1) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEI8MM (1 << 9) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEF32MM (1 << 10) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEBF16 (1 << 12) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_I8MM (1 << 13) +#define ARM_COMPUTE_CPU_FEATURE_HWCAP2_BF16 (1 << 14) + +namespace arm_compute +{ +namespace cpuinfo +{ +namespace +{ +#if defined(__arm__) +void decode_hwcaps(CpuIsaInfo &isa, const uint32_t hwcaps, const uint32_t hwcaps2) +{ + ARM_COMPUTE_UNUSED(hwcaps2); + + if(hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_HALF) + { + isa.fp16 = true; + } + if(hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_NEON) + { + isa.neon = true; + } +} +#elif defined(__aarch64__) +void decode_hwcaps(CpuIsaInfo &isa, const uint32_t hwcaps, const uint32_t hwcaps2) +{ + // High-level SIMD support + if(hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMD) + { + isa.neon = true; + } + if(hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_SVE) + { + isa.sve = true; + } + if(hwcaps2 & ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVE2) + { + isa.sve2 = true; + } + + // Data-type support + const uint32_t fp16_support_mask = ARM_COMPUTE_CPU_FEATURE_HWCAP_FPHP | ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDHP; + if(hwcaps & fp16_support_mask) + { + isa.fp16 = true; + } + if(hwcaps2 & ARM_COMPUTE_CPU_FEATURE_HWCAP2_BF16) + { + isa.bf16 = true; + } + + // Instruction extensions + if(hwcaps & ARM_COMPUTE_CPU_FEATURE_HWCAP_ASIMDDP) + { + isa.dot = true; + } + if(hwcaps2 & ARM_COMPUTE_CPU_FEATURE_HWCAP2_I8MM) + { + isa.immla = true; + } + if(hwcaps2 & ARM_COMPUTE_CPU_FEATURE_HWCAP2_SVEF32MM) + { + isa.fmmla = true; + } +} +#else /* defined(__aarch64__) */ +void decode_hwcaps(CpuIsaInfo &isa, const uint32_t hwcaps, const uint32_t hwcaps2) +{ + ARM_COMPUTE_UNUSED(isa, hwcaps, hwcaps2); +} +#endif /* defined(__aarch64__) */ + +void decode_regs(CpuIsaInfo &isa, const uint64_t isar0, const uint64_t isar1, const uint64_t pfr0, const uint64_t svefr0) +{ + // High-level SIMD support + if((pfr0 >> 32) & 0xf) + { + isa.sve = true; + } + if(svefr0 & 0xf) + { + isa.sve2 = true; + } + + // Data-type support + if((pfr0 >> 16) & 0xf) + { + isa.fp16 = true; + } + if((isar1 >> 44) & 0xf) + { + isa.bf16 = true; + } + + // Instruction extensions + if((isar0 >> 44) & 0xf) + { + isa.dot = true; + } + if((isar1 >> 48) & 0xf) + { + isa.immla = true; + } + if((svefr0 >> 52) & 0xf) + { + isa.fmmla = true; + } +} + +/** Handle features from whitelisted models in case of problematic kernels + * + * @param[in, out] isa ISA to update + * @param[in] model CPU model type + */ +void whitelisted_model_features(CpuIsaInfo &isa, CpuModel model) +{ + if(isa.dot == false) + { + isa.dot = model_supports_dot(model); + } + if(isa.fp16 == false) + { + isa.fp16 = model_supports_fp16(model); + } + if(isa.sve == false) + { + isa.sve = model_supports_sve(model); + } +} +} // namespace + +CpuIsaInfo init_cpu_isa_from_hwcaps(uint32_t hwcaps, uint32_t hwcaps2, uint32_t midr) +{ + CpuIsaInfo isa; + + decode_hwcaps(isa, hwcaps, hwcaps2); + + const CpuModel model = midr_to_model(midr); + whitelisted_model_features(isa, model); + + return isa; +} + +CpuIsaInfo init_cpu_isa_from_regs(uint64_t isar0, uint64_t isar1, uint64_t pfr0, uint64_t svefr0, uint64_t midr) +{ + CpuIsaInfo isa; + + decode_regs(isa, isar0, isar1, pfr0, svefr0); + + const CpuModel model = midr_to_model(midr); + whitelisted_model_features(isa, model); + + return isa; +} +} // namespace cpuinfo +} // namespace arm_compute \ No newline at end of file diff --git a/src/common/cpuinfo/CpuIsaInfo.h b/src/common/cpuinfo/CpuIsaInfo.h new file mode 100644 index 0000000000..1125f766dd --- /dev/null +++ b/src/common/cpuinfo/CpuIsaInfo.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef SRC_COMMON_CPUINFO_CPUISAINFO_H +#define SRC_COMMON_CPUINFO_CPUISAINFO_H + +#include + +namespace arm_compute +{ +namespace cpuinfo +{ +/** CPU ISA (Instruction Set Architecture) information + * + * Contains ISA related information around the Arm architecture + */ +struct CpuIsaInfo +{ + /* SIMD extension support */ + bool neon{ false }; + bool sve{ false }; + bool sve2{ false }; + + /* Data-type extensions support */ + bool fp16{ false }; + bool bf16{ false }; + + /* Instruction support */ + bool dot{ false }; + bool immla{ false }; + bool fmmla{ false }; +}; + +/** Identify ISA related information through system information + * + * @param[in] hwcaps HWCAPS feature information + * @param[in] hwcaps2 HWCAPS2 feature information + * @param[in] midr MIDR value + * + * @return CpuIsaInfo A populated ISA feature structure + */ +CpuIsaInfo init_cpu_isa_from_hwcaps(uint32_t hwcaps, uint32_t hwcaps2, uint32_t midr); + +/** Identify ISA related information through register information + * + * @param[in] isar0 Value of Instruction Set Attribute Register 0 (ID_AA64ISAR0_EL1) + * @param[in] isar1 Value of Instruction Set Attribute Register 1 (ID_AA64ISAR1_EL1) + * @param[in] pfr0 Value of Processor Feature Register 0 (ID_AA64PFR0_EL1) + * @param[in] svefr0 Value of SVE feature ID register 0 (ID_AA64ZFR0_EL1) + * @param[in] midr Value of Main ID Register (MIDR) + * + * @return CpuIsaInfo A populated ISA feature structure + */ +CpuIsaInfo init_cpu_isa_from_regs(uint64_t isar0, uint64_t isar1, uint64_t pfr0, uint64_t svefr0, uint64_t midr); +} // namespace cpuinfo +} // namespace arm_compute + +#endif /* SRC_COMMON_CPUINFO_CPUISAINFO_H */ diff --git a/src/common/cpuinfo/CpuModel.cpp b/src/common/cpuinfo/CpuModel.cpp new file mode 100644 index 0000000000..9f4d5d1433 --- /dev/null +++ b/src/common/cpuinfo/CpuModel.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/common/cpuinfo/CpuModel.h" + +namespace arm_compute +{ +namespace cpuinfo +{ +std::string cpu_model_to_string(CpuModel model) +{ + switch(model) + { +#define X(MODEL) \ +case CpuModel::MODEL: \ + return #MODEL; + ARM_COMPUTE_CPU_MODEL_LIST +#undef X + default: + { + return std::string("GENERIC"); + } + }; +} + +bool model_supports_fp16(CpuModel model) +{ + switch(model) + { + case CpuModel::GENERIC_FP16: + case CpuModel::GENERIC_FP16_DOT: + case CpuModel::A55r1: + case CpuModel::X1: + case CpuModel::KLEIN: + return true; + default: + return false; + } +} + +bool model_supports_dot(CpuModel model) +{ + switch(model) + { + case CpuModel::GENERIC_FP16_DOT: + case CpuModel::A55r1: + case CpuModel::X1: + case CpuModel::KLEIN: + return true; + default: + return false; + } +} + +bool model_supports_sve(CpuModel model) +{ + switch(model) + { + case CpuModel::KLEIN: + return true; + default: + return false; + } +} + +CpuModel midr_to_model(uint32_t midr) +{ + CpuModel model = CpuModel::GENERIC; + + // Unpack variant and CPU ID + const int implementer = (midr >> 24) & 0xFF; + const int variant = (midr >> 20) & 0xF; + const int cpunum = (midr >> 4) & 0xFFF; + + if(implementer == 0x41) // Arm CPUs + { + // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" + switch(cpunum) + { + case 0xd03: // A53 + case 0xd04: // A35 + model = CpuModel::A53; + break; + case 0xd05: // A55 + if(variant != 0) + { + model = CpuModel::A55r1; + } + else + { + model = CpuModel::A55r0; + } + break; + case 0xd09: // A73 + model = CpuModel::A73; + break; + case 0xd0a: // A75 + if(variant != 0) + { + model = CpuModel::GENERIC_FP16_DOT; + } + else + { + model = CpuModel::GENERIC_FP16; + } + break; + case 0xd06: // A65 + case 0xd0b: // A76 + case 0xd0c: // N1 + case 0xd0d: // A77 + case 0xd0e: // A76AE + case 0xd41: // A78 + case 0xd42: // A78AE + case 0xd4a: // E1 + model = CpuModel::GENERIC_FP16_DOT; + break; + case 0xd44: // X1 + model = CpuModel::X1; + break; + case 0xd46: + model = CpuModel::KLEIN; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + else if(implementer == 0x48) + { + // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" + switch(cpunum) + { + case 0xd40: // A76 + model = CpuModel::GENERIC_FP16_DOT; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + else if(implementer == 0x51) + { + // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" + switch(cpunum) + { + case 0x800: // A73 + model = CpuModel::A73; + break; + case 0x801: // A53 + model = CpuModel::A53; + break; + case 0x803: // A55r0 + model = CpuModel::A55r0; + break; + case 0x804: // A76 + model = CpuModel::GENERIC_FP16_DOT; + break; + case 0x805: // A55r1 + model = CpuModel::A55r1; + break; + default: + model = CpuModel::GENERIC; + break; + } + } + + return model; +} +} // namespace cpuinfo +} // namespace arm_compute \ No newline at end of file diff --git a/src/common/cpuinfo/CpuModel.h b/src/common/cpuinfo/CpuModel.h new file mode 100644 index 0000000000..071efc4b3f --- /dev/null +++ b/src/common/cpuinfo/CpuModel.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef SRC_COMMON_CPUINFO_CPUMODEL_H +#define SRC_COMMON_CPUINFO_CPUMODEL_H + +#include +#include + +#include "arm_compute/core/CPP/CPPTypes.h" + +namespace arm_compute +{ +namespace cpuinfo +{ +using CpuModel = arm_compute::CPUModel; + +/** Convert a CPU model value to a string + * + * @param model CpuModel value to be converted + * + * @return String representing the corresponding CpuModel + */ +std::string cpu_model_to_string(CpuModel model); + +/** Extract the model type from the MIDR value + * + * @param[in] midr MIDR information + * + * @return CpuModel a mapped CPU model + */ +CpuModel midr_to_model(uint32_t midr); + +/** Check if a model supports half-precision floating point arithmetic + * + * @note This is used in case of old kernel configurations where some capabilities are not exposed. + * + * @param[in] model Model to check for whitelisted capabilities + */ +bool model_supports_fp16(CpuModel model); + +/** Check if a model supports SVE + * + * @note This is used in case of old kernel configurations where some capabilities are not exposed. + * + * @param[in] model Model to check for whitelisted capabilities + */ +bool model_supports_sve(CpuModel model); + +/** Check if a model supports dot product + * + * @note This is used in case of old kernel configurations where some capabilities are not exposed. + * + * @param[in] model Model to check for whitelisted capabilities + */ +bool model_supports_dot(CpuModel model); +} // namespace cpuinfo +} // namespace arm_compute +#endif /* SRC_COMMON_CPUINFO_CPUMODEL_H */ diff --git a/src/common/cpuinfo/target/CpuInfoSveUtils.cpp b/src/common/cpuinfo/target/CpuInfoSveUtils.cpp new file mode 100644 index 0000000000..750a1b01d1 --- /dev/null +++ b/src/common/cpuinfo/target/CpuInfoSveUtils.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "src/common/cpuinfo/target/CpuInfoSveUtils.h" + +namespace arm_compute +{ +namespace cpuinfo +{ +uint64_t get_sve_feature_reg() +{ + uint64_t reg = 0; +#if defined(ENABLE_SVE) + __asm __volatile("MRS %0, ID_AA64ZFR0_EL1" + : "=r"(reg)); +#endif /* defined(DENABLE_SVE) */ + return reg; +} +} // namespace cpuinfo +} // namespace arm_compute diff --git a/src/common/cpuinfo/target/CpuInfoSveUtils.h b/src/common/cpuinfo/target/CpuInfoSveUtils.h new file mode 100644 index 0000000000..73862b131c --- /dev/null +++ b/src/common/cpuinfo/target/CpuInfoSveUtils.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Arm Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef SRC_COMMON_CPUINFO_TARGET_CPUINFO_SVE_UTILS_H +#define SRC_COMMON_CPUINFO_TARGET_CPUINFO_SVE_UTILS_H + +#include + +namespace arm_compute +{ +namespace cpuinfo +{ +/** Returns the contents of the SVE feature register (ID_AA64ZFR0_EL1) + * + * @return uint64_t The value of the register + */ +uint64_t get_sve_feature_reg(); +} // namespace cpuinfo +} // namespace arm_compute +#endif /* SRC_COMMON_CPUINFO_CPUISAINFO_H */ diff --git a/src/core/CPP/CPPTypes.cpp b/src/core/CPP/CPPTypes.cpp index 0850df29fd..edcb9cb1ba 100644 --- a/src/core/CPP/CPPTypes.cpp +++ b/src/core/CPP/CPPTypes.cpp @@ -25,105 +25,67 @@ #include "arm_compute/core/CPP/CPPTypes.h" #include "arm_compute/core/Error.h" +#include "src/common/cpuinfo/CpuInfo.h" -#if !defined(BARE_METAL) -#include -#endif /* defined(BARE_METAL) */ - -using namespace arm_compute; - -void CPUInfo::set_fp16(const bool fp16) +namespace arm_compute { - _fp16 = fp16; -} - -void CPUInfo::set_dotprod(const bool dotprod) +struct CPUInfo::Impl { - _dotprod = dotprod; -} + cpuinfo::CpuInfo info{}; + unsigned int L1_cache_size = 32768; + unsigned int L2_cache_size = 262144; +}; -void CPUInfo::set_sve(const bool sve) +CPUInfo::CPUInfo() + : _impl(std::make_unique()) { - _sve = sve; + _impl->info = cpuinfo::CpuInfo::build(); } -void CPUInfo::set_cpu_model(unsigned int cpuid, CPUModel model) -{ - ARM_COMPUTE_ERROR_ON(cpuid >= _percpu.size()); - if(_percpu.size() > cpuid) - { - _percpu[cpuid] = model; - } -} +CPUInfo::~CPUInfo() = default; unsigned int CPUInfo::get_cpu_num() const { - return _percpu.size(); + return _impl->info.num_cpus(); } bool CPUInfo::has_sve() const { - return _sve; + return _impl->info.has_sve(); } bool CPUInfo::has_fp16() const { - return _fp16; -} - -bool CPUInfo::has_dotprod() const -{ - return _dotprod; -} - -CPUModel CPUInfo::get_cpu_model(unsigned int cpuid) const -{ - if(cpuid < _percpu.size()) - { - return _percpu[cpuid]; - } - return CPUModel::GENERIC; + return _impl->info.has_fp16(); } -unsigned int CPUInfo::get_L1_cache_size() const +bool CPUInfo::has_bf16() const { - return _L1_cache_size; + return _impl->info.has_bf16(); } -void CPUInfo::set_L1_cache_size(unsigned int size) -{ - _L1_cache_size = size; -} - -unsigned int CPUInfo::get_L2_cache_size() const +bool CPUInfo::has_dotprod() const { - return _L2_cache_size; + return _impl->info.has_dotprod(); } -void CPUInfo::set_L2_cache_size(unsigned int size) +CPUModel CPUInfo::get_cpu_model() const { - _L2_cache_size = size; + return _impl->info.cpu_model(); } -void CPUInfo::set_cpu_num(unsigned int cpu_count) +CPUModel CPUInfo::get_cpu_model(unsigned int cpuid) const { - _percpu.resize(cpu_count); + return _impl->info.cpu_model(cpuid); } -CPUInfo::CPUInfo() - : _percpu(1) +unsigned int CPUInfo::get_L1_cache_size() const { - // The core library knows nothing about the CPUs so we set only 1 CPU to be generic. - // The runtime NESCheduler will initialise this vector with the correct CPU models. - // See void detect_cpus_configuration(CPUInfo &cpuinfo) in CPPUtils.h - _percpu[0] = CPUModel::GENERIC; + return _impl->L1_cache_size; } -CPUModel CPUInfo::get_cpu_model() const +unsigned int CPUInfo::get_L2_cache_size() const { -#if defined(BARE_METAL) || defined(__APPLE__) || (!defined(__arm__) && !defined(__aarch64__)) - return get_cpu_model(0); -#else /* defined(BARE_METAL) || defined(__APPLE__) || (!defined(__arm__) && !defined(__aarch64__)) */ - return get_cpu_model(sched_getcpu()); -#endif /* defined(BARE_METAL) || defined(__APPLE__) || (!defined(__arm__) && !defined(__aarch64__)) */ + return _impl->L2_cache_size; } +} // namespace arm_compute diff --git a/src/core/cpu/kernels/assembly/arm_gemm.hpp b/src/core/cpu/kernels/assembly/arm_gemm.hpp index 624e9e94dc..81e355d6b3 100644 --- a/src/core/cpu/kernels/assembly/arm_gemm.hpp +++ b/src/core/cpu/kernels/assembly/arm_gemm.hpp @@ -25,6 +25,7 @@ #include #include +#include #include "arm_gemm_local.hpp" #include "gemm_common.hpp" diff --git a/src/cpu/CpuContext.cpp b/src/cpu/CpuContext.cpp index b9a6999f84..18fa2e7469 100644 --- a/src/cpu/CpuContext.cpp +++ b/src/cpu/CpuContext.cpp @@ -26,7 +26,6 @@ #include "arm_compute/core/CPP/CPPTypes.h" #include "src/cpu/CpuQueue.h" #include "src/cpu/CpuTensor.h" -#include "src/runtime/CPUUtils.h" #include #include @@ -142,7 +141,6 @@ CpuCapabilities populate_capabilities(AclTargetCapabilities external_caps, { // Extract legacy structure CPUInfo cpu_info; - arm_compute::utils::cpu::get_cpu_configuration(cpu_info); CpuCapabilities caps; if(external_caps != AclCpuCapabilitiesAuto) diff --git a/src/runtime/CPP/CPPScheduler.cpp b/src/runtime/CPP/CPPScheduler.cpp index 3bd80eb51d..f112d456c7 100644 --- a/src/runtime/CPP/CPPScheduler.cpp +++ b/src/runtime/CPP/CPPScheduler.cpp @@ -29,7 +29,6 @@ #include "arm_compute/core/Log.h" #include "arm_compute/core/Utils.h" #include "arm_compute/core/utils/misc/Utility.h" -#include "src/runtime/CPUUtils.h" #include "support/Mutex.h" #include diff --git a/src/runtime/CPUUtils.cpp b/src/runtime/CPUUtils.cpp deleted file mode 100644 index 2bcba72f77..0000000000 --- a/src/runtime/CPUUtils.cpp +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (c) 2018-2021 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "src/runtime/CPUUtils.h" - -#include "arm_compute/core/CPP/CPPTypes.h" -#include "arm_compute/core/Error.h" -#include "arm_compute/core/Log.h" -#include "support/StringSupport.h" - -#include -#include -#include -#include -#include -#include - -#if !defined(BARE_METAL) -/* C++ std::regex takes up a lot of space in the standalone builds */ -#include -#include -#endif /* !defined(BARE_METAL) */ - -#if !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) -#include - -/* Get HWCAP bits from asm/hwcap.h */ -#include -#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ - -/* Make sure the bits we care about are defined, just in case asm/hwcap.h is - * out of date (or for bare metal mode) */ -#ifndef HWCAP_ASIMDHP -#define HWCAP_ASIMDHP (1 << 10) // NOLINT -#endif /* HWCAP_ASIMDHP */ - -#ifndef HWCAP_CPUID -#define HWCAP_CPUID (1 << 11) // NOLINT -#endif /* HWCAP_CPUID */ - -#ifndef HWCAP_ASIMDDP -#define HWCAP_ASIMDDP (1 << 20) // NOLINT -#endif /* HWCAP_ASIMDDP */ - -#ifndef HWCAP_SVE -#define HWCAP_SVE (1 << 22) // NOLINT -#endif /* HWCAP_SVE */ - -namespace -{ -using namespace arm_compute; - -#if !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) - -bool model_supports_sve(CPUModel model) -{ - switch(model) - { - case CPUModel::KLEIN: - return true; - default: - return false; - } -} - -bool model_supports_dot(CPUModel model) -{ - switch(model) - { - case CPUModel::GENERIC_FP16_DOT: - case CPUModel::A55r1: - case CPUModel::X1: - case CPUModel::KLEIN: - return true; - default: - return false; - } -} - -bool model_supports_fp16(CPUModel model) -{ - switch(model) - { - case CPUModel::GENERIC_FP16: - case CPUModel::GENERIC_FP16_DOT: - case CPUModel::A55r1: - case CPUModel::X1: - case CPUModel::KLEIN: - return true; - default: - return false; - } -} - -/* Convert an MIDR register value to a CPUModel enum value. */ -CPUModel midr_to_model(const unsigned int midr) -{ - CPUModel model = CPUModel::GENERIC; - - // Unpack variant and CPU ID - const int implementer = (midr >> 24) & 0xFF; - const int variant = (midr >> 20) & 0xF; - const int cpunum = (midr >> 4) & 0xFFF; - - if(implementer == 0x41) // Arm CPUs - { - // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" - switch(cpunum) - { - case 0xd03: // A53 - case 0xd04: // A35 - model = CPUModel::A53; - break; - case 0xd05: // A55 - if(variant != 0) - { - model = CPUModel::A55r1; - } - else - { - model = CPUModel::A55r0; - } - break; - case 0xd09: // A73 - model = CPUModel::A73; - break; - case 0xd0a: // A75 - if(variant != 0) - { - model = CPUModel::GENERIC_FP16_DOT; - } - else - { - model = CPUModel::GENERIC_FP16; - } - break; - case 0xd06: // A65 - case 0xd0b: // A76 - case 0xd0c: // N1 - case 0xd0d: // A77 - case 0xd41: // A78 - model = CPUModel::GENERIC_FP16_DOT; - break; - case 0xd44: // X1 - model = CPUModel::X1; - break; - case 0xd46: - model = CPUModel::KLEIN; - break; - default: - model = CPUModel::GENERIC; - break; - } - } - else if(implementer == 0x48) - { - // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" - switch(cpunum) - { - case 0xd40: // A76 - model = CPUModel::GENERIC_FP16_DOT; - break; - default: - model = CPUModel::GENERIC; - break; - } - } - else if(implementer == 0x51) - { - // Only CPUs we have code paths for are detected. All other CPUs can be safely classed as "GENERIC" - switch(cpunum) - { - case 0x800: // A73 - model = CPUModel::A73; - break; - case 0x801: // A53 - model = CPUModel::A53; - break; - case 0x803: // A55r0 - model = CPUModel::A55r0; - break; - case 0x804: // A76 - model = CPUModel::GENERIC_FP16_DOT; - break; - case 0x805: // A55r1 - model = CPUModel::A55r1; - break; - default: - model = CPUModel::GENERIC; - break; - } - } - - return model; -} - -void populate_models_cpuid(std::vector &cpusv) -{ - // If the CPUID capability is present, MIDR information is provided in /sys. Use that to populate the CPU model table. - uint32_t i = 0; - for(auto &c : cpusv) - { - std::stringstream str; - str << "/sys/devices/system/cpu/cpu" << i++ << "/regs/identification/midr_el1"; - std::ifstream file; - file.open(str.str(), std::ios::in); - if(file.is_open()) - { - std::string line; - if(bool(getline(file, line))) - { - const uint32_t midr = support::cpp11::stoul(line, nullptr, support::cpp11::NumericBase::BASE_16); - c = midr_to_model(midr & 0xffffffff); - } - } - } -} - -void populate_models_cpuinfo(std::vector &cpusv) -{ - regex_t proc_regex; - regex_t imp_regex; - regex_t var_regex; - regex_t part_regex; - regex_t rev_regex; - - memset(&proc_regex, 0, sizeof(regex_t)); - memset(&imp_regex, 0, sizeof(regex_t)); - memset(&var_regex, 0, sizeof(regex_t)); - memset(&part_regex, 0, sizeof(regex_t)); - memset(&rev_regex, 0, sizeof(regex_t)); - - int ret_status = 0; - // If "long-form" cpuinfo is present, parse that to populate models. - ret_status |= regcomp(&proc_regex, R"(^processor.*([[:digit:]]+)$)", REG_EXTENDED); - ret_status |= regcomp(&imp_regex, R"(^CPU implementer.*0x(..)$)", REG_EXTENDED); - ret_status |= regcomp(&var_regex, R"(^CPU variant.*0x(.)$)", REG_EXTENDED); - ret_status |= regcomp(&part_regex, R"(^CPU part.*0x(...)$)", REG_EXTENDED); - ret_status |= regcomp(&rev_regex, R"(^CPU revision.*([[:digit:]]+)$)", REG_EXTENDED); - ARM_COMPUTE_UNUSED(ret_status); - ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); - - std::ifstream file; - file.open("/proc/cpuinfo", std::ios::in); - - if(file.is_open()) - { - std::string line; - int midr = 0; - int curcpu = -1; - const int num_cpus = static_cast(cpusv.size()); - - while(bool(getline(file, line))) - { - std::array match; - ret_status = regexec(&proc_regex, line.c_str(), 2, match.data(), 0); - if(ret_status == 0) - { - std::string id = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); - int newcpu = support::cpp11::stoi(id, nullptr); - - if(curcpu >= 0 && midr == 0) - { - // Matched a new CPU ID without any description of the previous one - looks like old format. - return; - } - - if(curcpu >= 0 && curcpu < num_cpus) - { - cpusv[curcpu] = midr_to_model(midr); - } - else - { - ARM_COMPUTE_LOG_INFO_MSG_CORE("Trying to populate a core id with id greater than the expected number of cores!"); - } - - midr = 0; - curcpu = newcpu; - - continue; - } - - ret_status = regexec(&imp_regex, line.c_str(), 2, match.data(), 0); - if(ret_status == 0) - { - std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); - int impv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); - midr |= (impv << 24); - - continue; - } - - ret_status = regexec(&var_regex, line.c_str(), 2, match.data(), 0); - if(ret_status == 0) - { - std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); - int varv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); - midr |= (varv << 20); - - continue; - } - - ret_status = regexec(&part_regex, line.c_str(), 2, match.data(), 0); - if(ret_status == 0) - { - std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); - int partv = support::cpp11::stoi(subexp, nullptr, support::cpp11::NumericBase::BASE_16); - midr |= (partv << 4); - - continue; - } - - ret_status = regexec(&rev_regex, line.c_str(), 2, match.data(), 0); - if(ret_status == 0) - { - std::string subexp = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); - int regv = support::cpp11::stoi(subexp, nullptr); - midr |= (regv); - midr |= (0xf << 16); - - continue; - } - } - - if(curcpu >= 0 && curcpu < num_cpus) - { - cpusv[curcpu] = midr_to_model(midr); - } - else - { - ARM_COMPUTE_LOG_INFO_MSG_CORE("Trying to populate a core id with id greater than the expected number of cores!"); - } - } - - // Free allocated memory - regfree(&proc_regex); - regfree(&imp_regex); - regfree(&var_regex); - regfree(&part_regex); - regfree(&rev_regex); -} - -int get_max_cpus() -{ - int max_cpus = 1; - std::ifstream CPUspresent; - CPUspresent.open("/sys/devices/system/cpu/present", std::ios::in); - bool success = false; - - if(CPUspresent.is_open()) - { - std::string line; - - if(bool(getline(CPUspresent, line))) - { - /* The content of this file is a list of ranges or single values, e.g. - * 0-5, or 1-3,5,7 or similar. As we are interested in the - * max valid ID, we just need to find the last valid - * delimiter ('-' or ',') and parse the integer immediately after that. - */ - auto startfrom = line.begin(); - - for(auto i = line.begin(); i < line.end(); ++i) - { - if(*i == '-' || *i == ',') - { - startfrom = i + 1; - } - } - - line.erase(line.begin(), startfrom); - - max_cpus = support::cpp11::stoi(line, nullptr) + 1; - success = true; - } - } - - // Return std::thread::hardware_concurrency() as a fallback. - if(!success) - { - max_cpus = std::thread::hardware_concurrency(); - } - return max_cpus; -} -#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ - -} // namespace - -namespace arm_compute -{ -namespace utils -{ -namespace cpu -{ -void get_cpu_configuration(CPUInfo &cpuinfo) -{ -#if !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) - bool cpuid = false; - bool hwcaps_fp16_support = false; - bool hwcaps_dot_support = false; - bool hwcaps_sve = false; - const uint32_t hwcaps = getauxval(AT_HWCAP); - - if((hwcaps & HWCAP_CPUID) != 0) - { - cpuid = true; - } - - if((hwcaps & HWCAP_ASIMDHP) != 0) - { - hwcaps_fp16_support = true; - } - -#if defined(__aarch64__) - if((hwcaps & HWCAP_ASIMDDP) != 0) - { - hwcaps_dot_support = true; - } - - if((hwcaps & HWCAP_SVE) != 0) - { - hwcaps_sve = true; - } -#endif /* defined(__aarch64__) */ - - const unsigned int max_cpus = get_max_cpus(); - cpuinfo.set_cpu_num(max_cpus); - std::vector percpu(max_cpus, CPUModel::GENERIC); - if(cpuid) - { - populate_models_cpuid(percpu); - } - else - { - populate_models_cpuinfo(percpu); - } - int j(0); - // Update dot product and FP16 support if one of the CPUs support these features - // We assume that the system does not have mixed architectures - bool one_supports_dot = false; - bool one_supports_fp16 = false; - bool one_supports_sve = false; - for(const auto &v : percpu) - { - one_supports_dot = one_supports_dot || model_supports_dot(v); - one_supports_fp16 = one_supports_fp16 || model_supports_fp16(v); - one_supports_sve = one_supports_sve || model_supports_sve(v); - cpuinfo.set_cpu_model(j++, v); - } - cpuinfo.set_dotprod(one_supports_dot || hwcaps_dot_support); - cpuinfo.set_fp16(one_supports_fp16 || hwcaps_fp16_support); - cpuinfo.set_sve(one_supports_sve || hwcaps_sve); -#elif(BARE_METAL) && defined(__aarch64__) /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ - cpuinfo.set_cpu_num(1); - const CPUModel cpumodel{ CPUModel::GENERIC }; - cpuinfo.set_cpu_model(0, cpumodel); - // Assume single CPU in bare metal mode. Just read the ID register and feature bits directly. - uint64_t fr0, pfr0, midr; - __asm __volatile( - "MRS %0, ID_AA64ISAR0_EL1\n" - "MRS %1, ID_AA64PFR0_EL1\n" - "MRS %2, midr_el1" - : "=r"(fr0), "=r"(pfr0), "=r"(midr)); - if((fr0 >> 44) & 0xf) - { - cpuinfo.set_dotprod(true); - } - if((pfr0 >> 16) & 0xf) - { - cpuinfo.set_fp16(true); - } - if((pfr0 >> 32) & 0xf) - { - cpuinfo.set_sve(true); - } -#else /* #elif(BARE_METAL) && defined(__aarch64__) */ - ARM_COMPUTE_UNUSED(cpuinfo); -#endif /* !defined(BARE_METAL) && !defined(__APPLE__) && (defined(__arm__) || defined(__aarch64__)) */ -} - -unsigned int get_threads_hint() -{ - unsigned int num_threads_hint = 1; - -#if !defined(BARE_METAL) - std::map cpu_part_occurrence_map; - - // CPU part regex - regex_t cpu_part_rgx; - memset(&cpu_part_rgx, 0, sizeof(regex_t)); - int ret_status = regcomp(&cpu_part_rgx, R"(.*CPU part.+/?\:[[:space:]]+([[:alnum:]]+).*)", REG_EXTENDED); - ARM_COMPUTE_UNUSED(ret_status); - ARM_COMPUTE_ERROR_ON_MSG(ret_status != 0, "Regex compilation failed."); - - // Read cpuinfo and get occurrence of each core - std::ifstream cpuinfo; - cpuinfo.open("/proc/cpuinfo", std::ios::in); - if(cpuinfo.is_open()) - { - std::string line; - while(bool(getline(cpuinfo, line))) - { - std::array match; - ret_status = regexec(&cpu_part_rgx, line.c_str(), 2, match.data(), 0); - if(ret_status == 0) - { - std::string cpu_part = line.substr(match[1].rm_so, (match[1].rm_eo - match[1].rm_so)); - if(cpu_part_occurrence_map.find(cpu_part) != cpu_part_occurrence_map.end()) - { - cpu_part_occurrence_map[cpu_part]++; - } - else - { - cpu_part_occurrence_map[cpu_part] = 1; - } - } - } - } - regfree(&cpu_part_rgx); - - // Get min number of threads - auto min_common_cores = std::min_element(cpu_part_occurrence_map.begin(), cpu_part_occurrence_map.end(), - [](const std::pair &p1, const std::pair &p2) - { - return p1.second < p2.second; - }); - - // Set thread hint - num_threads_hint = cpu_part_occurrence_map.empty() ? std::thread::hardware_concurrency() : min_common_cores->second; -#endif /* !defined(BARE_METAL) */ - - return num_threads_hint; -} -} // namespace cpu -} // namespace utils -} // namespace arm_compute diff --git a/src/runtime/CPUUtils.h b/src/runtime/CPUUtils.h deleted file mode 100644 index 452d3d58ca..0000000000 --- a/src/runtime/CPUUtils.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2018-2020 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef ARM_COMPUTE_RUNTIME_CPU_UTILS_H -#define ARM_COMPUTE_RUNTIME_CPU_UTILS_H - -namespace arm_compute -{ -class CPUInfo; - -namespace utils -{ -namespace cpu -{ -/** This function will try to detect the CPU configuration on the system and will fill - * the cpuinfo object accordingly to reflect this. - * - * @param[out] cpuinfo @ref CPUInfo to be used to hold the system's cpu configuration. - */ -void get_cpu_configuration(CPUInfo &cpuinfo); -/** Some systems have both big and small cores, this fuction computes the minimum number of cores - * that are exactly the same on the system. To maximize performance the library attempts to process - * workloads concurrently using as many threads as big cores are available on the system. - * - * @return The minumum number of common cores. - */ -unsigned int get_threads_hint(); -} // namespace cpu -} // namespace utils -} // namespace arm_compute -#endif /* ARM_COMPUTE_RUNTIME_CPU_UTILS_H */ diff --git a/src/runtime/DeviceProperties.cpp b/src/runtime/DeviceProperties.cpp deleted file mode 100644 index ec9f4a16ed..0000000000 --- a/src/runtime/DeviceProperties.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2019-2020 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "arm_compute/runtime/DeviceProperties.h" - -#include "src/runtime/CPUUtils.h" - -namespace arm_compute -{ -DeviceProperties::DeviceProperties() -{ - utils::cpu::get_cpu_configuration(cpu_info); -} -} // namespace arm_compute diff --git a/src/runtime/IScheduler.cpp b/src/runtime/IScheduler.cpp index eae34b98eb..df04fed401 100644 --- a/src/runtime/IScheduler.cpp +++ b/src/runtime/IScheduler.cpp @@ -26,7 +26,7 @@ #include "arm_compute/core/CPP/ICPPKernel.h" #include "arm_compute/core/Error.h" #include "arm_compute/core/Window.h" -#include "src/runtime/CPUUtils.h" +#include "src/common/cpuinfo/CpuInfo.h" #include "src/runtime/SchedulerUtils.h" namespace arm_compute @@ -34,9 +34,8 @@ namespace arm_compute IScheduler::IScheduler() : _cpu_info() { - utils::cpu::get_cpu_configuration(_cpu_info); // Work out the best possible number of execution threads - _num_threads_hint = utils::cpu::get_threads_hint(); + _num_threads_hint = cpuinfo::num_threads_hint(); } CPUInfo &IScheduler::cpu_info() diff --git a/src/runtime/MEMUtils.cpp b/src/runtime/MEMUtils.cpp deleted file mode 100644 index 8b39a0f3f4..0000000000 --- a/src/runtime/MEMUtils.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2018-2020 Arm Limited. - * - * SPDX-License-Identifier: MIT - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "arm_compute/core/CPP/CPPTypes.h" -#include "arm_compute/core/Error.h" -#include "support/StringSupport.h" - -#ifndef BARE_METAL -#include -#include -#include -#endif // ifndef BARE_METAL - -namespace -{ -void parse_mem_info(size_t &total, size_t &free, size_t &buffer) -{ - free = 0; - total = 0; - buffer = 0; -#ifndef BARE_METAL - size_t memcache = 0; - size_t memfree = 0; - std::ifstream meminfo_f; - meminfo_f.open("/proc/meminfo", std::ios::in); - - if(meminfo_f.is_open()) - { - std::string line; - while(bool(getline(meminfo_f, line))) - { - std::istringstream iss(line); - std::vector tokens((std::istream_iterator(iss)), - std::istream_iterator()); - if(tokens[0] == "MemTotal:") - { - total = arm_compute::support::cpp11::stoul(tokens[1], nullptr); - } - else if(tokens[0] == "MemFree:") - { - memfree = arm_compute::support::cpp11::stoul(tokens[1], nullptr); - } - else if(tokens[0] == "Buffers:") - { - buffer = arm_compute::support::cpp11::stoul(tokens[1], nullptr); - } - else if(tokens[0] == "Cached:") - { - memcache = arm_compute::support::cpp11::stoul(tokens[1], nullptr); - } - } - free = memfree + (buffer + memcache); - } -#endif // ifndef BARE_METAL -} - -} // namespace - -namespace arm_compute -{ -void MEMInfo::set_policy(MemoryPolicy policy) -{ - _policy = policy; -} - -MemoryPolicy MEMInfo::get_policy() -{ - return _policy; -} -MemoryPolicy MEMInfo::_policy = { MemoryPolicy::NORMAL }; - -MEMInfo::MEMInfo() - : _total(0), _free(0), _buffer(0) -{ - parse_mem_info(_total, _free, _buffer); -} - -size_t MEMInfo::get_total_in_kb() const -{ - return _total; -} - -} // namespace arm_compute diff --git a/src/runtime/OMP/OMPScheduler.cpp b/src/runtime/OMP/OMPScheduler.cpp index a8bd5a0d60..ca763f907b 100644 --- a/src/runtime/OMP/OMPScheduler.cpp +++ b/src/runtime/OMP/OMPScheduler.cpp @@ -27,7 +27,6 @@ #include "arm_compute/core/Error.h" #include "arm_compute/core/Helpers.h" #include "arm_compute/core/Utils.h" -#include "src/runtime/CPUUtils.h" #include namespace arm_compute diff --git a/src/runtime/RuntimeContext.cpp b/src/runtime/RuntimeContext.cpp index 504a74c949..d1dea066e7 100644 --- a/src/runtime/RuntimeContext.cpp +++ b/src/runtime/RuntimeContext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Arm Limited. + * Copyright (c) 2019, 2021 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -29,7 +29,7 @@ namespace arm_compute { RuntimeContext::RuntimeContext() - : _owned_scheduler(SchedulerFactory::create()), _scheduler(_owned_scheduler.get()), _device_props() + : _owned_scheduler(SchedulerFactory::create()), _scheduler(_owned_scheduler.get()) { } @@ -48,9 +48,4 @@ IAssetManager *RuntimeContext::asset_manager() { return nullptr; } - -const DeviceProperties &RuntimeContext::properties() -{ - return _device_props; -} } // namespace arm_compute -- cgit v1.2.1