1 /**
2 * Copyright 2021 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifdef ENABLE_ARM
17 #include "src/litert/cpu_info.h"
18 #include <set>
19 #include <fstream>
20 #include "src/common/log_adapter.h"
21 #include "nnacl/nnacl_utils.h"
22 #if defined(__ANDROID__) || defined(MS_COMPILE_OHOS) && !defined(SUPPORT_NNIE) && !defined(MS_COMPILE_IOS)
23 #include <sys/auxv.h>
24 #include <asm/hwcap.h>
25 #endif
26 #ifdef MS_COMPILE_IOS
27 #include <mach/mach.h>
28 #include <mach/machine.h>
29 #include <mach/thread_act.h>
30 #include <sys/sysctl.h>
31 #include <sys/types.h>
32 #include "TargetConditionals.h"
33 // define missing cpu model for old sdk
34 #ifndef CPUFAMILY_ARM_HURRICANE
35 #define CPUFAMILY_ARM_HURRICANE 0x67ceee93
36 #endif
37 // A11
38 #ifndef CPUFAMILY_ARM_MONSOON_MISTRAL
39 #define CPUFAMILY_ARM_MONSOON_MISTRAL 0xe81e7ef6
40 #endif
41 // A12
42 #ifndef CPUFAMILY_ARM_VORTEX_TEMPEST
43 #define CPUFAMILY_ARM_VORTEX_TEMPEST 0x07d34b9f
44 #endif
45 // A13
46 #ifndef CPUFAMILY_ARM_LIGHTNING_THUNDER
47 #define CPUFAMILY_ARM_LIGHTNING_THUNDER 0x462504d2
48 #endif
49 // A14
50 #ifndef CPUFAMILY_ARM_FIRESTORM_ICESTORM
51 #define CPUFAMILY_ARM_FIRESTORM_ICESTORM 0x1b588bb3
52 #endif
53 // A15
54 #ifndef CPUFAMILY_ARM_AVALANCHE_BLIZZARD
55 #define CPUFAMILY_ARM_AVALANCHE_BLIZZARD 0xda33d83d
56 #endif
57 #endif
58 namespace mindspore::lite {
59 #if defined(__ANDROID__) || defined(MS_COMPILE_OHOS)
MidrSetPart(uint32_t part)60 uint32_t CpuInfo::MidrSetPart(uint32_t part) {
61 return ((part << ARM_CPU_PART_OFFSET) & ARM_CPU_PART_MASK) | (midr_ & ~ARM_CPU_PART_MASK);
62 }
63
MidrSetImplementer(uint32_t implementer)64 uint32_t CpuInfo::MidrSetImplementer(uint32_t implementer) {
65 return ((implementer << ARM_CPU_IMPLEMENTER_OFFSET) & ARM_CPU_IMPLEMENTER_MASK) | (midr_ & ~ARM_CPU_IMPLEMENTER_MASK);
66 }
67
StringToDigit(const std::string & str)68 uint32_t CpuInfo::StringToDigit(const std::string &str) {
69 // hex string to digit
70 constexpr size_t base_16 = 16;
71 constexpr size_t base_10 = 10;
72 // verify hex prefix '0' and 'x'
73 if (str[0] != '0' || str[1] != 'x') {
74 return 0;
75 }
76 auto str_length = str.length();
77 uint32_t str_digit = 0;
78 for (unsigned int i = 2; i < str_length; ++i) {
79 auto tmp_char = str[i];
80 uint32_t digit;
81 if (tmp_char >= '0' && tmp_char <= '9') {
82 digit = tmp_char - '0';
83 } else if ((uint32_t)(tmp_char - 'A') < 6) {
84 digit = base_10 + (tmp_char - 'A');
85 } else if ((uint32_t)(tmp_char - 'a') < 6) {
86 digit = base_10 + (tmp_char - 'a');
87 } else {
88 return 0;
89 }
90 str_digit = str_digit * base_16 + digit;
91 }
92 return str_digit;
93 }
94
ParseArmCpuPart(const std::string & cpu_part)95 uint32_t CpuInfo::ParseArmCpuPart(const std::string &cpu_part) {
96 // cpu_part string length is in [3, 5]
97 constexpr size_t cpu_part_min_len = 3;
98 constexpr size_t cpu_part_max_len = 5;
99 auto cpu_part_length = cpu_part.length();
100 if (cpu_part_length < cpu_part_min_len || cpu_part_length > cpu_part_max_len) {
101 return 0;
102 }
103 return StringToDigit(cpu_part);
104 }
105
ParseArmCpuImplementer(const std::string & str)106 uint32_t CpuInfo::ParseArmCpuImplementer(const std::string &str) {
107 auto str_length = str.length();
108 switch (str_length) {
109 case 3:
110 case 4:
111 break;
112 default:
113 return 0;
114 }
115 return StringToDigit(str);
116 }
117
GetArmProcCpuInfo(AndroidCpuInfo * android_cpu_info)118 void CpuInfo::GetArmProcCpuInfo(AndroidCpuInfo *android_cpu_info) {
119 // only get cpu part, implementer and hardware
120 std::ifstream infile("/proc/cpuinfo", std::ios::in);
121 std::string line;
122 while (getline(infile, line)) {
123 for (unsigned int i = 0; i < line.length(); ++i) {
124 if (line[i] == ':') {
125 std::string prefix = line.substr(0, i);
126 prefix.erase(0, prefix.find_first_not_of(' '));
127 prefix.erase(prefix.find_last_not_of('\t') + 1);
128 std::string suffix = line.substr(i + 2);
129 if (prefix == "CPU implementer" && android_cpu_info->cpu_implementer == 0) {
130 android_cpu_info->cpu_implementer = ParseArmCpuImplementer(suffix);
131 } else if (prefix == "CPU part" && android_cpu_info->cpu_part == 0) {
132 android_cpu_info->cpu_part = ParseArmCpuPart(suffix);
133 } else if (prefix == "Hardware" && android_cpu_info->hardware.empty()) {
134 android_cpu_info->hardware = suffix;
135 }
136 }
137 }
138 }
139 infile.close();
140 }
141 #endif
142
ArmIsSupportFp16()143 bool CpuInfo::ArmIsSupportFp16() {
144 #ifdef MS_COMPILE_IOS
145 unsigned int value = 0;
146 size_t len = sizeof(value);
147 sysctlbyname("hw.cpufamily", &value, &len, NULL, 0);
148 if (value == CPUFAMILY_ARM_MONSOON_MISTRAL || value == CPUFAMILY_ARM_VORTEX_TEMPEST ||
149 value == CPUFAMILY_ARM_LIGHTNING_THUNDER || value == CPUFAMILY_ARM_FIRESTORM_ICESTORM ||
150 CPUFAMILY_ARM_AVALANCHE_BLIZZARD) {
151 return true;
152 }
153 return false;
154 #else
155 #if defined(__ANDROID__) || defined(MS_COMPILE_OHOS)
156 #ifdef ENABLE_ARM32
157 GetArmProcCpuInfo(&android_cpu_info_);
158 midr_ = MidrSetPart(android_cpu_info_.cpu_part);
159 midr_ = MidrSetImplementer(android_cpu_info_.cpu_implementer);
160 midr_ = (ARM_CPU_IMPLEMENTER_MASK | ARM_CPU_PART_MASK) & midr_;
161 std::set<uint32_t> cpu_list_support_fp16 = {
162 UINT32_C(0x4800D400), // Cortex-A76 in HiSilicon Cpu
163 UINT32_C(0x4100D050), // Arm Cortex-A55
164 UINT32_C(0x4100D060), // Arm Cortex-A65
165 UINT32_C(0x4100D0B0), // Arm Cortex-A76
166 UINT32_C(0x4100D0E0), // Arm Cortex-A76-AE
167 UINT32_C(0x4100D0D0), // Arm Cortex-A77
168 UINT32_C(0x4100D0C0), // Neoverse-N1 Cpu
169 UINT32_C(0x53000030), // Exynos-M4 Cpu
170 UINT32_C(0x53000040), // Exynos-M5 Cpu
171 UINT32_C(0x51008050), // Cortex-A55 in Kryo-485-Silver
172 UINT32_C(0x51008040), // Cortex-A76 in Kryo-485-Gold
173 UINT32_C(0x51008030), // Cortex-A55 in Kryo-385-Silver
174 UINT32_C(0x51008020) // Cortex-A75 in Kryo-385-Gold
175 };
176 if (cpu_list_support_fp16.find(midr_) != cpu_list_support_fp16.end()) {
177 fp16_flag_ = true;
178 }
179 #ifdef Debug
180 if (!fp16_flag_) {
181 MS_LOG(DEBUG) << "cpu midr_:" << midr_ << "is not support fp16!";
182 }
183 #endif
184 #elif defined(ENABLE_ARM64)
185 int hwcap_type = 16;
186 uint32_t hwcap = getHwCap(hwcap_type);
187 if (hwcap & HWCAP_FPHP) {
188 MS_LOG(DEBUG) << "Hw cap support FP16, hwcap: 0x" << hwcap;
189 fp16_flag_ = true;
190 } else {
191 MS_LOG(DEBUG) << "Hw cap NOT support FP16, hwcap: 0x" << hwcap;
192 }
193 #endif
194 #elif defined(ENABLE_ARM64) && defined(MACHINE_LINUX_ARM64)
195 const uint32_t hwcap = getauxval(AT_HWCAP);
196 if (hwcap & HWCAP_FPHP) {
197 MS_LOG(DEBUG) << "Hw cap support FP16, hwcap: 0x" << hwcap;
198 fp16_flag_ = true;
199 } else {
200 MS_LOG(DEBUG) << "Hw cap NOT support FP16, hwcap: 0x" << hwcap;
201 }
202 #endif
203 return fp16_flag_;
204 #endif
205 }
206 } // namespace mindspore::lite
207 #endif
208