OLD | NEW |
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; | 13 import android.content.Context; |
14 import android.content.Intent; | 14 import android.content.Intent; |
15 import android.content.IntentFilter; | 15 import android.content.IntentFilter; |
16 import android.os.BatteryManager; | 16 import android.os.BatteryManager; |
17 import android.os.Environment; | |
18 import android.os.SystemClock; | 17 import android.os.SystemClock; |
19 import android.util.Log; | 18 import android.util.Log; |
20 | 19 |
21 import java.io.BufferedReader; | 20 import java.io.BufferedReader; |
22 import java.io.File; | |
23 import java.io.FileNotFoundException; | 21 import java.io.FileNotFoundException; |
24 import java.io.FileOutputStream; | |
25 import java.io.FileReader; | 22 import java.io.FileReader; |
26 import java.io.IOException; | 23 import java.io.IOException; |
27 import java.text.SimpleDateFormat; | 24 import java.util.Arrays; |
28 import java.util.Calendar; | |
29 import java.util.Date; | |
30 import java.util.Scanner; | 25 import java.util.Scanner; |
31 | 26 |
32 import org.appspot.apprtc.util.LooperExecutor; | 27 import org.appspot.apprtc.util.LooperExecutor; |
33 | 28 |
34 /** | 29 /** |
35 * Simple CPU monitor. The caller creates a CpuMonitor object which can then | 30 * Simple CPU monitor. The caller creates a CpuMonitor object which can then |
36 * be used via sampleCpuUtilization() to collect the percentual use of the | 31 * be used via sampleCpuUtilization() to collect the percentual use of the |
37 * cumulative CPU capacity for all CPUs running at their nominal frequency. 3 | 32 * cumulative CPU capacity for all CPUs running at their nominal frequency. 3 |
38 * values are generated: (1) getCpuCurrent() returns the use since the last | 33 * values are generated: (1) getCpuCurrent() returns the use since the last |
39 * sampleCpuUtilization(), (2) getCpuAvg3() returns the use since 3 prior | 34 * sampleCpuUtilization(), (2) getCpuAvg3() returns the use since 3 prior |
(...skipping 28 matching lines...) Expand all Loading... |
68 * | 63 * |
69 * <p>Known problems: | 64 * <p>Known problems: |
70 * 1. Nexus 7 devices running Kitkat have a kernel which often output an | 65 * 1. Nexus 7 devices running Kitkat have a kernel which often output an |
71 * incorrect 'idle' field in /proc/stat. The value is close to twice the | 66 * incorrect 'idle' field in /proc/stat. The value is close to twice the |
72 * correct value, and then returns to back to correct reading. Both when | 67 * correct value, and then returns to back to correct reading. Both when |
73 * jumping up and back down we might create faulty CPU load readings. | 68 * jumping up and back down we might create faulty CPU load readings. |
74 */ | 69 */ |
75 | 70 |
76 class CpuMonitor { | 71 class CpuMonitor { |
77 private static final String TAG = "CpuMonitor"; | 72 private static final String TAG = "CpuMonitor"; |
78 private static final String DUMP_FILE = "cpu_log.txt"; | 73 private static final int MOVING_AVERAGE_SAMPLES = 10; |
79 private static final int CPU_STAT_SAMPLE_PERIOD = 2000; | 74 |
80 private static final int CPU_STAT_LOG_PERIOD = 6000; | 75 private static final int CPU_STAT_SAMPLE_PERIOD_MS = 1000; |
| 76 private static final int CPU_STAT_LOG_PERIOD_MS = 5000; |
81 | 77 |
82 private final Context appContext; | 78 private final Context appContext; |
| 79 // User CPU usage at current frequency. |
| 80 private final MovingAverage userCpuUsage; |
| 81 // System CPU usage at current frequency. |
| 82 private final MovingAverage systemCpuUsage; |
| 83 // Total CPU usage relative to maximum frequency. |
| 84 private final MovingAverage totalCpuUsage; |
| 85 // CPU frequency in percentage from maximum. |
| 86 private final MovingAverage frequencyScale; |
| 87 |
83 private LooperExecutor executor; | 88 private LooperExecutor executor; |
84 private long lastStatLogTimeMs; | 89 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; | 90 private long[] cpuFreqMax; |
95 private int cpusPresent; | 91 private int cpusPresent; |
96 private int actualCpusPresent; | 92 private int actualCpusPresent; |
97 private boolean initialized = false; | 93 private boolean initialized; |
| 94 private boolean cpuOveruse; |
98 private String[] maxPath; | 95 private String[] maxPath; |
99 private String[] curPath; | 96 private String[] curPath; |
100 private double[] curFreqScales; | 97 private double[] curFreqScales; |
101 private ProcStat lastProcStat; | 98 private ProcStat lastProcStat; |
102 | 99 |
103 private static boolean dumpEnabled = false; | 100 private static class ProcStat { |
104 private static FileOutputStream fileWriter; | |
105 | |
106 private class ProcStat { | |
107 final long userTime; | 101 final long userTime; |
108 final long systemTime; | 102 final long systemTime; |
109 final long idleTime; | 103 final long idleTime; |
110 | 104 |
111 ProcStat(long userTime, long systemTime, long idleTime) { | 105 ProcStat(long userTime, long systemTime, long idleTime) { |
112 this.userTime = userTime; | 106 this.userTime = userTime; |
113 this.systemTime = systemTime; | 107 this.systemTime = systemTime; |
114 this.idleTime = idleTime; | 108 this.idleTime = idleTime; |
115 } | 109 } |
116 } | 110 } |
117 | 111 |
| 112 private static class MovingAverage { |
| 113 private final int size; |
| 114 private double sum; |
| 115 private double currentValue; |
| 116 private double circBuffer[]; |
| 117 private int circBufferIndex; |
| 118 |
| 119 public MovingAverage(int size) { |
| 120 if (size <= 0) { |
| 121 throw new AssertionError("Size value in MovingAverage ctor should be pos
itive."); |
| 122 } |
| 123 this.size = size; |
| 124 circBuffer = new double[size]; |
| 125 } |
| 126 |
| 127 public void reset() { |
| 128 Arrays.fill(circBuffer, 0); |
| 129 circBufferIndex = 0; |
| 130 sum = 0; |
| 131 currentValue = 0; |
| 132 } |
| 133 |
| 134 public void addValue(double value) { |
| 135 sum -= circBuffer[circBufferIndex]; |
| 136 circBuffer[circBufferIndex++] = value; |
| 137 currentValue = value; |
| 138 sum += value; |
| 139 if (circBufferIndex >= size) { |
| 140 circBufferIndex = 0; |
| 141 } |
| 142 } |
| 143 |
| 144 public double getCurrent() { |
| 145 return currentValue; |
| 146 } |
| 147 |
| 148 public double getAverage() { |
| 149 return sum / (double) size; |
| 150 } |
| 151 } |
| 152 |
118 public CpuMonitor(Context context) { | 153 public CpuMonitor(Context context) { |
119 Log.d(TAG, "CpuMonitor ctor."); | 154 Log.d(TAG, "CpuMonitor ctor."); |
120 appContext = context.getApplicationContext(); | 155 appContext = context.getApplicationContext(); |
121 lastStatLogTimeMs = 0; | 156 userCpuUsage = new MovingAverage(MOVING_AVERAGE_SAMPLES); |
| 157 systemCpuUsage = new MovingAverage(MOVING_AVERAGE_SAMPLES); |
| 158 totalCpuUsage = new MovingAverage(MOVING_AVERAGE_SAMPLES); |
| 159 frequencyScale = new MovingAverage(MOVING_AVERAGE_SAMPLES); |
| 160 lastStatLogTimeMs = SystemClock.elapsedRealtime(); |
122 | 161 |
123 executor = new LooperExecutor(); | 162 executor = new LooperExecutor(); |
124 executor.requestStart(); | 163 executor.requestStart(); |
125 scheduleCpuUtilizationTask(); | 164 scheduleCpuUtilizationTask(); |
126 } | 165 } |
127 | 166 |
128 public void release() { | 167 public void release() { |
129 if (executor != null) { | 168 if (executor != null) { |
130 Log.d(TAG, "release"); | 169 Log.d(TAG, "release"); |
131 executor.cancelScheduledTasks(); | 170 executor.cancelScheduledTasks(); |
(...skipping 10 matching lines...) Expand all Loading... |
142 } | 181 } |
143 | 182 |
144 public void resume() { | 183 public void resume() { |
145 if (executor != null) { | 184 if (executor != null) { |
146 Log.d(TAG, "resume"); | 185 Log.d(TAG, "resume"); |
147 resetStat(); | 186 resetStat(); |
148 scheduleCpuUtilizationTask(); | 187 scheduleCpuUtilizationTask(); |
149 } | 188 } |
150 } | 189 } |
151 | 190 |
| 191 public synchronized void reset() { |
| 192 if (executor != null) { |
| 193 Log.d(TAG, "reset"); |
| 194 resetStat(); |
| 195 cpuOveruse = false; |
| 196 } |
| 197 } |
| 198 |
152 public synchronized int getCpuUsageCurrent() { | 199 public synchronized int getCpuUsageCurrent() { |
153 return doubleToPercent(currentTotalCpuUsage); | 200 return doubleToPercent(userCpuUsage.getCurrent() + systemCpuUsage.getCurrent
()); |
154 } | 201 } |
155 | 202 |
156 public synchronized int getCpuUsageAverage() { | 203 public synchronized int getCpuUsageAverage() { |
157 return sumDoubleToPercent(sumTotalCpuUsage, iterations); | 204 return doubleToPercent(userCpuUsage.getAverage() + systemCpuUsage.getAverage
()); |
158 } | 205 } |
159 | 206 |
160 public synchronized int getCpuFrequencyScaleCurrent() { | 207 public synchronized int getFrequencyScaleAverage() { |
161 return doubleToPercent(currentFrequencyScale); | 208 return doubleToPercent(frequencyScale.getAverage()); |
162 } | 209 } |
163 | 210 |
164 private void scheduleCpuUtilizationTask() { | 211 private void scheduleCpuUtilizationTask() { |
165 executor.scheduleAtFixedRate(new Runnable() { | 212 executor.scheduleAtFixedRate(new Runnable() { |
166 @Override | 213 @Override |
167 public void run() { | 214 public void run() { |
168 logCpuUtilization(); | 215 cpuUtilizationTask(); |
169 } | 216 } |
170 }, CPU_STAT_SAMPLE_PERIOD); | 217 }, CPU_STAT_SAMPLE_PERIOD_MS); |
171 } | 218 } |
172 | 219 |
173 private void checkDump(String statString) { | 220 private void cpuUtilizationTask() { |
174 if (!dumpEnabled) { | 221 boolean cpuMonitorAvailable = sampleCpuUtilization(); |
175 return; | 222 if (cpuMonitorAvailable |
176 } | 223 && SystemClock.elapsedRealtime() - lastStatLogTimeMs >= CPU_STAT_LOG_PER
IOD_MS) { |
177 if (fileWriter == null) { | 224 lastStatLogTimeMs = SystemClock.elapsedRealtime(); |
178 Log.d(TAG, "Start log dump"); | 225 String statString = getStatString(); |
179 String fileName = Environment.getExternalStorageDirectory().getAbsolutePat
h() | 226 Log.d(TAG, statString); |
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 } | 227 } |
199 } | 228 } |
200 | 229 |
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 | |
216 private void init() { | 230 private void init() { |
217 try { | 231 try { |
218 FileReader fin = new FileReader("/sys/devices/system/cpu/present"); | 232 FileReader fin = new FileReader("/sys/devices/system/cpu/present"); |
219 try { | 233 try { |
220 BufferedReader reader = new BufferedReader(fin); | 234 BufferedReader reader = new BufferedReader(fin); |
221 Scanner scanner = new Scanner(reader).useDelimiter("[-\n]"); | 235 Scanner scanner = new Scanner(reader).useDelimiter("[-\n]"); |
222 scanner.nextInt(); // Skip leading number 0. | 236 scanner.nextInt(); // Skip leading number 0. |
223 cpusPresent = 1 + scanner.nextInt(); | 237 cpusPresent = 1 + scanner.nextInt(); |
224 scanner.close(); | 238 scanner.close(); |
225 } catch (Exception e) { | 239 } catch (Exception e) { |
(...skipping 18 matching lines...) Expand all Loading... |
244 curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_fre
q"; | 258 curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_fre
q"; |
245 } | 259 } |
246 | 260 |
247 lastProcStat = new ProcStat(0, 0, 0); | 261 lastProcStat = new ProcStat(0, 0, 0); |
248 resetStat(); | 262 resetStat(); |
249 | 263 |
250 initialized = true; | 264 initialized = true; |
251 } | 265 } |
252 | 266 |
253 private synchronized void resetStat() { | 267 private synchronized void resetStat() { |
254 sumUserCpuUsage = 0; | 268 userCpuUsage.reset(); |
255 sumSystemCpuUsage = 0; | 269 systemCpuUsage.reset(); |
256 sumFrequencyScale = 0; | 270 totalCpuUsage.reset(); |
257 sumTotalCpuUsage = 0; | 271 frequencyScale.reset(); |
258 iterations = 0; | 272 lastStatLogTimeMs = SystemClock.elapsedRealtime(); |
259 } | 273 } |
260 | 274 |
261 private int getBatteryLevel() { | 275 private int getBatteryLevel() { |
262 // Use sticky broadcast with null receiver to read battery level once only. | 276 // Use sticky broadcast with null receiver to read battery level once only. |
263 Intent intent = appContext.registerReceiver( | 277 Intent intent = appContext.registerReceiver( |
264 null /* receiver */, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); | 278 null /* receiver */, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); |
265 | 279 |
266 int batteryLevel = 0; | 280 int batteryLevel = 0; |
267 int batteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); | 281 int batteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); |
268 if (batteryScale > 0) { | 282 if (batteryScale > 0) { |
(...skipping 29 matching lines...) Expand all Loading... |
298 * For each CPU, attempt to first read its max frequency, then its | 312 * For each CPU, attempt to first read its max frequency, then its |
299 * current frequency. Once as the max frequency for a CPU is found, | 313 * current frequency. Once as the max frequency for a CPU is found, |
300 * save it in cpuFreqMax[]. | 314 * save it in cpuFreqMax[]. |
301 */ | 315 */ |
302 | 316 |
303 curFreqScales[i] = 0; | 317 curFreqScales[i] = 0; |
304 if (cpuFreqMax[i] == 0) { | 318 if (cpuFreqMax[i] == 0) { |
305 // We have never found this CPU's max frequency. Attempt to read it. | 319 // We have never found this CPU's max frequency. Attempt to read it. |
306 long cpufreqMax = readFreqFromFile(maxPath[i]); | 320 long cpufreqMax = readFreqFromFile(maxPath[i]); |
307 if (cpufreqMax > 0) { | 321 if (cpufreqMax > 0) { |
| 322 Log.d(TAG, "Core " + i + ". Max frequency: " + cpufreqMax); |
308 lastSeenMaxFreq = cpufreqMax; | 323 lastSeenMaxFreq = cpufreqMax; |
309 cpuFreqMax[i] = cpufreqMax; | 324 cpuFreqMax[i] = cpufreqMax; |
310 maxPath[i] = null; // Kill path to free its memory. | 325 maxPath[i] = null; // Kill path to free its memory. |
311 } | 326 } |
312 } else { | 327 } else { |
313 lastSeenMaxFreq = cpuFreqMax[i]; // A valid, previously read value. | 328 lastSeenMaxFreq = cpuFreqMax[i]; // A valid, previously read value. |
314 } | 329 } |
315 | 330 |
316 long cpuFreqCur = readFreqFromFile(curPath[i]); | 331 long cpuFreqCur = readFreqFromFile(curPath[i]); |
317 if (cpuFreqCur == 0 && lastSeenMaxFreq == 0) { | 332 if (cpuFreqCur == 0 && lastSeenMaxFreq == 0) { |
(...skipping 22 matching lines...) Expand all Loading... |
340 return false; | 355 return false; |
341 } | 356 } |
342 | 357 |
343 /* | 358 /* |
344 * Since the cycle counts are for the period between the last invocation | 359 * Since the cycle counts are for the period between the last invocation |
345 * and this present one, we average the percentual CPU frequencies between | 360 * and this present one, we average the percentual CPU frequencies between |
346 * now and the beginning of the measurement period. This is significantly | 361 * now and the beginning of the measurement period. This is significantly |
347 * incorrect only if the frequencies have peeked or dropped in between the | 362 * incorrect only if the frequencies have peeked or dropped in between the |
348 * invocations. | 363 * invocations. |
349 */ | 364 */ |
350 double newFrequencyScale = (double) cpuFreqCurSum / cpuFreqMaxSum; | 365 double currentFrequencyScale = cpuFreqCurSum / (double) cpuFreqMaxSum; |
351 double frequencyScale; | 366 if (frequencyScale.getCurrent() > 0) { |
352 if (currentFrequencyScale > 0) { | 367 currentFrequencyScale = (frequencyScale.getCurrent() + currentFrequencySca
le) * 0.5; |
353 frequencyScale = (currentFrequencyScale + newFrequencyScale) * 0.5; | |
354 } else { | |
355 frequencyScale = newFrequencyScale; | |
356 } | 368 } |
357 | 369 |
358 ProcStat procStat = readProcStat(); | 370 ProcStat procStat = readProcStat(); |
359 if (procStat == null) { | 371 if (procStat == null) { |
360 return false; | 372 return false; |
361 } | 373 } |
362 | 374 |
363 long diffUserTime = procStat.userTime - lastProcStat.userTime; | 375 long diffUserTime = procStat.userTime - lastProcStat.userTime; |
364 long diffSystemTime = procStat.systemTime - lastProcStat.systemTime; | 376 long diffSystemTime = procStat.systemTime - lastProcStat.systemTime; |
365 long diffIdleTime = procStat.idleTime - lastProcStat.idleTime; | 377 long diffIdleTime = procStat.idleTime - lastProcStat.idleTime; |
366 long allTime = diffUserTime + diffSystemTime + diffIdleTime; | 378 long allTime = diffUserTime + diffSystemTime + diffIdleTime; |
367 | 379 |
368 if (frequencyScale == 0 || allTime == 0) { | 380 if (currentFrequencyScale == 0 || allTime == 0) { |
369 return false; | 381 return false; |
370 } | 382 } |
371 | 383 |
372 // Update statistics. | 384 // Update statistics. |
373 currentFrequencyScale = frequencyScale; | 385 frequencyScale.addValue(currentFrequencyScale); |
374 sumFrequencyScale += frequencyScale; | |
375 | 386 |
376 currentUserCpuUsage = (double) diffUserTime / allTime; | 387 double currentUserCpuUsage = diffUserTime / (double) allTime; |
377 sumUserCpuUsage += currentUserCpuUsage; | 388 userCpuUsage.addValue(currentUserCpuUsage); |
378 | 389 |
379 currentSystemCpuUsage = (double) diffSystemTime / allTime; | 390 double currentSystemCpuUsage = diffSystemTime / (double) allTime; |
380 sumSystemCpuUsage += currentSystemCpuUsage; | 391 systemCpuUsage.addValue(currentSystemCpuUsage); |
381 | 392 |
382 currentTotalCpuUsage = (currentUserCpuUsage + currentSystemCpuUsage) * curre
ntFrequencyScale; | 393 double currentTotalCpuUsage = |
383 sumTotalCpuUsage += currentTotalCpuUsage; | 394 (currentUserCpuUsage + currentSystemCpuUsage) * currentFrequencyScale; |
| 395 totalCpuUsage.addValue(currentTotalCpuUsage); |
384 | 396 |
385 iterations++; | |
386 // Save new measurements for next round's deltas. | 397 // Save new measurements for next round's deltas. |
387 lastProcStat = procStat; | 398 lastProcStat = procStat; |
388 | 399 |
389 return true; | 400 return true; |
390 } | 401 } |
391 | 402 |
392 private int doubleToPercent(double d) { | 403 private int doubleToPercent(double d) { |
393 return (int) (d * 100 + 0.5); | 404 return (int) (d * 100 + 0.5); |
394 } | 405 } |
395 | 406 |
396 private int sumDoubleToPercent(double d, int iterations) { | 407 private synchronized String getStatString() { |
397 if (iterations > 0) { | |
398 return (int) (d * 100.0 / (double) iterations + 0.5); | |
399 } else { | |
400 return 0; | |
401 } | |
402 } | |
403 | |
404 private String getStatString() { | |
405 StringBuilder stat = new StringBuilder(); | 408 StringBuilder stat = new StringBuilder(); |
406 stat.append("CPU User: ") | 409 stat.append("CPU User: ") |
407 .append(doubleToPercent(currentUserCpuUsage)).append("/") | 410 .append(doubleToPercent(userCpuUsage.getCurrent())).append("/") |
408 .append(sumDoubleToPercent(sumUserCpuUsage, iterations)).append(" (") | 411 .append(doubleToPercent(userCpuUsage.getAverage())) |
409 .append(doubleToPercent(currentUserCpuUsage * currentFrequencyScale)).ap
pend(")") | |
410 .append(". System: ") | 412 .append(". System: ") |
411 .append(doubleToPercent(currentSystemCpuUsage)).append("/") | 413 .append(doubleToPercent(systemCpuUsage.getCurrent())).append("/") |
412 .append(sumDoubleToPercent(sumSystemCpuUsage, iterations)).append(" (") | 414 .append(doubleToPercent(systemCpuUsage.getAverage())) |
413 .append(doubleToPercent(currentSystemCpuUsage * currentFrequencyScale)).
append(")") | 415 .append(". Freq: ") |
414 .append(". CPU freq %: ") | 416 .append(doubleToPercent(frequencyScale.getCurrent())).append("/") |
415 .append(doubleToPercent(currentFrequencyScale)).append("/") | 417 .append(doubleToPercent(frequencyScale.getAverage())) |
416 .append(sumDoubleToPercent(sumFrequencyScale, iterations)) | 418 .append(". Total usage: ") |
417 .append(". Total CPU usage: ") | 419 .append(doubleToPercent(totalCpuUsage.getCurrent())).append("/") |
418 .append(doubleToPercent(currentTotalCpuUsage)).append("/") | 420 .append(doubleToPercent(totalCpuUsage.getAverage())) |
419 .append(sumDoubleToPercent(sumTotalCpuUsage, iterations)) | |
420 .append(". Cores: ") | 421 .append(". Cores: ") |
421 .append(actualCpusPresent); | 422 .append(actualCpusPresent); |
422 stat.append("( "); | 423 stat.append("( "); |
423 for (int i = 0; i < cpusPresent; i++) { | 424 for (int i = 0; i < cpusPresent; i++) { |
424 stat.append(doubleToPercent(curFreqScales[i])).append(" "); | 425 stat.append(doubleToPercent(curFreqScales[i])).append(" "); |
425 } | 426 } |
426 stat.append("). Battery %: ") | 427 stat.append("). Battery: ").append(getBatteryLevel()); |
427 .append(getBatteryLevel()); | 428 if (cpuOveruse) { |
| 429 stat.append(". Overuse."); |
| 430 } |
428 return stat.toString(); | 431 return stat.toString(); |
429 } | 432 } |
430 | 433 |
431 /** | 434 /** |
432 * Read a single integer value from the named file. Return the read value | 435 * Read a single integer value from the named file. Return the read value |
433 * or if an error occurs return 0. | 436 * or if an error occurs return 0. |
434 */ | 437 */ |
435 private long readFreqFromFile(String fileName) { | 438 private long readFreqFromFile(String fileName) { |
436 long number = 0; | 439 long number = 0; |
437 try { | 440 try { |
(...skipping 23 matching lines...) Expand all Loading... |
461 private ProcStat readProcStat() { | 464 private ProcStat readProcStat() { |
462 long userTime = 0; | 465 long userTime = 0; |
463 long systemTime = 0; | 466 long systemTime = 0; |
464 long idleTime = 0; | 467 long idleTime = 0; |
465 try { | 468 try { |
466 FileReader fin = new FileReader("/proc/stat"); | 469 FileReader fin = new FileReader("/proc/stat"); |
467 try { | 470 try { |
468 BufferedReader rdr = new BufferedReader(fin); | 471 BufferedReader rdr = new BufferedReader(fin); |
469 Scanner scanner = new Scanner(rdr); | 472 Scanner scanner = new Scanner(rdr); |
470 scanner.next(); | 473 scanner.next(); |
471 userTime = scanner.nextLong(); | 474 userTime = scanner.nextLong(); // user |
472 long nice = scanner.nextLong(); | 475 long nice = scanner.nextLong(); // nice |
473 userTime += nice; | 476 userTime += nice; |
474 systemTime = scanner.nextLong(); | 477 systemTime = scanner.nextLong(); // system |
475 idleTime = scanner.nextLong(); | 478 idleTime = scanner.nextLong(); // idle |
476 long ioWaitTime = scanner.nextLong(); | 479 long ioWaitTime = scanner.nextLong(); // iowait |
477 userTime += ioWaitTime; | 480 userTime += ioWaitTime; |
| 481 long irqTime = scanner.nextLong() + scanner.nextLong(); // irq + softirq |
| 482 systemTime += irqTime; |
478 scanner.close(); | 483 scanner.close(); |
479 } catch (Exception e) { | 484 } catch (Exception e) { |
480 Log.e(TAG, "Problems parsing /proc/stat"); | 485 Log.e(TAG, "Problems parsing /proc/stat"); |
481 return null; | 486 return null; |
482 } finally { | 487 } finally { |
483 fin.close(); | 488 fin.close(); |
484 } | 489 } |
485 } catch (FileNotFoundException e) { | 490 } catch (FileNotFoundException e) { |
486 Log.e(TAG, "Cannot open /proc/stat for reading"); | 491 Log.e(TAG, "Cannot open /proc/stat for reading"); |
487 return null; | 492 return null; |
488 } catch (IOException e) { | 493 } catch (IOException e) { |
489 Log.e(TAG, "Problems reading /proc/stat"); | 494 Log.e(TAG, "Problems reading /proc/stat"); |
490 return null; | 495 return null; |
491 } | 496 } |
492 return new ProcStat(userTime, systemTime, idleTime); | 497 return new ProcStat(userTime, systemTime, idleTime); |
493 } | 498 } |
494 } | 499 } |
OLD | NEW |