Index: talk/examples/android/src/org/appspot/apprtc/CpuMonitor.java |
diff --git a/talk/examples/android/src/org/appspot/apprtc/CpuMonitor.java b/talk/examples/android/src/org/appspot/apprtc/CpuMonitor.java |
deleted file mode 100644 |
index 89d21d4e252bc5d3200dce1967d573d9125063f3..0000000000000000000000000000000000000000 |
--- a/talk/examples/android/src/org/appspot/apprtc/CpuMonitor.java |
+++ /dev/null |
@@ -1,316 +0,0 @@ |
-/* |
- * libjingle |
- * Copyright 2015 Google Inc. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions are met: |
- * |
- * 1. Redistributions of source code must retain the above copyright notice, |
- * this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright notice, |
- * this list of conditions and the following disclaimer in the documentation |
- * and/or other materials provided with the distribution. |
- * 3. The name of the author may not be used to endorse or promote products |
- * derived from this software without specific prior written permission. |
- * |
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-package org.appspot.apprtc; |
- |
-import android.util.Log; |
- |
-import java.io.BufferedReader; |
-import java.io.FileNotFoundException; |
-import java.io.FileReader; |
-import java.io.IOException; |
-import java.util.InputMismatchException; |
-import java.util.Scanner; |
- |
-/** |
- * Simple CPU monitor. The caller creates a CpuMonitor object which can then |
- * be used via sampleCpuUtilization() to collect the percentual use of the |
- * cumulative CPU capacity for all CPUs running at their nominal frequency. 3 |
- * values are generated: (1) getCpuCurrent() returns the use since the last |
- * sampleCpuUtilization(), (2) getCpuAvg3() returns the use since 3 prior |
- * calls, and (3) getCpuAvgAll() returns the use over all SAMPLE_SAVE_NUMBER |
- * calls. |
- * |
- * <p>CPUs in Android are often "offline", and while this of course means 0 Hz |
- * as current frequency, in this state we cannot even get their nominal |
- * frequency. We therefore tread carefully, and allow any CPU to be missing. |
- * Missing CPUs are assumed to have the same nominal frequency as any close |
- * lower-numbered CPU, but as soon as it is online, we'll get their proper |
- * frequency and remember it. (Since CPU 0 in practice always seem to be |
- * online, this unidirectional frequency inheritance should be no problem in |
- * practice.) |
- * |
- * <p>Caveats: |
- * o No provision made for zany "turbo" mode, common in the x86 world. |
- * o No provision made for ARM big.LITTLE; if CPU n can switch behind our |
- * back, we might get incorrect estimates. |
- * o This is not thread-safe. To call asynchronously, create different |
- * CpuMonitor objects. |
- * |
- * <p>If we can gather enough info to generate a sensible result, |
- * sampleCpuUtilization returns true. It is designed to never through an |
- * exception. |
- * |
- * <p>sampleCpuUtilization should not be called too often in its present form, |
- * since then deltas would be small and the percent values would fluctuate and |
- * be unreadable. If it is desirable to call it more often than say once per |
- * second, one would need to increase SAMPLE_SAVE_NUMBER and probably use |
- * Queue<Integer> to avoid copying overhead. |
- * |
- * <p>Known problems: |
- * 1. Nexus 7 devices running Kitkat have a kernel which often output an |
- * incorrect 'idle' field in /proc/stat. The value is close to twice the |
- * correct value, and then returns to back to correct reading. Both when |
- * jumping up and back down we might create faulty CPU load readings. |
- */ |
- |
-class CpuMonitor { |
- private static final int SAMPLE_SAVE_NUMBER = 10; // Assumed to be >= 3. |
- private int[] percentVec = new int[SAMPLE_SAVE_NUMBER]; |
- private int sum3 = 0; |
- private int sum10 = 0; |
- private static final String TAG = "CpuMonitor"; |
- private long[] cpuFreq; |
- private int cpusPresent; |
- private double lastPercentFreq = -1; |
- private int cpuCurrent; |
- private int cpuAvg3; |
- private int cpuAvgAll; |
- private boolean initialized = false; |
- private String[] maxPath; |
- private String[] curPath; |
- ProcStat lastProcStat; |
- |
- private class ProcStat { |
- final long runTime; |
- final long idleTime; |
- |
- ProcStat(long aRunTime, long aIdleTime) { |
- runTime = aRunTime; |
- idleTime = aIdleTime; |
- } |
- } |
- |
- private void init() { |
- try { |
- FileReader fin = new FileReader("/sys/devices/system/cpu/present"); |
- try { |
- BufferedReader rdr = new BufferedReader(fin); |
- Scanner scanner = new Scanner(rdr).useDelimiter("[-\n]"); |
- scanner.nextInt(); // Skip leading number 0. |
- cpusPresent = 1 + scanner.nextInt(); |
- scanner.close(); |
- } catch (Exception e) { |
- Log.e(TAG, "Cannot do CPU stats due to /sys/devices/system/cpu/present parsing problem"); |
- } finally { |
- fin.close(); |
- } |
- } catch (FileNotFoundException e) { |
- Log.e(TAG, "Cannot do CPU stats since /sys/devices/system/cpu/present is missing"); |
- } catch (IOException e) { |
- Log.e(TAG, "Error closing file"); |
- } |
- |
- cpuFreq = new long [cpusPresent]; |
- maxPath = new String [cpusPresent]; |
- curPath = new String [cpusPresent]; |
- for (int i = 0; i < cpusPresent; i++) { |
- cpuFreq[i] = 0; // Frequency "not yet determined". |
- maxPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_freq"; |
- curPath[i] = "/sys/devices/system/cpu/cpu" + i + "/cpufreq/scaling_cur_freq"; |
- } |
- |
- lastProcStat = new ProcStat(0, 0); |
- |
- initialized = true; |
- } |
- |
- /** |
- * Re-measure CPU use. Call this method at an interval of around 1/s. |
- * This method returns true on success. The fields |
- * cpuCurrent, cpuAvg3, and cpuAvgAll are updated on success, and represents: |
- * cpuCurrent: The CPU use since the last sampleCpuUtilization call. |
- * cpuAvg3: The average CPU over the last 3 calls. |
- * cpuAvgAll: The average CPU over the last SAMPLE_SAVE_NUMBER calls. |
- */ |
- public boolean sampleCpuUtilization() { |
- long lastSeenMaxFreq = 0; |
- long cpufreqCurSum = 0; |
- long cpufreqMaxSum = 0; |
- |
- if (!initialized) { |
- init(); |
- } |
- |
- for (int i = 0; i < cpusPresent; i++) { |
- /* |
- * For each CPU, attempt to first read its max frequency, then its |
- * current frequency. Once as the max frequency for a CPU is found, |
- * save it in cpuFreq[]. |
- */ |
- |
- if (cpuFreq[i] == 0) { |
- // We have never found this CPU's max frequency. Attempt to read it. |
- long cpufreqMax = readFreqFromFile(maxPath[i]); |
- if (cpufreqMax > 0) { |
- lastSeenMaxFreq = cpufreqMax; |
- cpuFreq[i] = cpufreqMax; |
- maxPath[i] = null; // Kill path to free its memory. |
- } |
- } else { |
- lastSeenMaxFreq = cpuFreq[i]; // A valid, previously read value. |
- } |
- |
- long cpufreqCur = readFreqFromFile(curPath[i]); |
- cpufreqCurSum += cpufreqCur; |
- |
- /* Here, lastSeenMaxFreq might come from |
- * 1. cpuFreq[i], or |
- * 2. a previous iteration, or |
- * 3. a newly read value, or |
- * 4. hypothetically from the pre-loop dummy. |
- */ |
- cpufreqMaxSum += lastSeenMaxFreq; |
- } |
- |
- if (cpufreqMaxSum == 0) { |
- Log.e(TAG, "Could not read max frequency for any CPU"); |
- return false; |
- } |
- |
- /* |
- * Since the cycle counts are for the period between the last invocation |
- * and this present one, we average the percentual CPU frequencies between |
- * now and the beginning of the measurement period. This is significantly |
- * incorrect only if the frequencies have peeked or dropped in between the |
- * invocations. |
- */ |
- double newPercentFreq = 100.0 * cpufreqCurSum / cpufreqMaxSum; |
- double percentFreq; |
- if (lastPercentFreq > 0) { |
- percentFreq = (lastPercentFreq + newPercentFreq) * 0.5; |
- } else { |
- percentFreq = newPercentFreq; |
- } |
- lastPercentFreq = newPercentFreq; |
- |
- ProcStat procStat = readIdleAndRunTime(); |
- if (procStat == null) { |
- return false; |
- } |
- |
- long diffRunTime = procStat.runTime - lastProcStat.runTime; |
- long diffIdleTime = procStat.idleTime - lastProcStat.idleTime; |
- |
- // Save new measurements for next round's deltas. |
- lastProcStat = procStat; |
- |
- long allTime = diffRunTime + diffIdleTime; |
- int percent = allTime == 0 ? 0 : (int) Math.round(percentFreq * diffRunTime / allTime); |
- percent = Math.max(0, Math.min(percent, 100)); |
- |
- // Subtract old relevant measurement, add newest. |
- sum3 += percent - percentVec[2]; |
- // Subtract oldest measurement, add newest. |
- sum10 += percent - percentVec[SAMPLE_SAVE_NUMBER - 1]; |
- |
- // Rotate saved percent values, save new measurement in vacated spot. |
- for (int i = SAMPLE_SAVE_NUMBER - 1; i > 0; i--) { |
- percentVec[i] = percentVec[i - 1]; |
- } |
- percentVec[0] = percent; |
- |
- cpuCurrent = percent; |
- cpuAvg3 = sum3 / 3; |
- cpuAvgAll = sum10 / SAMPLE_SAVE_NUMBER; |
- |
- return true; |
- } |
- |
- public int getCpuCurrent() { |
- return cpuCurrent; |
- } |
- |
- public int getCpuAvg3() { |
- return cpuAvg3; |
- } |
- |
- public int getCpuAvgAll() { |
- return cpuAvgAll; |
- } |
- |
- /** |
- * Read a single integer value from the named file. Return the read value |
- * or if an error occurs return 0. |
- */ |
- private long readFreqFromFile(String fileName) { |
- long number = 0; |
- try { |
- FileReader fin = new FileReader(fileName); |
- try { |
- BufferedReader rdr = new BufferedReader(fin); |
- Scanner scannerC = new Scanner(rdr); |
- number = scannerC.nextLong(); |
- scannerC.close(); |
- } catch (Exception e) { |
- // CPU presumably got offline just after we opened file. |
- } finally { |
- fin.close(); |
- } |
- } catch (FileNotFoundException e) { |
- // CPU is offline, not an error. |
- } catch (IOException e) { |
- Log.e(TAG, "Error closing file"); |
- } |
- return number; |
- } |
- |
- /* |
- * Read the current utilization of all CPUs using the cumulative first line |
- * of /proc/stat. |
- */ |
- private ProcStat readIdleAndRunTime() { |
- long runTime = 0; |
- long idleTime = 0; |
- try { |
- FileReader fin = new FileReader("/proc/stat"); |
- try { |
- BufferedReader rdr = new BufferedReader(fin); |
- Scanner scanner = new Scanner(rdr); |
- scanner.next(); |
- long user = scanner.nextLong(); |
- long nice = scanner.nextLong(); |
- long sys = scanner.nextLong(); |
- runTime = user + nice + sys; |
- idleTime = scanner.nextLong(); |
- scanner.close(); |
- } catch (Exception e) { |
- Log.e(TAG, "Problems parsing /proc/stat"); |
- return null; |
- } finally { |
- fin.close(); |
- } |
- } catch (FileNotFoundException e) { |
- Log.e(TAG, "Cannot open /proc/stat for reading"); |
- return null; |
- } catch (IOException e) { |
- Log.e(TAG, "Problems reading /proc/stat"); |
- return null; |
- } |
- return new ProcStat(runTime, idleTime); |
- } |
-} |