Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(440)

Side by Side Diff: talk/examples/android/src/org/appspot/apprtc/CpuMonitor.java

Issue 1235563006: Move talk/examples/* to webrtc/examples. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: 201508051337 Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * libjingle
3 * Copyright 2015 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 package org.appspot.apprtc;
29
30 import android.util.Log;
31
32 import java.io.BufferedReader;
33 import java.io.FileNotFoundException;
34 import java.io.FileReader;
35 import java.io.IOException;
36 import java.util.InputMismatchException;
37 import java.util.Scanner;
38
39 /**
40 * Simple CPU monitor. The caller creates a CpuMonitor object which can then
41 * be used via sampleCpuUtilization() to collect the percentual use of the
42 * cumulative CPU capacity for all CPUs running at their nominal frequency. 3
43 * values are generated: (1) getCpuCurrent() returns the use since the last
44 * sampleCpuUtilization(), (2) getCpuAvg3() returns the use since 3 prior
45 * calls, and (3) getCpuAvgAll() returns the use over all SAMPLE_SAVE_NUMBER
46 * calls.
47 *
48 * <p>CPUs in Android are often "offline", and while this of course means 0 Hz
49 * as current frequency, in this state we cannot even get their nominal
50 * frequency. We therefore tread carefully, and allow any CPU to be missing.
51 * Missing CPUs are assumed to have the same nominal frequency as any close
52 * lower-numbered CPU, but as soon as it is online, we'll get their proper
53 * frequency and remember it. (Since CPU 0 in practice always seem to be
54 * online, this unidirectional frequency inheritance should be no problem in
55 * practice.)
56 *
57 * <p>Caveats:
58 * o No provision made for zany "turbo" mode, common in the x86 world.
59 * o No provision made for ARM big.LITTLE; if CPU n can switch behind our
60 * back, we might get incorrect estimates.
61 * o This is not thread-safe. To call asynchronously, create different
62 * CpuMonitor objects.
63 *
64 * <p>If we can gather enough info to generate a sensible result,
65 * sampleCpuUtilization returns true. It is designed to never through an
66 * exception.
67 *
68 * <p>sampleCpuUtilization should not be called too often in its present form,
69 * since then deltas would be small and the percent values would fluctuate and
70 * be unreadable. If it is desirable to call it more often than say once per
71 * second, one would need to increase SAMPLE_SAVE_NUMBER and probably use
72 * Queue<Integer> to avoid copying overhead.
73 *
74 * <p>Known problems:
75 * 1. Nexus 7 devices running Kitkat have a kernel which often output an
76 * incorrect 'idle' field in /proc/stat. The value is close to twice the
77 * correct value, and then returns to back to correct reading. Both when
78 * jumping up and back down we might create faulty CPU load readings.
79 */
80
81 class CpuMonitor {
82 private static final int SAMPLE_SAVE_NUMBER = 10; // Assumed to be >= 3.
83 private int[] percentVec = new int[SAMPLE_SAVE_NUMBER];
84 private int sum3 = 0;
85 private int sum10 = 0;
86 private static final String TAG = "CpuMonitor";
87 private long[] cpuFreq;
88 private int cpusPresent;
89 private double lastPercentFreq = -1;
90 private int cpuCurrent;
91 private int cpuAvg3;
92 private int cpuAvgAll;
93 private boolean initialized = false;
94 private String[] maxPath;
95 private String[] curPath;
96 ProcStat lastProcStat;
97
98 private class ProcStat {
99 final long runTime;
100 final long idleTime;
101
102 ProcStat(long aRunTime, long aIdleTime) {
103 runTime = aRunTime;
104 idleTime = aIdleTime;
105 }
106 }
107
108 private void init() {
109 try {
110 FileReader fin = new FileReader("/sys/devices/system/cpu/present");
111 try {
112 BufferedReader rdr = new BufferedReader(fin);
113 Scanner scanner = new Scanner(rdr).useDelimiter("[-\n]");
114 scanner.nextInt(); // Skip leading number 0.
115 cpusPresent = 1 + scanner.nextInt();
116 scanner.close();
117 } catch (Exception e) {
118 Log.e(TAG, "Cannot do CPU stats due to /sys/devices/system/cpu/present p arsing problem");
119 } finally {
120 fin.close();
121 }
122 } catch (FileNotFoundException e) {
123 Log.e(TAG, "Cannot do CPU stats since /sys/devices/system/cpu/present is m issing");
124 } catch (IOException e) {
125 Log.e(TAG, "Error closing file");
126 }
127
128 cpuFreq = new long [cpusPresent];
129 maxPath = new String [cpusPresent];
130 curPath = new String [cpusPresent];
131 for (int i = 0; i < cpusPresent; i++) {
132 cpuFreq[i] = 0; // Frequency "not yet determined".
133 maxPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_fre q";
134 curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_fre q";
135 }
136
137 lastProcStat = new ProcStat(0, 0);
138
139 initialized = true;
140 }
141
142 /**
143 * Re-measure CPU use. Call this method at an interval of around 1/s.
144 * This method returns true on success. The fields
145 * cpuCurrent, cpuAvg3, and cpuAvgAll are updated on success, and represents:
146 * cpuCurrent: The CPU use since the last sampleCpuUtilization call.
147 * cpuAvg3: The average CPU over the last 3 calls.
148 * cpuAvgAll: The average CPU over the last SAMPLE_SAVE_NUMBER calls.
149 */
150 public boolean sampleCpuUtilization() {
151 long lastSeenMaxFreq = 0;
152 long cpufreqCurSum = 0;
153 long cpufreqMaxSum = 0;
154
155 if (!initialized) {
156 init();
157 }
158
159 for (int i = 0; i < cpusPresent; i++) {
160 /*
161 * For each CPU, attempt to first read its max frequency, then its
162 * current frequency. Once as the max frequency for a CPU is found,
163 * save it in cpuFreq[].
164 */
165
166 if (cpuFreq[i] == 0) {
167 // We have never found this CPU's max frequency. Attempt to read it.
168 long cpufreqMax = readFreqFromFile(maxPath[i]);
169 if (cpufreqMax > 0) {
170 lastSeenMaxFreq = cpufreqMax;
171 cpuFreq[i] = cpufreqMax;
172 maxPath[i] = null; // Kill path to free its memory.
173 }
174 } else {
175 lastSeenMaxFreq = cpuFreq[i]; // A valid, previously read value.
176 }
177
178 long cpufreqCur = readFreqFromFile(curPath[i]);
179 cpufreqCurSum += cpufreqCur;
180
181 /* Here, lastSeenMaxFreq might come from
182 * 1. cpuFreq[i], or
183 * 2. a previous iteration, or
184 * 3. a newly read value, or
185 * 4. hypothetically from the pre-loop dummy.
186 */
187 cpufreqMaxSum += lastSeenMaxFreq;
188 }
189
190 if (cpufreqMaxSum == 0) {
191 Log.e(TAG, "Could not read max frequency for any CPU");
192 return false;
193 }
194
195 /*
196 * Since the cycle counts are for the period between the last invocation
197 * and this present one, we average the percentual CPU frequencies between
198 * now and the beginning of the measurement period. This is significantly
199 * incorrect only if the frequencies have peeked or dropped in between the
200 * invocations.
201 */
202 double newPercentFreq = 100.0 * cpufreqCurSum / cpufreqMaxSum;
203 double percentFreq;
204 if (lastPercentFreq > 0) {
205 percentFreq = (lastPercentFreq + newPercentFreq) * 0.5;
206 } else {
207 percentFreq = newPercentFreq;
208 }
209 lastPercentFreq = newPercentFreq;
210
211 ProcStat procStat = readIdleAndRunTime();
212 if (procStat == null) {
213 return false;
214 }
215
216 long diffRunTime = procStat.runTime - lastProcStat.runTime;
217 long diffIdleTime = procStat.idleTime - lastProcStat.idleTime;
218
219 // Save new measurements for next round's deltas.
220 lastProcStat = procStat;
221
222 long allTime = diffRunTime + diffIdleTime;
223 int percent = allTime == 0 ? 0 : (int) Math.round(percentFreq * diffRunTime / allTime);
224 percent = Math.max(0, Math.min(percent, 100));
225
226 // Subtract old relevant measurement, add newest.
227 sum3 += percent - percentVec[2];
228 // Subtract oldest measurement, add newest.
229 sum10 += percent - percentVec[SAMPLE_SAVE_NUMBER - 1];
230
231 // Rotate saved percent values, save new measurement in vacated spot.
232 for (int i = SAMPLE_SAVE_NUMBER - 1; i > 0; i--) {
233 percentVec[i] = percentVec[i - 1];
234 }
235 percentVec[0] = percent;
236
237 cpuCurrent = percent;
238 cpuAvg3 = sum3 / 3;
239 cpuAvgAll = sum10 / SAMPLE_SAVE_NUMBER;
240
241 return true;
242 }
243
244 public int getCpuCurrent() {
245 return cpuCurrent;
246 }
247
248 public int getCpuAvg3() {
249 return cpuAvg3;
250 }
251
252 public int getCpuAvgAll() {
253 return cpuAvgAll;
254 }
255
256 /**
257 * Read a single integer value from the named file. Return the read value
258 * or if an error occurs return 0.
259 */
260 private long readFreqFromFile(String fileName) {
261 long number = 0;
262 try {
263 FileReader fin = new FileReader(fileName);
264 try {
265 BufferedReader rdr = new BufferedReader(fin);
266 Scanner scannerC = new Scanner(rdr);
267 number = scannerC.nextLong();
268 scannerC.close();
269 } catch (Exception e) {
270 // CPU presumably got offline just after we opened file.
271 } finally {
272 fin.close();
273 }
274 } catch (FileNotFoundException e) {
275 // CPU is offline, not an error.
276 } catch (IOException e) {
277 Log.e(TAG, "Error closing file");
278 }
279 return number;
280 }
281
282 /*
283 * Read the current utilization of all CPUs using the cumulative first line
284 * of /proc/stat.
285 */
286 private ProcStat readIdleAndRunTime() {
287 long runTime = 0;
288 long idleTime = 0;
289 try {
290 FileReader fin = new FileReader("/proc/stat");
291 try {
292 BufferedReader rdr = new BufferedReader(fin);
293 Scanner scanner = new Scanner(rdr);
294 scanner.next();
295 long user = scanner.nextLong();
296 long nice = scanner.nextLong();
297 long sys = scanner.nextLong();
298 runTime = user + nice + sys;
299 idleTime = scanner.nextLong();
300 scanner.close();
301 } catch (Exception e) {
302 Log.e(TAG, "Problems parsing /proc/stat");
303 return null;
304 } finally {
305 fin.close();
306 }
307 } catch (FileNotFoundException e) {
308 Log.e(TAG, "Cannot open /proc/stat for reading");
309 return null;
310 } catch (IOException e) {
311 Log.e(TAG, "Problems reading /proc/stat");
312 return null;
313 }
314 return new ProcStat(runTime, idleTime);
315 }
316 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698