Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2494361b authored by Adam Lesinski's avatar Adam Lesinski Committed by android-build-merger
Browse files

Merge "BatteryStats: Fix up semantics of SamplingTimer" into nyc-dev

am: 1a8a717a

* commit '1a8a717a':
  BatteryStats: Fix up semantics of SamplingTimer

Change-Id: Ie2533ead98202eb9c12daa7032fe98ffd4971c56
parents b96a7859 1a8a717a
Loading
Loading
Loading
Loading
+70 −36
Original line number Diff line number Diff line
@@ -1210,6 +1210,16 @@ public class BatteryStatsImpl extends BatteryStats {
        }
    }

    /**
     * A counter meant to accept monotonically increasing values to its {@link #update(long, int)}
     * method. The state of the timer according to its {@link TimeBase} will determine how much
     * of the value is recorded.
     *
     * If the value being recorded resets, {@link #endSample()} can be called in order to
     * account for the change. If the value passed in to {@link #update(long, int)} decreased
     * between calls, the {@link #endSample()} is automatically called and the new value is
     * expected to increase monotonically from that point on.
     */
    public static class SamplingTimer extends Timer {

        /**
@@ -1262,16 +1272,21 @@ public class BatteryStatsImpl extends BatteryStats {
        }

        @VisibleForTesting
        public SamplingTimer(Clocks clocks, TimeBase timeBase, boolean trackReportedValues) {
        public SamplingTimer(Clocks clocks, TimeBase timeBase) {
            super(clocks, 0, timeBase);
            mTrackingReportedValues = trackReportedValues;
            mTrackingReportedValues = false;
            mTimeBaseRunning = timeBase.isRunning();
        }

        public void setStale() {
            mTrackingReportedValues = false;
            mUnpluggedReportedTotalTime = 0;
            mUnpluggedReportedCount = 0;
        /**
         * Ends the current sample, allowing subsequent values to {@link #update(long, int)} to
         * be less than the values used for a previous invocation.
         */
        public void endSample() {
            mTotalTime = computeRunTimeLocked(0 /* unused by us */);
            mCount = computeCurrentCountLocked();
            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
            mUnpluggedReportedCount = mCurrentReportedCount = 0;
        }

        public void setUpdateVersion(int version) {
@@ -1282,34 +1297,46 @@ public class BatteryStatsImpl extends BatteryStats {
            return mUpdateVersion;
        }

        public void updateCurrentReportedCount(int count) {
            if (mTimeBaseRunning && mUnpluggedReportedCount == 0) {
        /**
         * Updates the current recorded values. These are meant to be monotonically increasing
         * and cumulative. If you are dealing with deltas, use {@link #add(long, int)}.
         *
         * If the values being recorded have been reset, the monotonically increasing requirement
         * will be broken. In this case, {@link #endSample()} is automatically called and
         * the total value of totalTime and count are recorded, starting a new monotonically
         * increasing sample.
         *
         * @param totalTime total time of sample in microseconds.
         * @param count total number of times the event being sampled occurred.
         */
        public void update(long totalTime, int count) {
            if (mTimeBaseRunning && !mTrackingReportedValues) {
                // Updating the reported value for the first time.
                mUnpluggedReportedTotalTime = totalTime;
                mUnpluggedReportedCount = count;
                // If we are receiving an update update mTrackingReportedValues;
                mTrackingReportedValues = true;
            }
            mCurrentReportedCount = count;
            }

        public void addCurrentReportedCount(int delta) {
            updateCurrentReportedCount(mCurrentReportedCount + delta);
        }

        public void updateCurrentReportedTotalTime(long totalTime) {
            if (mTimeBaseRunning && mUnpluggedReportedTotalTime == 0) {
                // Updating the reported value for the first time.
                mUnpluggedReportedTotalTime = totalTime;
                // If we are receiving an update update mTrackingReportedValues;
            mTrackingReportedValues = true;

            if (totalTime < mCurrentReportedTotalTime || count < mCurrentReportedCount) {
                endSample();
            }

            mCurrentReportedTotalTime = totalTime;
            mCurrentReportedCount = count;
        }

        public void addCurrentReportedTotalTime(long delta) {
            updateCurrentReportedTotalTime(mCurrentReportedTotalTime + delta);
        /**
         * Adds deltaTime and deltaCount to the current sample.
         *
         * @param deltaTime additional time recorded since the last sampled event, in microseconds.
         * @param deltaCount additional number of times the event being sampled occurred.
         */
        public void add(long deltaTime, int deltaCount) {
            update(mCurrentReportedTotalTime + deltaTime, mCurrentReportedCount + deltaCount);
        }

        @Override
        public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
            super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
            if (mTrackingReportedValues) {
@@ -1319,11 +1346,13 @@ public class BatteryStatsImpl extends BatteryStats {
            mTimeBaseRunning = true;
        }

        @Override
        public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
            super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
            mTimeBaseRunning = false;
        }

        @Override
        public void logState(Printer pw, String prefix) {
            super.logState(pw, prefix);
            pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
@@ -1332,16 +1361,19 @@ public class BatteryStatsImpl extends BatteryStats {
                    + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
        }

        @Override
        protected long computeRunTimeLocked(long curBatteryRealtime) {
            return mTotalTime + (mTimeBaseRunning && mTrackingReportedValues
                    ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
        }

        @Override
        protected int computeCurrentCountLocked() {
            return mCount + (mTimeBaseRunning && mTrackingReportedValues
                    ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
        }

        @Override
        public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
            super.writeToParcel(out, elapsedRealtimeUs);
            out.writeInt(mCurrentReportedCount);
@@ -1351,12 +1383,16 @@ public class BatteryStatsImpl extends BatteryStats {
            out.writeInt(mTrackingReportedValues ? 1 : 0);
        }

        @Override
        public boolean reset(boolean detachIfReset) {
            super.reset(detachIfReset);
            setStale();
            mTrackingReportedValues = false;
            mUnpluggedReportedTotalTime = 0;
            mUnpluggedReportedCount = 0;
            return true;
        }

        @Override
        public void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
            super.writeSummaryFromParcelLocked(out, batteryRealtime);
            out.writeLong(mCurrentReportedTotalTime);
@@ -1364,6 +1400,7 @@ public class BatteryStatsImpl extends BatteryStats {
            out.writeInt(mTrackingReportedValues ? 1 : 0);
        }

        @Override
        public void readSummaryFromParcelLocked(Parcel in) {
            super.readSummaryFromParcelLocked(in);
            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
@@ -2002,7 +2039,7 @@ public class BatteryStatsImpl extends BatteryStats {
    public SamplingTimer getWakeupReasonTimerLocked(String name) {
        SamplingTimer timer = mWakeupReasonStats.get(name);
        if (timer == null) {
            timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, true);
            timer = new SamplingTimer(mClocks, mOnBatteryTimeBase);
            mWakeupReasonStats.put(name, timer);
        }
        return timer;
@@ -2015,8 +2052,7 @@ public class BatteryStatsImpl extends BatteryStats {
    public SamplingTimer getKernelWakelockTimerLocked(String name) {
        SamplingTimer kwlt = mKernelWakelockStats.get(name);
        if (kwlt == null) {
            kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
                    true /* track reported values */);
            kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
            mKernelWakelockStats.put(name, kwlt);
        }
        return kwlt;
@@ -3125,8 +3161,7 @@ public class BatteryStatsImpl extends BatteryStats {
        if (mLastWakeupReason != null) {
            long deltaUptime = uptimeMs - mLastWakeupUptimeMs;
            SamplingTimer timer = getWakeupReasonTimerLocked(mLastWakeupReason);
            timer.addCurrentReportedCount(1);
            timer.addCurrentReportedTotalTime(deltaUptime * 1000); // time is in microseconds
            timer.add(deltaUptime * 1000, 1); // time in in microseconds
            mLastWakeupReason = null;
        }
    }
@@ -8727,17 +8762,16 @@ public class BatteryStatsImpl extends BatteryStats {

            SamplingTimer kwlt = mKernelWakelockStats.get(name);
            if (kwlt == null) {
                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
                        true /* track reported val */);
                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
                mKernelWakelockStats.put(name, kwlt);
            }
            kwlt.updateCurrentReportedCount(kws.mCount);
            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
            kwlt.update(kws.mTotalTime, kws.mCount);
            kwlt.setUpdateVersion(kws.mVersion);

            if (kws.mVersion != wakelockStats.kernelWakelockVersion)
            if (kws.mVersion != wakelockStats.kernelWakelockVersion) {
                seenNonZeroTime |= kws.mTotalTime > 0;
            }
        }

        int numWakelocksSetStale = 0;
        if (wakelockStats.size() != mKernelWakelockStats.size()) {
@@ -8745,7 +8779,7 @@ public class BatteryStatsImpl extends BatteryStats {
            for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
                SamplingTimer st = ent.getValue();
                if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
                    st.setStale();
                    st.endSample();
                    numWakelocksSetStale++;
                }
            }
+116 −8
Original line number Diff line number Diff line
@@ -21,8 +21,119 @@ import android.support.test.filters.SmallTest;

import junit.framework.TestCase;

import org.mockito.Mockito;

public class BatteryStatsSamplingTimerTest extends TestCase {

    @SmallTest
    public void testSettingStalePreservesData() throws Exception {
        final MockClocks clocks = new MockClocks();
        final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
                Mockito.mock(BatteryStatsImpl.TimeBase.class));

        timer.onTimeStarted(100, 100, 100);

        // First update is absorbed.
        timer.update(10, 1);

        timer.update(20, 2);

        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));

        timer.endSample();

        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));

        timer.onTimeStopped(200, 200, 200);

        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
    }

    @SmallTest
    public void testEndSampleAndContinueWhenTimeOrCountDecreases() throws Exception {
        final MockClocks clocks = new MockClocks();
        final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
        final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
                timeBase);

        // First once is absorbed.
        timer.update(10, 1);

        timer.add(10, 1);

        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));

        // This is less than we currently have, so we will end the sample. Time isn't running, so
        // nothing should happen.
        timer.update(0, 0);

        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));

        timer.onTimeStarted(100, 100, 100);

        // This should add.
        timer.add(100, 10);

        assertEquals(100, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(10, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));

        // This is less than we currently have, so we should end our sample and continue with the
        // entire amount updated here.
        timer.update(50, 5);

        assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));

        timer.onTimeStopped(200, 200, 200);

        assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
    }

    @SmallTest
    public void testFirstUpdateIsAbsorbed() throws Exception {
        final MockClocks clocks = new MockClocks();
        final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);

        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);

        // This should be absorbed because it is our first update and we don't know what
        // was being counted before.
        timer.update(10, 1);

        assertEquals(0, timer.getTotalTimeLocked(10, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));

        timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
        timer.onTimeStarted(100, 100, 100);

        // This should be absorbed.
        timer.update(10, 1);

        assertEquals(0, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));

        // This should NOT be aborbed, since we've already done that.
        timer.add(10, 1);

        assertEquals(10, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));

        timer.onTimeStopped(200, 200, 200);
        timer.onTimeStarted(300, 300, 300);

        // This should NOT be absorbed.
        timer.add(10, 1);

        assertEquals(20, timer.getTotalTimeLocked(300, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(2, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
    }

    @SmallTest
    public void testSampleTimerSummaryParceling() throws Exception {
        final MockClocks clocks = new MockClocks();
@@ -32,18 +143,15 @@ public class BatteryStatsSamplingTimerTest extends TestCase {
        final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
        timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());

        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase,
                true);
        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);

        // Start running on battery.
        timeBase.setRunning(true, clocks.uptimeMillis(), clocks.elapsedRealtime());

        // The first update on battery consumes the values as a way of starting cleanly.
        timer.addCurrentReportedTotalTime(10);
        timer.addCurrentReportedCount(1);
        timer.add(10, 1);

        timer.addCurrentReportedTotalTime(10);
        timer.addCurrentReportedCount(1);
        timer.add(10, 1);

        clocks.realtime = 20;
        clocks.uptime = 20;
@@ -72,14 +180,14 @@ public class BatteryStatsSamplingTimerTest extends TestCase {

        // Read the on battery summary from the parcel.
        BatteryStatsImpl.SamplingTimer unparceledTimer = new BatteryStatsImpl.SamplingTimer(
                clocks, timeBase, true);
                clocks, timeBase);
        unparceledTimer.readSummaryFromParcelLocked(onBatterySummaryParcel);

        assertEquals(10, unparceledTimer.getTotalTimeLocked(0, BatteryStats.STATS_SINCE_CHARGED));
        assertEquals(1, unparceledTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));

        // Read the off battery summary from the parcel.
        unparceledTimer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase, true);
        unparceledTimer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
        unparceledTimer.readSummaryFromParcelLocked(offBatterySummaryParcel);

        assertEquals(10, unparceledTimer.getTotalTimeLocked(0, BatteryStats.STATS_SINCE_CHARGED));