1 /*
2 * Copyright 2018 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
17 #define LOG_TAG "Swappy"
18
19 #include "CpuInfo.h"
20
21 #include <limits>
22 #include <bitset>
23 #include <cstdlib>
24 #include <cstring>
25
26 #include "Log.h"
27
28 namespace {
29
startsWith(std::string & mainStr,const char * toMatch)30 bool startsWith(std::string &mainStr, const char *toMatch) {
31 // std::string::find returns 0 if toMatch is found at beginning
32 return mainStr.find(toMatch) == 0;
33 }
34
split(const std::string & s,char c)35 std::vector<std::string> split(const std::string& s, char c) {
36 std::vector<std::string> v;
37 std::string::size_type i = 0;
38 std::string::size_type j = s.find(c);
39
40 while (j != std::string::npos) {
41 v.push_back(s.substr(i, j-i));
42 i = ++j;
43 j = s.find(c, j);
44
45 if (j == std::string::npos) {
46 v.push_back(s.substr(i, s.length()));
47 }
48 }
49 return v;
50 }
51
ReadFile(const std::string & path)52 std::string ReadFile(const std::string& path) {
53 char buf[10240];
54 FILE *fp = fopen(path.c_str(), "r");
55 if (fp == nullptr)
56 return std::string();
57
58 fgets(buf, 10240, fp);
59 fclose(fp);
60 return std::string(buf);
61 }
62
63 } // anonymous namespace
64
65 namespace swappy {
66
to_string(int n)67 std::string to_string(int n) {
68 constexpr int kBufSize = 12; // strlen("−2147483648")+1
69 static char buf[kBufSize];
70 snprintf(buf, kBufSize, "%d", n);
71 return buf;
72 }
73
CpuInfo()74 CpuInfo::CpuInfo() {
75 const auto BUFFER_LENGTH = 10240;
76
77 char buf[BUFFER_LENGTH];
78 FILE *fp = fopen("/proc/cpuinfo", "r");
79
80 if (!fp) {
81 return;
82 }
83
84 long mMaxFrequency = 0;
85 long mMinFrequency = std::numeric_limits<long>::max();
86
87 while (fgets(buf, BUFFER_LENGTH, fp) != NULL) {
88 buf[strlen(buf) - 1] = '\0'; // eat the newline fgets() stores
89 std::string line = buf;
90
91 if (startsWith(line, "processor")) {
92 Cpu core;
93 core.id = mCpus.size();
94
95 auto core_path = std::string("/sys/devices/system/cpu/cpu")
96 + to_string(core.id);
97
98 auto package_id = ReadFile(core_path + "/topology/physical_package_id");
99 auto frequency = ReadFile(core_path + "/cpufreq/cpuinfo_max_freq");
100
101 core.package_id = atol(package_id.c_str());
102 core.frequency = atol(frequency.c_str());
103
104 mMinFrequency = std::min(mMinFrequency, core.frequency);
105 mMaxFrequency = std::max(mMaxFrequency, core.frequency);
106
107 mCpus.push_back(core);
108 }
109 else if (startsWith(line, "Hardware")) {
110 mHardware = split(line, ':')[1];
111 }
112 }
113 fclose(fp);
114
115 CPU_ZERO(&mLittleCoresMask);
116 CPU_ZERO(&mBigCoresMask);
117
118 for (auto cpu : mCpus) {
119 if (cpu.frequency == mMinFrequency) {
120 ++mNumberOfLittleCores;
121 cpu.type = Cpu::Type::Little;
122 CPU_SET(cpu.id, &mLittleCoresMask);
123 }
124 else {
125 ++mNumberOfBigCores;
126 cpu.type = Cpu::Type::Big;
127 CPU_SET(cpu.id, &mBigCoresMask);
128 }
129 }
130 }
131
getNumberOfCpus() const132 unsigned int CpuInfo::getNumberOfCpus() const {
133 return mCpus.size();
134 }
135
getCpus() const136 const std::vector<CpuInfo::Cpu>& CpuInfo::getCpus() const {
137 return mCpus;
138 }
139
getHardware() const140 const std::string CpuInfo::getHardware() const {
141 return mHardware;
142 }
143
getNumberOfLittleCores() const144 unsigned int CpuInfo::getNumberOfLittleCores() const {
145 return mNumberOfLittleCores;
146 }
147
getNumberOfBigCores() const148 unsigned int CpuInfo::getNumberOfBigCores() const {
149 return mNumberOfBigCores;
150 }
151
getLittleCoresMask() const152 cpu_set_t CpuInfo::getLittleCoresMask() const {
153 return mLittleCoresMask;
154 }
155
getBigCoresMask() const156 cpu_set_t CpuInfo::getBigCoresMask() const {
157 return mBigCoresMask;
158 }
159
to_mask(cpu_set_t cpu_set)160 unsigned int to_mask(cpu_set_t cpu_set) {
161 std::bitset<32> mask;
162
163 for (int i = 0; i < CPU_SETSIZE; ++i) {
164 if (CPU_ISSET(i, &cpu_set))
165 mask[i] = 1;
166 }
167 return (int) mask.to_ulong();
168 }
169
170 } // namespace swappy
171