| 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; |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |