OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <vector> | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/strings/string_number_conversions.h" | |
10 #include "base/strings/string_split.h" | |
11 #include "base/strings/stringprintf.h" | |
12 #include "chrome/browser/chromeos/power/cpu_data_collector.h" | |
13 #include "chrome/browser/chromeos/power/power_data_collector.h" | |
14 #include "content/public/browser/browser_thread.h" | |
15 | |
16 namespace chromeos { | |
17 | |
18 namespace { | |
19 // The CPU data is sampled every |kCpuDataSamplePeriodSec| seconds. | |
20 const int kCpuDataSamplePeriodSec = 30; | |
21 | |
22 const int kCpuOnlineStatus = 1; | |
Daniel Erat
2014/02/15 15:31:25
add a comment describing what this corresponds to
Siva Chandra
2014/02/19 20:02:30
Done.
| |
23 | |
24 #define CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE "/sys/devices/system/cpu" | |
Daniel Erat
2014/02/15 15:31:25
why is this a macro instead of a const char[]?
Siva Chandra
2014/02/19 20:02:30
Done.
| |
25 | |
26 // Path to file listing the range of possible CPUs on the system. | |
27 const char kPossibleCpuPath[] = CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
Daniel Erat
2014/02/15 15:31:25
if the answer to the previous question is "so it c
Siva Chandra
2014/02/19 20:02:30
Done.
| |
28 "/possible"; | |
29 | |
30 // Format of the path to the file which contains information about a particular | |
31 // CPU being online or offline. | |
32 const char kCpuOnlinePathFormat[] = | |
33 CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
Daniel Erat
2014/02/15 15:31:25
same here
Siva Chandra
2014/02/19 20:02:30
Done.
| |
34 "/cpu%d/online"; | |
35 | |
36 // Format of the path to the file which contains freq state information of a | |
37 // CPU. | |
38 const char kCpuFreqTimeInStatePathFormat[] = | |
39 CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
40 "/cpu%d/cpufreq/stats/time_in_state"; | |
41 | |
42 // Format of the path to the directory which contains information about an | |
43 // idle state of a CPU on the system. | |
44 const char kCpuIdleStateDirPathFormat[] = | |
45 CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
46 "/cpu%d/cpuidle/state%d"; | |
47 | |
48 // Format of the path to the file which contains the name of an idle state | |
49 // of a CPU. | |
50 const char kCpuIdleStateNamePathFormat[] = | |
51 CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
52 "/cpu%d/cpuidle/state%d/name"; | |
53 | |
54 // Format of the path which contains information about time spent in an idle | |
55 // state on a CPU. | |
56 const char kCpuIdleStateTimePathFormat[] = | |
57 CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
58 "/cpu%d/cpuidle/state%d/time"; | |
59 | |
60 #undef CHROMEOS_CPU_DATA_COLLECTOR_CPU_DATA_PATH_BASE | |
61 | |
62 // Returns true if the |i|-th CPU is online; false otherwise. | |
63 bool CpuIsOnline(const int i) { | |
64 std::string cpu_online_file = base::StringPrintf(kCpuOnlinePathFormat, i); | |
65 if (!base::PathExists(base::FilePath(cpu_online_file))) { | |
66 // If the 'online' status file is missing, then it means that the CPU is | |
67 // not hot-pluggable and hence is always online. | |
68 return true; | |
69 } | |
70 | |
71 int online; | |
72 std::string cpu_online_string; | |
73 base::ReadFileToString(base::FilePath(cpu_online_file), &cpu_online_string); | |
Daniel Erat
2014/02/15 15:31:25
check the return value of reads
Siva Chandra
2014/02/19 20:02:30
Done.
| |
74 base::StringToInt(cpu_online_string, &online); | |
75 if (online == kCpuOnlineStatus) { | |
Daniel Erat
2014/02/15 15:31:25
just do "return online == kCpuOnlineStatus"
Siva Chandra
2014/02/19 20:02:30
Done.
| |
76 return true; | |
77 } else { | |
78 return false; | |
79 } | |
80 } | |
81 | |
82 // Samples the CPU idle state information from sysfs. |cpu_count| is the number | |
83 // of possible CPUs on the system. Sample at index i in |idle_samples| | |
84 // corresponds to the idle state information of the i-th CPU. | |
85 void SampleCpuIdleData( | |
86 const int cpu_count, | |
Daniel Erat
2014/02/15 15:31:25
don't need const for pass-by-value
Siva Chandra
2014/02/19 20:02:30
Done.
| |
87 std::vector<CpuDataCollector::StateOccupancySample>* idle_samples) { | |
88 base::Time startTime = base::Time::Now(); | |
Daniel Erat
2014/02/15 15:31:25
start_time
Siva Chandra
2014/02/19 20:02:30
Done.
| |
89 for (int i = 0; i < cpu_count; ++i) { | |
90 CpuDataCollector::StateOccupancySample idle_sample; | |
91 idle_sample.time = base::Time::Now(); | |
92 | |
93 if (!CpuIsOnline(i)) { | |
94 idle_sample.cpu_online = false; | |
95 } else { | |
96 idle_sample.cpu_online = true; | |
97 int k = 0; | |
Daniel Erat
2014/02/15 15:31:25
give this variable a meaningful name
Siva Chandra
2014/02/19 20:02:30
Done.
| |
98 std::string idle_state_dir = base::StringPrintf( | |
99 kCpuIdleStateDirPathFormat, i, k); | |
100 while (base::DirectoryExists(base::FilePath(idle_state_dir))) { | |
101 std::string name_file_path = base::StringPrintf( | |
102 kCpuIdleStateNamePathFormat, i, k); | |
103 DCHECK(base::PathExists(base::FilePath(name_file_path))); | |
104 | |
105 std::string time_file_path = base::StringPrintf( | |
106 kCpuIdleStateTimePathFormat, i, k); | |
107 DCHECK(base::PathExists(base::FilePath(time_file_path))); | |
108 | |
109 std::string state_name, occupancy_time_string; | |
110 base::ReadFileToString(base::FilePath(name_file_path), &state_name); | |
Daniel Erat
2014/02/15 15:31:25
check return values
Siva Chandra
2014/02/19 20:02:30
Done.
| |
111 base::ReadFileToString(base::FilePath(time_file_path), | |
112 &occupancy_time_string); | |
113 int64 occupancy_time; | |
114 base::StringToInt64(occupancy_time_string, &occupancy_time); | |
Daniel Erat
2014/02/15 15:31:25
check return value
Siva Chandra
2014/02/19 20:02:30
Done.
| |
115 // idle state occupany time in sysfs is recorded in microseconds. | |
116 idle_sample.state_occupancy[state_name] = occupancy_time/1000; | |
Daniel Erat
2014/02/15 15:31:25
it'd probably be better to keep a separate map fro
Siva Chandra
2014/02/19 20:02:30
Which duplicate strings are you referring to? Also
Daniel Erat
2014/02/21 02:29:37
i meant that each state name will be duplicated in
Siva Chandra
2014/03/05 21:20:26
Done.
| |
117 | |
118 ++k; | |
119 idle_state_dir = base::StringPrintf(kCpuIdleStateDirPathFormat, i, k); | |
120 } | |
121 } | |
122 | |
123 idle_samples->push_back(idle_sample); | |
124 } | |
125 | |
126 // If there was an interruption in sampling (like system suspended), | |
127 // re-sample! | |
128 if (base::TimeDelta(base::Time::Now() - startTime).InMilliseconds() > 500) { | |
129 idle_samples->clear(); | |
130 SampleCpuIdleData(cpu_count, idle_samples); | |
Daniel Erat
2014/02/15 15:31:25
i'd strongly prefer you didn't use recursion here
Siva Chandra
2014/02/19 20:02:30
Removed recursion now. Just discarding the sample.
| |
131 } | |
132 } | |
133 | |
134 // Samples the CPU freq state information from sysfs. |cpu_count| is the number | |
135 // of possible CPUs on the system. Sample at index i in |freq_samples| | |
136 // corresponds to the freq state information of the i-th CPU. | |
137 void SampleCpuFreqData( | |
138 const int cpu_count, | |
139 std::vector<CpuDataCollector::StateOccupancySample>* freq_samples) { | |
140 base::Time startTime = base::Time::Now(); | |
Daniel Erat
2014/02/15 15:31:25
start_time
Siva Chandra
2014/02/19 20:02:30
Done.
| |
141 for (int i = 0; i < cpu_count; ++i) { | |
142 CpuDataCollector::StateOccupancySample freq_sample; | |
143 | |
144 if (!CpuIsOnline(i)) { | |
145 freq_sample.time = base::Time::Now(); | |
146 freq_sample.cpu_online = false; | |
147 } else { | |
148 freq_sample.cpu_online = true; | |
149 | |
150 std::string time_in_state_path = base::StringPrintf( | |
151 kCpuFreqTimeInStatePathFormat, i); | |
152 DCHECK(!base::PathExists(base::FilePath(time_in_state_path))); | |
Daniel Erat
2014/02/15 15:31:25
i don't understand. why are you asserting that a f
Siva Chandra
2014/02/19 20:02:30
I am lost too. Having '!' here is an error, but I
| |
153 | |
154 std::string time_in_state_string; | |
155 // Note time as close to reading the file as possible. This is not | |
156 // possible for idle state samples as the information for each state there | |
157 // is recorded in different files. | |
158 base::Time now = base::Time::Now(); | |
159 base::ReadFileToString(base::FilePath(time_in_state_path), | |
Daniel Erat
2014/02/15 15:31:25
check return value
Siva Chandra
2014/02/19 20:02:30
Done.
| |
160 &time_in_state_string); | |
161 freq_sample.time = now; | |
162 | |
163 std::vector<std::string> lines; | |
164 base::SplitString(time_in_state_string, '\n', &lines); | |
165 // The last line could end with '\n'. Ignore the last empty string in | |
166 // such cases. | |
167 unsigned int state_count = lines.size(); | |
Daniel Erat
2014/02/15 15:31:25
s/unsigned int/size_t/
Siva Chandra
2014/02/19 20:02:30
Done.
| |
168 if (state_count > 0 && lines.back().empty()) { | |
Daniel Erat
2014/02/15 15:31:25
omit curly brackets here
Siva Chandra
2014/02/19 20:02:30
Done.
| |
169 state_count -= 1; | |
170 } | |
171 for (unsigned int k = 0; k < state_count; ++k) { | |
172 std::vector<std::string> pair; | |
173 // Occupancy of each state is in the format "<state> <time>" | |
174 base::SplitString(lines[k], ' ', &pair); | |
Daniel Erat
2014/02/15 15:31:25
check that you got two parts
Siva Chandra
2014/02/19 20:02:30
Done.
| |
175 | |
176 int freq_in_khz; | |
177 int64 occupancy_time; | |
178 base::StringToInt(pair[0], &freq_in_khz); | |
179 base::StringToInt64(pair[1], &occupancy_time); | |
Daniel Erat
2014/02/15 15:31:25
check return values
Siva Chandra
2014/02/19 20:02:30
Done.
| |
180 | |
181 // Freq state occupancy time is recorded in tens of milliseconds. | |
182 freq_sample.state_occupancy[base::IntToString(freq_in_khz / 1000)] = | |
Daniel Erat
2014/02/15 15:31:25
why do you need to convert this to a string? keepi
Siva Chandra
2014/02/19 20:02:30
I did have it as an int initially. I changed it to
| |
183 occupancy_time * 10; | |
184 } | |
185 } | |
186 | |
187 freq_samples->push_back(freq_sample); | |
188 } | |
189 | |
190 // If there was an interruption in sampling (like system suspended), | |
191 // re-sample! | |
192 if (base::TimeDelta(base::Time::Now() - startTime).InMilliseconds() > 500) { | |
193 freq_samples->clear(); | |
194 SampleCpuFreqData(cpu_count, freq_samples); | |
Daniel Erat
2014/02/15 15:31:25
same comment about recursion here
Siva Chandra
2014/02/19 20:02:30
Done.
| |
195 } | |
196 } | |
197 | |
198 } // namespace | |
199 | |
200 CpuDataCollector::CpuDataCollector() : cpu_count_(1), weak_ptr_factory_(this) { | |
201 DCHECK(base::PathExists(base::FilePath(kPossibleCpuPath))); | |
Daniel Erat
2014/02/15 15:31:25
it'd be better to just log an error here and set c
Siva Chandra
2014/02/19 20:02:30
Done.
| |
202 std::string possible_string; | |
203 base::ReadFileToString(base::FilePath(kPossibleCpuPath), &possible_string); | |
204 if (possible_string.find("-") != std::string::npos) { | |
Daniel Erat
2014/02/15 15:31:25
also check that possible_string is long enough so
Siva Chandra
2014/02/19 20:02:30
Done.
| |
205 int max_cpu; | |
206 // The possible CPUs are listed in the format "0-N". Hence, N is present in | |
207 // the substring starting at offset 2. | |
208 base::StringToInt(possible_string.substr(2), &max_cpu); | |
Daniel Erat
2014/02/15 15:31:25
check return value
Siva Chandra
2014/02/19 20:02:30
Done.
| |
209 cpu_count_ = max_cpu + 1; | |
210 } | |
211 | |
212 // Initialize the deques in the data vectors. | |
213 for (int i = 0; i < cpu_count_; ++i) { | |
Daniel Erat
2014/02/15 15:31:25
just do:
cpu_idle_state_data_.resize(cpu_count_
Siva Chandra
2014/02/19 20:02:30
Done.
| |
214 cpu_idle_state_data_.push_back(StateOccupancySampleDeque()); | |
215 cpu_freq_state_data_.push_back(StateOccupancySampleDeque()); | |
216 } | |
217 } | |
218 | |
219 void CpuDataCollector::Start() { | |
220 timer_.Start(FROM_HERE, | |
221 base::TimeDelta::FromSeconds(kCpuDataSamplePeriodSec), | |
222 this, | |
223 &CpuDataCollector::PostSampleCpuState); | |
224 } | |
225 | |
226 void CpuDataCollector::PostSampleCpuState() { | |
227 std::vector<StateOccupancySample>* idle_samples = | |
228 new std::vector<StateOccupancySample>; | |
229 std::vector<StateOccupancySample>* freq_samples = | |
230 new std::vector<StateOccupancySample>; | |
231 content::BrowserThread::PostBlockingPoolTaskAndReply( | |
232 FROM_HERE, | |
233 base::Bind(&CpuDataCollector::SampleCpuStateOnBlockingPool, | |
234 weak_ptr_factory_.GetWeakPtr(), | |
235 base::Unretained(idle_samples), | |
236 base::Unretained(freq_samples)), | |
237 base::Bind(&CpuDataCollector::SaveCpuStateSamplesOnUIThread, | |
238 weak_ptr_factory_.GetWeakPtr(), | |
239 base::Owned(idle_samples), | |
240 base::Owned(freq_samples))); | |
241 } | |
242 | |
243 void CpuDataCollector::SampleCpuStateOnBlockingPool( | |
244 std::vector<CpuDataCollector::StateOccupancySample>* idle_samples, | |
245 std::vector<CpuDataCollector::StateOccupancySample>* freq_samples) { | |
246 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
247 | |
248 SampleCpuIdleData(cpu_count_, idle_samples); | |
249 SampleCpuFreqData(cpu_count_, freq_samples); | |
250 } | |
251 | |
252 void CpuDataCollector::SaveCpuStateSamplesOnUIThread( | |
253 const std::vector<CpuDataCollector::StateOccupancySample>* idle_samples, | |
254 const std::vector<CpuDataCollector::StateOccupancySample>* freq_samples) { | |
255 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
256 | |
257 DCHECK(idle_samples->size() == cpu_idle_state_data_.size()); | |
Daniel Erat
2014/02/15 15:31:25
nit: DCHECK_EQ
Siva Chandra
2014/02/19 20:02:30
Done.
| |
258 for (unsigned int i = 0; i < cpu_idle_state_data_.size(); ++i) { | |
Daniel Erat
2014/02/15 15:31:25
nit: omit curly brackets
Siva Chandra
2014/02/19 20:02:30
Done.
| |
259 AddSample(&cpu_idle_state_data_[i], (*idle_samples)[i]); | |
Daniel Erat
2014/02/15 15:31:25
does this compile? i don't see where AddSample is
Siva Chandra
2014/02/19 20:02:30
AddSample is a template function defined in power_
| |
260 } | |
261 | |
262 DCHECK(freq_samples->size() == cpu_freq_state_data_.size()); | |
Daniel Erat
2014/02/15 15:31:25
nit: DCHECK_EQ
Siva Chandra
2014/02/19 20:02:30
Done.
| |
263 for (unsigned int i = 0; i < cpu_freq_state_data_.size(); ++i) { | |
Daniel Erat
2014/02/15 15:31:25
nit: omit curly brackets
Siva Chandra
2014/02/19 20:02:30
Done.
| |
264 AddSample(&cpu_freq_state_data_[i], (*freq_samples)[i]); | |
265 } | |
266 } | |
267 | |
268 CpuDataCollector::StateOccupancySample::StateOccupancySample() | |
269 : cpu_online(false) { | |
270 } | |
271 | |
272 } // namespace chromeos | |
OLD | NEW |