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