//----------------------------------------------------------------------------- // // (C) Brandon Valosek, 2011 <bvalosek@gmail.com> // (C) Willi Ye, 2015 <williye97@gmail.com> // //----------------------------------------------------------------------------- // Modified by Willi Ye to work with big.LITTLE package com.bvalosek.cpuspy; import android.os.SystemClock; import android.support.annotation.NonNull; import android.util.SparseArray; import com.grarak.kerneladiutor.utils.Utils; import com.grarak.kerneladiutor.utils.kernel.cpu.CPUFreq; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * CpuStateMonitor is a class responsible for querying the system and getting * the time-in-state information, as well as allowing the user to set/reset * offsets to "restart" the state timers */ public class CpuStateMonitor { private final int mCore; private final List<CpuState> mStates = new ArrayList<>(); private final SparseArray<Long> mOffsets = new SparseArray<>(); CpuStateMonitor(int core) { mCore = core; } /** * exception class */ public static class CpuStateMonitorException extends Exception { private CpuStateMonitorException(String s) { super(s); } } /** * simple struct for states/time */ public static class CpuState implements Comparable<CpuState> { private int mFreq = 0; private long mDuration = 0; /** * init with freq and duration */ private CpuState(int a, long b) { mFreq = a; mDuration = b; } public int getFreq() { return mFreq; } public long getDuration() { return mDuration; } /** * for sorting, compare the freqs */ @Override public int compareTo(@NonNull CpuState another) { return ((Integer) mFreq).compareTo(another.mFreq); } } /** * @return List of CpuState with the offsets applied */ public List<CpuState> getStates() { List<CpuState> states = new ArrayList<>(); /* * check for an existing offset, and if it's not too big, subtract it * from the duration, otherwise just add it to the return List */ for (CpuState state : mStates) { long duration = state.getDuration(); if (mOffsets.indexOfKey(state.getFreq()) >= 0) { long offset = mOffsets.get(state.getFreq()); if (offset <= duration) { duration -= offset; } else { /* * offset > duration implies our offsets are now invalid, so * clear and recall this function */ mOffsets.clear(); return getStates(); } } states.add(new CpuState(state.getFreq(), duration)); } return states; } /** * @return Sum of all state durations including deep sleep, accounting for * offsets */ public long getTotalStateTime() { long sum = 0; for (CpuState state : mStates) { sum += state.getDuration(); } return sum; } /** * @return Map of freq->duration of all the offsets */ SparseArray<Long> getOffsets() { return mOffsets; } /** * Sets the offset map (freq->duration offset) */ void setOffsets(SparseArray<Long> offsets) { mOffsets.clear(); for (int i = 0; i < offsets.size(); i++) { mOffsets.put(offsets.keyAt(i), offsets.valueAt(i)); } } /** * Updates the current time in states and then sets the offset map to the * current duration, effectively "zeroing out" the timers */ public void setOffsets() throws CpuStateMonitorException { mOffsets.clear(); updateStates(); for (CpuState state : mStates) { mOffsets.put(state.getFreq(), state.getDuration()); } } /** * removes state offsets */ public void removeOffsets() { mOffsets.clear(); } /** * list of all the CPU frequency states, which contains both a * frequency and a duration (time spent in that state */ public void updateStates() throws CpuStateMonitorException { mStates.clear(); try { String file; if (Utils.existFile(Utils.strFormat(CPUFreq.TIME_STATE, mCore))) { file = Utils.strFormat(CPUFreq.TIME_STATE, mCore); } else { file = Utils.strFormat(CPUFreq.TIME_STATE_2, mCore); } boolean offline = CPUFreq.isOffline(mCore); if (offline) { CPUFreq.onlineCpu(mCore, true, false, null); } String states = Utils.readFile(file); if (offline) { CPUFreq.onlineCpu(mCore, false, false, null); } if (states.isEmpty()) { throw new CpuStateMonitorException("Problem opening time-in-states file"); } readInStates(states.split("\\r?\\n")); } catch (Exception e) { throw new CpuStateMonitorException("Problem opening time-in-states file"); } /* * deep sleep time determined by difference between elapsed (total) boot * time and the system uptime (awake) */ long sleepTime = (SystemClock.elapsedRealtime() - SystemClock.uptimeMillis()) / 10; mStates.add(new CpuState(0, sleepTime)); Collections.sort(mStates, Collections.reverseOrder()); } /** * read from a provided BufferedReader the state lines into the States * member field */ private void readInStates(String[] states) throws CpuStateMonitorException { try { // split open line and convert to Integers for (String line : states) { String[] nums = line.split(" "); mStates.add(new CpuState(Utils.strToInt(nums[0]), Utils.strToLong(nums[1]))); } } catch (Exception e) { throw new CpuStateMonitorException("Problem processing time-in-states file"); } } }