OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2008 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #if defined(WEBRTC_LINUX) | |
12 #include "webrtc/base/linux.h" | |
13 | |
14 #include <ctype.h> | |
15 | |
16 #include <errno.h> | |
17 #include <sys/utsname.h> | |
18 #include <sys/wait.h> | |
19 | |
20 #include <cstdio> | |
21 #include <set> | |
22 | |
23 #include "webrtc/base/stringencode.h" | |
24 | |
25 namespace rtc { | |
26 | |
27 static const char kCpuInfoFile[] = "/proc/cpuinfo"; | |
28 static const char kCpuMaxFreqFile[] = | |
29 "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"; | |
30 | |
31 ProcCpuInfo::ProcCpuInfo() { | |
32 } | |
33 | |
34 ProcCpuInfo::~ProcCpuInfo() { | |
35 } | |
36 | |
37 bool ProcCpuInfo::LoadFromSystem() { | |
38 ConfigParser procfs; | |
39 if (!procfs.Open(kCpuInfoFile)) { | |
40 return false; | |
41 } | |
42 return procfs.Parse(§ions_); | |
43 }; | |
44 | |
45 bool ProcCpuInfo::GetSectionCount(size_t* count) { | |
46 if (sections_.empty()) { | |
47 return false; | |
48 } | |
49 if (count) { | |
50 *count = sections_.size(); | |
51 } | |
52 return true; | |
53 } | |
54 | |
55 bool ProcCpuInfo::GetNumCpus(int* num) { | |
56 if (sections_.empty()) { | |
57 return false; | |
58 } | |
59 int total_cpus = 0; | |
60 #if defined(__arm__) | |
61 // Count the number of blocks that have a "processor" key defined. On ARM, | |
62 // there may be extra blocks of information that aren't per-processor. | |
63 size_t section_count = sections_.size(); | |
64 for (size_t i = 0; i < section_count; ++i) { | |
65 int processor_id; | |
66 if (GetSectionIntValue(i, "processor", &processor_id)) { | |
67 ++total_cpus; | |
68 } | |
69 } | |
70 // Single core ARM systems don't include "processor" keys at all, so return | |
71 // that we have a single core if we didn't find any explicitly above. | |
72 if (total_cpus == 0) { | |
73 total_cpus = 1; | |
74 } | |
75 #else | |
76 // On X86, there is exactly one info section per processor. | |
77 total_cpus = static_cast<int>(sections_.size()); | |
78 #endif | |
79 if (num) { | |
80 *num = total_cpus; | |
81 } | |
82 return true; | |
83 } | |
84 | |
85 bool ProcCpuInfo::GetNumPhysicalCpus(int* num) { | |
86 if (sections_.empty()) { | |
87 return false; | |
88 } | |
89 // TODO: /proc/cpuinfo only reports cores that are currently | |
90 // _online_, so this may underreport the number of physical cores. | |
91 #if defined(__arm__) | |
92 // ARM (currently) has no hyperthreading, so just return the same value | |
93 // as GetNumCpus. | |
94 return GetNumCpus(num); | |
95 #else | |
96 int total_cores = 0; | |
97 std::set<int> physical_ids; | |
98 size_t section_count = sections_.size(); | |
99 for (size_t i = 0; i < section_count; ++i) { | |
100 int physical_id; | |
101 int cores; | |
102 // Count the cores for the physical id only if we have not counted the id. | |
103 if (GetSectionIntValue(i, "physical id", &physical_id) && | |
104 GetSectionIntValue(i, "cpu cores", &cores) && | |
105 physical_ids.find(physical_id) == physical_ids.end()) { | |
106 physical_ids.insert(physical_id); | |
107 total_cores += cores; | |
108 } | |
109 } | |
110 | |
111 if (num) { | |
112 *num = total_cores; | |
113 } | |
114 return true; | |
115 #endif | |
116 } | |
117 | |
118 bool ProcCpuInfo::GetCpuFamily(int* id) { | |
119 int cpu_family = 0; | |
120 | |
121 #if defined(__arm__) | |
122 // On some ARM platforms, there is no 'cpu family' in '/proc/cpuinfo'. But | |
123 // there is 'CPU Architecture' which can be used as 'cpu family'. | |
124 // See http://en.wikipedia.org/wiki/ARM_architecture for a good list of | |
125 // ARM cpu families, architectures, and their mappings. | |
126 // There may be multiple sessions that aren't per-processor. We need to scan | |
127 // through each session until we find the first 'CPU architecture'. | |
128 size_t section_count = sections_.size(); | |
129 for (size_t i = 0; i < section_count; ++i) { | |
130 if (GetSectionIntValue(i, "CPU architecture", &cpu_family)) { | |
131 // We returns the first one (if there are multiple entries). | |
132 break; | |
133 }; | |
134 } | |
135 #else | |
136 GetSectionIntValue(0, "cpu family", &cpu_family); | |
137 #endif | |
138 if (id) { | |
139 *id = cpu_family; | |
140 } | |
141 return true; | |
142 } | |
143 | |
144 bool ProcCpuInfo::GetSectionStringValue(size_t section_num, | |
145 const std::string& key, | |
146 std::string* result) { | |
147 if (section_num >= sections_.size()) { | |
148 return false; | |
149 } | |
150 ConfigParser::SimpleMap::iterator iter = sections_[section_num].find(key); | |
151 if (iter == sections_[section_num].end()) { | |
152 return false; | |
153 } | |
154 *result = iter->second; | |
155 return true; | |
156 } | |
157 | |
158 bool ProcCpuInfo::GetSectionIntValue(size_t section_num, | |
159 const std::string& key, | |
160 int* result) { | |
161 if (section_num >= sections_.size()) { | |
162 return false; | |
163 } | |
164 ConfigParser::SimpleMap::iterator iter = sections_[section_num].find(key); | |
165 if (iter == sections_[section_num].end()) { | |
166 return false; | |
167 } | |
168 return FromString(iter->second, result); | |
169 } | |
170 | |
171 ConfigParser::ConfigParser() {} | |
172 | |
173 ConfigParser::~ConfigParser() {} | |
174 | |
175 bool ConfigParser::Open(const std::string& filename) { | |
176 FileStream* fs = new FileStream(); | |
177 if (!fs->Open(filename, "r", NULL)) { | |
178 return false; | |
179 } | |
180 instream_.reset(fs); | |
181 return true; | |
182 } | |
183 | |
184 void ConfigParser::Attach(StreamInterface* stream) { | |
185 instream_.reset(stream); | |
186 } | |
187 | |
188 bool ConfigParser::Parse(MapVector* key_val_pairs) { | |
189 // Parses the file and places the found key-value pairs into key_val_pairs. | |
190 SimpleMap section; | |
191 while (ParseSection(§ion)) { | |
192 key_val_pairs->push_back(section); | |
193 section.clear(); | |
194 } | |
195 return (!key_val_pairs->empty()); | |
196 } | |
197 | |
198 bool ConfigParser::ParseSection(SimpleMap* key_val_pair) { | |
199 // Parses the next section in the filestream and places the found key-value | |
200 // pairs into key_val_pair. | |
201 std::string key, value; | |
202 while (ParseLine(&key, &value)) { | |
203 (*key_val_pair)[key] = value; | |
204 } | |
205 return (!key_val_pair->empty()); | |
206 } | |
207 | |
208 bool ConfigParser::ParseLine(std::string* key, std::string* value) { | |
209 // Parses the next line in the filestream and places the found key-value | |
210 // pair into key and val. | |
211 std::string line; | |
212 if ((instream_->ReadLine(&line)) == SR_EOS) { | |
213 return false; | |
214 } | |
215 std::vector<std::string> tokens; | |
216 if (2 != split(line, ':', &tokens)) { | |
217 return false; | |
218 } | |
219 // Removes whitespace at the end of Key name | |
220 size_t pos = tokens[0].length() - 1; | |
221 while ((pos > 0) && isspace(tokens[0][pos])) { | |
222 pos--; | |
223 } | |
224 tokens[0].erase(pos + 1); | |
225 // Removes whitespace at the start of value | |
226 pos = 0; | |
227 while (pos < tokens[1].length() && isspace(tokens[1][pos])) { | |
228 pos++; | |
229 } | |
230 tokens[1].erase(0, pos); | |
231 *key = tokens[0]; | |
232 *value = tokens[1]; | |
233 return true; | |
234 } | |
235 | |
236 std::string ReadLinuxUname() { | |
237 struct utsname buf; | |
238 if (uname(&buf) < 0) { | |
239 LOG_ERR(LS_ERROR) << "Can't call uname()"; | |
240 return std::string(); | |
241 } | |
242 std::ostringstream sstr; | |
243 sstr << buf.sysname << " " | |
244 << buf.release << " " | |
245 << buf.version << " " | |
246 << buf.machine; | |
247 return sstr.str(); | |
248 } | |
249 | |
250 int ReadCpuMaxFreq() { | |
251 FileStream fs; | |
252 std::string str; | |
253 int freq = -1; | |
254 if (!fs.Open(kCpuMaxFreqFile, "r", NULL) || | |
255 SR_SUCCESS != fs.ReadLine(&str) || | |
256 !FromString(str, &freq)) { | |
257 return -1; | |
258 } | |
259 return freq; | |
260 } | |
261 | |
262 } // namespace rtc | |
263 | |
264 #endif // defined(WEBRTC_LINUX) | |
OLD | NEW |