• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 The Android Open Source Project
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 #include "cpu_info.h"  // NOLINT
17 
18 #include <unistd.h>
19 
20 #include <cerrno>
21 #include <climits>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 
26 namespace gav1_jni {
27 namespace {
28 
29 // Note: The code in this file needs to use the 'long' type because it is the
30 // return type of the Standard C Library function strtol(). The linter warnings
31 // are suppressed with NOLINT comments since they are integers at runtime.
32 
33 // Returns the number of online processor cores.
GetNumberOfProcessorsOnline()34 int GetNumberOfProcessorsOnline() {
35   // See https://developer.android.com/ndk/guides/cpu-features.
36   long num_cpus = sysconf(_SC_NPROCESSORS_ONLN);  // NOLINT
37   if (num_cpus < 0) {
38     return 0;
39   }
40   // It is safe to cast num_cpus to int. sysconf(_SC_NPROCESSORS_ONLN) returns
41   // the return value of get_nprocs(), which is an int.
42   return static_cast<int>(num_cpus);
43 }
44 
45 }  // namespace
46 
47 // These CPUs support heterogeneous multiprocessing.
48 #if defined(__arm__) || defined(__aarch64__)
49 
50 // A helper function used by GetNumberOfPerformanceCoresOnline().
51 //
52 // Returns the cpuinfo_max_freq value (in kHz) of the given CPU. Returns 0 on
53 // failure.
GetCpuinfoMaxFreq(int cpu_index)54 long GetCpuinfoMaxFreq(int cpu_index) {  // NOLINT
55   char buffer[128];
56   const int rv = snprintf(
57       buffer, sizeof(buffer),
58       "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu_index);
59   if (rv < 0 || rv >= sizeof(buffer)) {
60     return 0;
61   }
62   FILE* file = fopen(buffer, "r");
63   if (file == nullptr) {
64     return 0;
65   }
66   char* const str = fgets(buffer, sizeof(buffer), file);
67   fclose(file);
68   if (str == nullptr) {
69     return 0;
70   }
71   const long freq = strtol(str, nullptr, 10);  // NOLINT
72   if (freq <= 0 || freq == LONG_MAX) {
73     return 0;
74   }
75   return freq;
76 }
77 
78 // Returns the number of performance CPU cores that are online. The number of
79 // efficiency CPU cores is subtracted from the total number of CPU cores. Uses
80 // cpuinfo_max_freq to determine whether a CPU is a performance core or an
81 // efficiency core.
82 //
83 // This function is not perfect. For example, the Snapdragon 632 SoC used in
84 // Motorola Moto G7 has performance and efficiency cores with the same
85 // cpuinfo_max_freq but different cpuinfo_min_freq. This function fails to
86 // differentiate the two kinds of cores and reports all the cores as
87 // performance cores.
GetNumberOfPerformanceCoresOnline()88 int GetNumberOfPerformanceCoresOnline() {
89   // Get the online CPU list. Some examples of the online CPU list are:
90   //   "0-7"
91   //   "0"
92   //   "0-1,2,3,4-7"
93   FILE* file = fopen("/sys/devices/system/cpu/online", "r");
94   if (file == nullptr) {
95     return 0;
96   }
97   char online[512];
98   char* const str = fgets(online, sizeof(online), file);
99   fclose(file);
100   file = nullptr;
101   if (str == nullptr) {
102     return 0;
103   }
104 
105   // Count the number of the slowest CPUs. Some SoCs such as Snapdragon 855
106   // have performance cores with different max frequencies, so only the slowest
107   // CPUs are efficiency cores. If we count the number of the fastest CPUs, we
108   // will fail to count the second fastest performance cores.
109   long slowest_cpu_freq = LONG_MAX;  // NOLINT
110   int num_slowest_cpus = 0;
111   int num_cpus = 0;
112   const char* cp = online;
113   int range_begin = -1;
114   while (true) {
115     char* str_end;
116     const int cpu = static_cast<int>(strtol(cp, &str_end, 10));  // NOLINT
117     if (str_end == cp) {
118       break;
119     }
120     cp = str_end;
121     if (*cp == '-') {
122       range_begin = cpu;
123     } else {
124       if (range_begin == -1) {
125         range_begin = cpu;
126       }
127 
128       num_cpus += cpu - range_begin + 1;
129       for (int i = range_begin; i <= cpu; ++i) {
130         const long freq = GetCpuinfoMaxFreq(i);  // NOLINT
131         if (freq <= 0) {
132           return 0;
133         }
134         if (freq < slowest_cpu_freq) {
135           slowest_cpu_freq = freq;
136           num_slowest_cpus = 0;
137         }
138         if (freq == slowest_cpu_freq) {
139           ++num_slowest_cpus;
140         }
141       }
142 
143       range_begin = -1;
144     }
145     if (*cp == '\0') {
146       break;
147     }
148     ++cp;
149   }
150 
151   // If there are faster CPU cores than the slowest CPU cores, exclude the
152   // slowest CPU cores.
153   if (num_slowest_cpus < num_cpus) {
154     num_cpus -= num_slowest_cpus;
155   }
156   return num_cpus;
157 }
158 
159 #else
160 
161 // Assume symmetric multiprocessing.
GetNumberOfPerformanceCoresOnline()162 int GetNumberOfPerformanceCoresOnline() {
163   return GetNumberOfProcessorsOnline();
164 }
165 
166 #endif
167 
168 }  // namespace gav1_jni
169