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

Side by Side Diff: webrtc/examples/androidapp/src/org/appspot/apprtc/CpuMonitor.java

Issue 1813053007: Update CPU Monitor to report CPU frequency and battery level. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc@master
Patch Set: Address comment Created 4 years, 9 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
1 /* 1 /*
2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 package org.appspot.apprtc; 11 package org.appspot.apprtc;
12 12
13 import android.content.Context;
14 import android.content.Intent;
15 import android.content.IntentFilter;
16 import android.os.BatteryManager;
17 import android.os.Environment;
18 import android.os.SystemClock;
13 import android.util.Log; 19 import android.util.Log;
14 20
15 import java.io.BufferedReader; 21 import java.io.BufferedReader;
22 import java.io.File;
16 import java.io.FileNotFoundException; 23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
17 import java.io.FileReader; 25 import java.io.FileReader;
18 import java.io.IOException; 26 import java.io.IOException;
19 import java.util.InputMismatchException; 27 import java.text.SimpleDateFormat;
28 import java.util.Calendar;
29 import java.util.Date;
20 import java.util.Scanner; 30 import java.util.Scanner;
21 31
32 import org.appspot.apprtc.util.LooperExecutor;
33
22 /** 34 /**
23 * Simple CPU monitor. The caller creates a CpuMonitor object which can then 35 * Simple CPU monitor. The caller creates a CpuMonitor object which can then
24 * be used via sampleCpuUtilization() to collect the percentual use of the 36 * be used via sampleCpuUtilization() to collect the percentual use of the
25 * cumulative CPU capacity for all CPUs running at their nominal frequency. 3 37 * cumulative CPU capacity for all CPUs running at their nominal frequency. 3
26 * values are generated: (1) getCpuCurrent() returns the use since the last 38 * values are generated: (1) getCpuCurrent() returns the use since the last
27 * sampleCpuUtilization(), (2) getCpuAvg3() returns the use since 3 prior 39 * sampleCpuUtilization(), (2) getCpuAvg3() returns the use since 3 prior
28 * calls, and (3) getCpuAvgAll() returns the use over all SAMPLE_SAVE_NUMBER 40 * calls, and (3) getCpuAvgAll() returns the use over all SAMPLE_SAVE_NUMBER
29 * calls. 41 * calls.
30 * 42 *
31 * <p>CPUs in Android are often "offline", and while this of course means 0 Hz 43 * <p>CPUs in Android are often "offline", and while this of course means 0 Hz
(...skipping 23 matching lines...) Expand all
55 * Queue<Integer> to avoid copying overhead. 67 * Queue<Integer> to avoid copying overhead.
56 * 68 *
57 * <p>Known problems: 69 * <p>Known problems:
58 * 1. Nexus 7 devices running Kitkat have a kernel which often output an 70 * 1. Nexus 7 devices running Kitkat have a kernel which often output an
59 * incorrect 'idle' field in /proc/stat. The value is close to twice the 71 * incorrect 'idle' field in /proc/stat. The value is close to twice the
60 * correct value, and then returns to back to correct reading. Both when 72 * correct value, and then returns to back to correct reading. Both when
61 * jumping up and back down we might create faulty CPU load readings. 73 * jumping up and back down we might create faulty CPU load readings.
62 */ 74 */
63 75
64 class CpuMonitor { 76 class CpuMonitor {
65 private static final int SAMPLE_SAVE_NUMBER = 10; // Assumed to be >= 3.
66 private int[] percentVec = new int[SAMPLE_SAVE_NUMBER];
67 private int sum3 = 0;
68 private int sum10 = 0;
69 private static final String TAG = "CpuMonitor"; 77 private static final String TAG = "CpuMonitor";
70 private long[] cpuFreq; 78 private static final String DUMP_FILE = "cpu_log.txt";
79 private static final int CPU_STAT_SAMPLE_PERIOD = 2000;
80 private static final int CPU_STAT_LOG_PERIOD = 6000;
81
82 private final Context appContext;
83 private LooperExecutor executor;
84 private long lastStatLogTimeMs;
85 private int iterations;
86 private double currentUserCpuUsage;
87 private double currentSystemCpuUsage;
88 private double currentTotalCpuUsage;
89 private double currentFrequencyScale = -1;
90 private double sumUserCpuUsage;
91 private double sumSystemCpuUsage;
92 private double sumFrequencyScale;
93 private double sumTotalCpuUsage;
94 private long[] cpuFreqMax;
71 private int cpusPresent; 95 private int cpusPresent;
72 private double lastPercentFreq = -1; 96 private int actualCpusPresent;
73 private int cpuCurrent;
74 private int cpuAvg3;
75 private int cpuAvgAll;
76 private boolean initialized = false; 97 private boolean initialized = false;
77 private String[] maxPath; 98 private String[] maxPath;
78 private String[] curPath; 99 private String[] curPath;
79 ProcStat lastProcStat; 100 private double[] curFreqScales;
101 private ProcStat lastProcStat;
102
103 private static boolean dumpEnabled = false;
104 private static FileOutputStream fileWriter;
80 105
81 private class ProcStat { 106 private class ProcStat {
82 final long runTime; 107 final long userTime;
108 final long systemTime;
83 final long idleTime; 109 final long idleTime;
84 110
85 ProcStat(long aRunTime, long aIdleTime) { 111 ProcStat(long userTime, long systemTime, long idleTime) {
86 runTime = aRunTime; 112 this.userTime = userTime;
87 idleTime = aIdleTime; 113 this.systemTime = systemTime;
114 this.idleTime = idleTime;
88 } 115 }
89 } 116 }
90 117
118 public CpuMonitor(Context context) {
119 Log.d(TAG, "CpuMonitor ctor.");
120 appContext = context.getApplicationContext();
121 lastStatLogTimeMs = 0;
122
123 executor = new LooperExecutor();
124 executor.requestStart();
125 scheduleCpuUtilizationTask();
126 }
127
128 public void release() {
129 if (executor != null) {
130 Log.d(TAG, "release");
131 executor.cancelScheduledTasks();
132 executor.requestStop();
133 executor = null;
134 }
135 }
136
137 public void pause() {
138 if (executor != null) {
139 Log.d(TAG, "pause");
140 executor.cancelScheduledTasks();
141 }
142 }
143
144 public void resume() {
145 if (executor != null) {
146 Log.d(TAG, "resume");
147 resetStat();
148 scheduleCpuUtilizationTask();
149 }
150 }
151
152 public synchronized int getCpuUsageCurrent() {
153 return doubleToPercent(currentTotalCpuUsage);
154 }
155
156 public synchronized int getCpuUsageAverage() {
157 return sumDoubleToPercent(sumTotalCpuUsage, iterations);
158 }
159
160 public synchronized int getCpuFrequencyScaleCurrent() {
161 return doubleToPercent(currentFrequencyScale);
162 }
163
164 private void scheduleCpuUtilizationTask() {
165 executor.scheduleAtFixedRate(new Runnable() {
166 @Override
167 public void run() {
168 logCpuUtilization();
169 }
170 }, CPU_STAT_SAMPLE_PERIOD);
171 }
172
173 private void checkDump(String statString) {
174 if (!dumpEnabled) {
175 return;
176 }
177 if (fileWriter == null) {
178 Log.d(TAG, "Start log dump");
179 String fileName = Environment.getExternalStorageDirectory().getAbsolutePat h()
180 + File.separator + DUMP_FILE;
181 try {
182 fileWriter = new FileOutputStream(fileName, false /* append */);
183 } catch (FileNotFoundException e) {
184 Log.e(TAG, "Can not open file.", e);
185 dumpEnabled = false;
186 return;
187 }
188 }
189
190 Date date = Calendar.getInstance().getTime();
191 SimpleDateFormat df = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
192 String msg = df.format(date) + " " + TAG + ":" + statString + "\n";
193 try {
194 fileWriter.write(msg.getBytes());
195 } catch (IOException e) {
196 Log.e(TAG, "Can not write to file.", e);
197 dumpEnabled = false;
198 }
199 }
200
201 private void logCpuUtilization() {
202 boolean logStatistics = false;
203 if (SystemClock.elapsedRealtime() - lastStatLogTimeMs >= CPU_STAT_LOG_PERIOD ) {
204 lastStatLogTimeMs = SystemClock.elapsedRealtime();
205 logStatistics = true;
206 }
207 boolean cpuMonitorAvailable = sampleCpuUtilization();
208 if (logStatistics && cpuMonitorAvailable) {
209 String statString = getStatString();
210 checkDump(statString);
211 Log.d(TAG, statString);
212 resetStat();
213 }
214 }
215
91 private void init() { 216 private void init() {
92 try { 217 try {
93 FileReader fin = new FileReader("/sys/devices/system/cpu/present"); 218 FileReader fin = new FileReader("/sys/devices/system/cpu/present");
94 try { 219 try {
95 BufferedReader rdr = new BufferedReader(fin); 220 BufferedReader reader = new BufferedReader(fin);
96 Scanner scanner = new Scanner(rdr).useDelimiter("[-\n]"); 221 Scanner scanner = new Scanner(reader).useDelimiter("[-\n]");
97 scanner.nextInt(); // Skip leading number 0. 222 scanner.nextInt(); // Skip leading number 0.
98 cpusPresent = 1 + scanner.nextInt(); 223 cpusPresent = 1 + scanner.nextInt();
99 scanner.close(); 224 scanner.close();
100 } catch (Exception e) { 225 } catch (Exception e) {
101 Log.e(TAG, "Cannot do CPU stats due to /sys/devices/system/cpu/present p arsing problem"); 226 Log.e(TAG, "Cannot do CPU stats due to /sys/devices/system/cpu/present p arsing problem");
102 } finally { 227 } finally {
103 fin.close(); 228 fin.close();
104 } 229 }
105 } catch (FileNotFoundException e) { 230 } catch (FileNotFoundException e) {
106 Log.e(TAG, "Cannot do CPU stats since /sys/devices/system/cpu/present is m issing"); 231 Log.e(TAG, "Cannot do CPU stats since /sys/devices/system/cpu/present is m issing");
107 } catch (IOException e) { 232 } catch (IOException e) {
108 Log.e(TAG, "Error closing file"); 233 Log.e(TAG, "Error closing file");
109 } 234 }
110 235
111 cpuFreq = new long [cpusPresent]; 236 cpuFreqMax = new long[cpusPresent];
112 maxPath = new String [cpusPresent]; 237 maxPath = new String[cpusPresent];
113 curPath = new String [cpusPresent]; 238 curPath = new String[cpusPresent];
239 curFreqScales = new double[cpusPresent];
114 for (int i = 0; i < cpusPresent; i++) { 240 for (int i = 0; i < cpusPresent; i++) {
115 cpuFreq[i] = 0; // Frequency "not yet determined". 241 cpuFreqMax[i] = 0; // Frequency "not yet determined".
242 curFreqScales[i] = 0;
116 maxPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_fre q"; 243 maxPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_fre q";
117 curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_fre q"; 244 curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_fre q";
118 } 245 }
119 246
120 lastProcStat = new ProcStat(0, 0); 247 lastProcStat = new ProcStat(0, 0, 0);
248 resetStat();
121 249
122 initialized = true; 250 initialized = true;
123 } 251 }
124 252
253 private synchronized void resetStat() {
254 sumUserCpuUsage = 0;
255 sumSystemCpuUsage = 0;
256 sumFrequencyScale = 0;
257 sumTotalCpuUsage = 0;
258 iterations = 0;
259 }
260
261 private int getBatteryLevel() {
262 // Use sticky broadcast with null receiver to read battery level once only.
263 Intent intent = appContext.registerReceiver(
264 null /* receiver */, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
265
266 int batteryLevel = 0;
267 int batteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
268 if (batteryScale > 0) {
269 batteryLevel = (int) (
270 100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / batteryScal e);
271 }
272 return batteryLevel;
273 }
274
125 /** 275 /**
126 * Re-measure CPU use. Call this method at an interval of around 1/s. 276 * Re-measure CPU use. Call this method at an interval of around 1/s.
127 * This method returns true on success. The fields 277 * This method returns true on success. The fields
128 * cpuCurrent, cpuAvg3, and cpuAvgAll are updated on success, and represents: 278 * cpuCurrent, cpuAvg3, and cpuAvgAll are updated on success, and represents:
129 * cpuCurrent: The CPU use since the last sampleCpuUtilization call. 279 * cpuCurrent: The CPU use since the last sampleCpuUtilization call.
130 * cpuAvg3: The average CPU over the last 3 calls. 280 * cpuAvg3: The average CPU over the last 3 calls.
131 * cpuAvgAll: The average CPU over the last SAMPLE_SAVE_NUMBER calls. 281 * cpuAvgAll: The average CPU over the last SAMPLE_SAVE_NUMBER calls.
132 */ 282 */
133 public boolean sampleCpuUtilization() { 283 private synchronized boolean sampleCpuUtilization() {
134 long lastSeenMaxFreq = 0; 284 long lastSeenMaxFreq = 0;
135 long cpufreqCurSum = 0; 285 long cpuFreqCurSum = 0;
136 long cpufreqMaxSum = 0; 286 long cpuFreqMaxSum = 0;
137 287
138 if (!initialized) { 288 if (!initialized) {
139 init(); 289 init();
140 } 290 }
291 if (cpusPresent == 0) {
292 return false;
293 }
141 294
295 actualCpusPresent = 0;
142 for (int i = 0; i < cpusPresent; i++) { 296 for (int i = 0; i < cpusPresent; i++) {
143 /* 297 /*
144 * For each CPU, attempt to first read its max frequency, then its 298 * For each CPU, attempt to first read its max frequency, then its
145 * current frequency. Once as the max frequency for a CPU is found, 299 * current frequency. Once as the max frequency for a CPU is found,
146 * save it in cpuFreq[]. 300 * save it in cpuFreqMax[].
147 */ 301 */
148 302
149 if (cpuFreq[i] == 0) { 303 curFreqScales[i] = 0;
304 if (cpuFreqMax[i] == 0) {
150 // We have never found this CPU's max frequency. Attempt to read it. 305 // We have never found this CPU's max frequency. Attempt to read it.
151 long cpufreqMax = readFreqFromFile(maxPath[i]); 306 long cpufreqMax = readFreqFromFile(maxPath[i]);
152 if (cpufreqMax > 0) { 307 if (cpufreqMax > 0) {
153 lastSeenMaxFreq = cpufreqMax; 308 lastSeenMaxFreq = cpufreqMax;
154 cpuFreq[i] = cpufreqMax; 309 cpuFreqMax[i] = cpufreqMax;
155 maxPath[i] = null; // Kill path to free its memory. 310 maxPath[i] = null; // Kill path to free its memory.
156 } 311 }
157 } else { 312 } else {
158 lastSeenMaxFreq = cpuFreq[i]; // A valid, previously read value. 313 lastSeenMaxFreq = cpuFreqMax[i]; // A valid, previously read value.
159 } 314 }
160 315
161 long cpufreqCur = readFreqFromFile(curPath[i]); 316 long cpuFreqCur = readFreqFromFile(curPath[i]);
162 cpufreqCurSum += cpufreqCur; 317 if (cpuFreqCur == 0 && lastSeenMaxFreq == 0) {
318 // No current frequency information for this CPU core - ignore it.
319 continue;
320 }
321 if (cpuFreqCur > 0) {
322 actualCpusPresent++;
323 }
324 cpuFreqCurSum += cpuFreqCur;
163 325
164 /* Here, lastSeenMaxFreq might come from 326 /* Here, lastSeenMaxFreq might come from
165 * 1. cpuFreq[i], or 327 * 1. cpuFreq[i], or
166 * 2. a previous iteration, or 328 * 2. a previous iteration, or
167 * 3. a newly read value, or 329 * 3. a newly read value, or
168 * 4. hypothetically from the pre-loop dummy. 330 * 4. hypothetically from the pre-loop dummy.
169 */ 331 */
170 cpufreqMaxSum += lastSeenMaxFreq; 332 cpuFreqMaxSum += lastSeenMaxFreq;
333 if (lastSeenMaxFreq > 0) {
334 curFreqScales[i] = (double) cpuFreqCur / lastSeenMaxFreq;
335 }
171 } 336 }
172 337
173 if (cpufreqMaxSum == 0) { 338 if (cpuFreqCurSum == 0 || cpuFreqMaxSum == 0) {
174 Log.e(TAG, "Could not read max frequency for any CPU"); 339 Log.e(TAG, "Could not read max or current frequency for any CPU");
175 return false; 340 return false;
176 } 341 }
177 342
178 /* 343 /*
179 * Since the cycle counts are for the period between the last invocation 344 * Since the cycle counts are for the period between the last invocation
180 * and this present one, we average the percentual CPU frequencies between 345 * and this present one, we average the percentual CPU frequencies between
181 * now and the beginning of the measurement period. This is significantly 346 * now and the beginning of the measurement period. This is significantly
182 * incorrect only if the frequencies have peeked or dropped in between the 347 * incorrect only if the frequencies have peeked or dropped in between the
183 * invocations. 348 * invocations.
184 */ 349 */
185 double newPercentFreq = 100.0 * cpufreqCurSum / cpufreqMaxSum; 350 double newFrequencyScale = (double) cpuFreqCurSum / cpuFreqMaxSum;
186 double percentFreq; 351 double frequencyScale;
187 if (lastPercentFreq > 0) { 352 if (currentFrequencyScale > 0) {
188 percentFreq = (lastPercentFreq + newPercentFreq) * 0.5; 353 frequencyScale = (currentFrequencyScale + newFrequencyScale) * 0.5;
189 } else { 354 } else {
190 percentFreq = newPercentFreq; 355 frequencyScale = newFrequencyScale;
191 } 356 }
192 lastPercentFreq = newPercentFreq;
193 357
194 ProcStat procStat = readIdleAndRunTime(); 358 ProcStat procStat = readProcStat();
195 if (procStat == null) { 359 if (procStat == null) {
196 return false; 360 return false;
197 } 361 }
198 362
199 long diffRunTime = procStat.runTime - lastProcStat.runTime; 363 long diffUserTime = procStat.userTime - lastProcStat.userTime;
364 long diffSystemTime = procStat.systemTime - lastProcStat.systemTime;
200 long diffIdleTime = procStat.idleTime - lastProcStat.idleTime; 365 long diffIdleTime = procStat.idleTime - lastProcStat.idleTime;
366 long allTime = diffUserTime + diffSystemTime + diffIdleTime;
201 367
368 if (frequencyScale == 0 || allTime == 0) {
369 return false;
370 }
371
372 // Update statistics.
373 currentFrequencyScale = frequencyScale;
374 sumFrequencyScale += frequencyScale;
375
376 currentUserCpuUsage = (double) diffUserTime / allTime;
377 sumUserCpuUsage += currentUserCpuUsage;
378
379 currentSystemCpuUsage = (double) diffSystemTime / allTime;
380 sumSystemCpuUsage += currentSystemCpuUsage;
381
382 currentTotalCpuUsage = (currentUserCpuUsage + currentSystemCpuUsage) * curre ntFrequencyScale;
383 sumTotalCpuUsage += currentTotalCpuUsage;
384
385 iterations++;
202 // Save new measurements for next round's deltas. 386 // Save new measurements for next round's deltas.
203 lastProcStat = procStat; 387 lastProcStat = procStat;
204 388
205 long allTime = diffRunTime + diffIdleTime;
206 int percent = allTime == 0 ? 0 : (int) Math.round(percentFreq * diffRunTime / allTime);
207 percent = Math.max(0, Math.min(percent, 100));
208
209 // Subtract old relevant measurement, add newest.
210 sum3 += percent - percentVec[2];
211 // Subtract oldest measurement, add newest.
212 sum10 += percent - percentVec[SAMPLE_SAVE_NUMBER - 1];
213
214 // Rotate saved percent values, save new measurement in vacated spot.
215 for (int i = SAMPLE_SAVE_NUMBER - 1; i > 0; i--) {
216 percentVec[i] = percentVec[i - 1];
217 }
218 percentVec[0] = percent;
219
220 cpuCurrent = percent;
221 cpuAvg3 = sum3 / 3;
222 cpuAvgAll = sum10 / SAMPLE_SAVE_NUMBER;
223
224 return true; 389 return true;
225 } 390 }
226 391
227 public int getCpuCurrent() { 392 private int doubleToPercent(double d) {
228 return cpuCurrent; 393 return (int) (d * 100 + 0.5);
229 } 394 }
230 395
231 public int getCpuAvg3() { 396 private int sumDoubleToPercent(double d, int iterations) {
232 return cpuAvg3; 397 if (iterations > 0) {
398 return (int) (d * 100.0 / (double) iterations + 0.5);
399 } else {
400 return 0;
401 }
233 } 402 }
234 403
235 public int getCpuAvgAll() { 404 private String getStatString() {
236 return cpuAvgAll; 405 StringBuilder stat = new StringBuilder();
406 stat.append("CPU User: ")
407 .append(doubleToPercent(currentUserCpuUsage)).append("/")
408 .append(sumDoubleToPercent(sumUserCpuUsage, iterations)).append(" (")
409 .append(doubleToPercent(currentUserCpuUsage * currentFrequencyScale)).ap pend(")")
410 .append(". System: ")
411 .append(doubleToPercent(currentSystemCpuUsage)).append("/")
412 .append(sumDoubleToPercent(sumSystemCpuUsage, iterations)).append(" (")
413 .append(doubleToPercent(currentSystemCpuUsage * currentFrequencyScale)). append(")")
414 .append(". CPU freq %: ")
415 .append(doubleToPercent(currentFrequencyScale)).append("/")
416 .append(sumDoubleToPercent(sumFrequencyScale, iterations))
417 .append(". Total CPU usage: ")
418 .append(doubleToPercent(currentTotalCpuUsage)).append("/")
419 .append(sumDoubleToPercent(sumTotalCpuUsage, iterations))
420 .append(". Cores: ")
421 .append(actualCpusPresent);
422 stat.append("( ");
423 for (int i = 0; i < cpusPresent; i++) {
424 stat.append(doubleToPercent(curFreqScales[i])).append(" ");
425 }
426 stat.append("). Battery %: ")
427 .append(getBatteryLevel());
428 return stat.toString();
237 } 429 }
238 430
239 /** 431 /**
240 * Read a single integer value from the named file. Return the read value 432 * Read a single integer value from the named file. Return the read value
241 * or if an error occurs return 0. 433 * or if an error occurs return 0.
242 */ 434 */
243 private long readFreqFromFile(String fileName) { 435 private long readFreqFromFile(String fileName) {
244 long number = 0; 436 long number = 0;
245 try { 437 try {
246 FileReader fin = new FileReader(fileName); 438 FileReader fin = new FileReader(fileName);
(...skipping 12 matching lines...) Expand all
259 } catch (IOException e) { 451 } catch (IOException e) {
260 Log.e(TAG, "Error closing file"); 452 Log.e(TAG, "Error closing file");
261 } 453 }
262 return number; 454 return number;
263 } 455 }
264 456
265 /* 457 /*
266 * Read the current utilization of all CPUs using the cumulative first line 458 * Read the current utilization of all CPUs using the cumulative first line
267 * of /proc/stat. 459 * of /proc/stat.
268 */ 460 */
269 private ProcStat readIdleAndRunTime() { 461 private ProcStat readProcStat() {
270 long runTime = 0; 462 long userTime = 0;
463 long systemTime = 0;
271 long idleTime = 0; 464 long idleTime = 0;
272 try { 465 try {
273 FileReader fin = new FileReader("/proc/stat"); 466 FileReader fin = new FileReader("/proc/stat");
274 try { 467 try {
275 BufferedReader rdr = new BufferedReader(fin); 468 BufferedReader rdr = new BufferedReader(fin);
276 Scanner scanner = new Scanner(rdr); 469 Scanner scanner = new Scanner(rdr);
277 scanner.next(); 470 scanner.next();
278 long user = scanner.nextLong(); 471 userTime = scanner.nextLong();
279 long nice = scanner.nextLong(); 472 long nice = scanner.nextLong();
280 long sys = scanner.nextLong(); 473 userTime += nice;
281 runTime = user + nice + sys; 474 systemTime = scanner.nextLong();
282 idleTime = scanner.nextLong(); 475 idleTime = scanner.nextLong();
476 long ioWaitTime = scanner.nextLong();
477 userTime += ioWaitTime;
283 scanner.close(); 478 scanner.close();
284 } catch (Exception e) { 479 } catch (Exception e) {
285 Log.e(TAG, "Problems parsing /proc/stat"); 480 Log.e(TAG, "Problems parsing /proc/stat");
286 return null; 481 return null;
287 } finally { 482 } finally {
288 fin.close(); 483 fin.close();
289 } 484 }
290 } catch (FileNotFoundException e) { 485 } catch (FileNotFoundException e) {
291 Log.e(TAG, "Cannot open /proc/stat for reading"); 486 Log.e(TAG, "Cannot open /proc/stat for reading");
292 return null; 487 return null;
293 } catch (IOException e) { 488 } catch (IOException e) {
294 Log.e(TAG, "Problems reading /proc/stat"); 489 Log.e(TAG, "Problems reading /proc/stat");
295 return null; 490 return null;
296 } 491 }
297 return new ProcStat(runTime, idleTime); 492 return new ProcStat(userTime, systemTime, idleTime);
298 } 493 }
299 } 494 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698