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

Commit e8a76f23 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Trim unnecessary data from CpuWakeupStats

Unsupported wakeups, like aborts, were taking up unnecessary memory as
Wakeup objects.
Also removed the raw reason string which would be redundant after it was
successfully parsed into components.

Also added some unit tests exercising CPU_WAKEUP_SUBSYSTEM_WIFI.

Test: atest FrameworksServicesTests:CpuWakeupStatsTest

Bug: 271216325
Change-Id: I7fb678586b581e380ddc0361028a0e23c653dd14
parent 4c75bada
Loading
Loading
Loading
Loading
+16 −13
Original line number Diff line number Diff line
@@ -126,7 +126,10 @@ public class CpuWakeupStats {
    /** Notes a wakeup reason as reported by SuspendControlService to battery stats. */
    public synchronized void noteWakeupTimeAndReason(long elapsedRealtime, long uptime,
            String rawReason) {
        final Wakeup parsedWakeup = new Wakeup(rawReason, elapsedRealtime, uptime);
        final Wakeup parsedWakeup = Wakeup.parseWakeup(rawReason, elapsedRealtime, uptime);
        if (parsedWakeup == null) {
            return;
        }
        mWakeupEvents.put(elapsedRealtime, parsedWakeup);
        attemptAttributionFor(parsedWakeup);
        // Assuming that wakeups always arrive in monotonically increasing elapsedRealtime order,
@@ -451,28 +454,25 @@ public class CpuWakeupStats {
        private static final String PARSER_TAG = "CpuWakeupStats.Wakeup";
        private static final String ABORT_REASON_PREFIX = "Abort";
        private static final Pattern sIrqPattern = Pattern.compile("^(\\d+)\\s+(\\S+)");

        String mRawReason;
        long mElapsedMillis;
        long mUptimeMillis;
        IrqDevice[] mDevices;

        Wakeup(String rawReason, long elapsedMillis, long uptimeMillis) {
            mRawReason = rawReason;
        private Wakeup(IrqDevice[] devices, long elapsedMillis, long uptimeMillis) {
            mElapsedMillis = elapsedMillis;
            mUptimeMillis = uptimeMillis;
            mDevices = parseIrqDevices(rawReason);
            mDevices = devices;
        }

        private static IrqDevice[] parseIrqDevices(String rawReason) {
        static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis) {
            final String[] components = rawReason.split(":");
            if (ArrayUtils.isEmpty(components) || components[0].startsWith(ABORT_REASON_PREFIX)) {
                // We don't support parsing aborts yet.
                // Accounting of aborts is not supported yet.
                return null;
            }

            int parsedDeviceCount = 0;
            IrqDevice[] parsedDevices = new IrqDevice[components.length];
            final IrqDevice[] parsedDevices = new IrqDevice[components.length];

            for (String component : components) {
                final Matcher matcher = sIrqPattern.matcher(component.trim());
@@ -490,14 +490,17 @@ public class CpuWakeupStats {
                    parsedDevices[parsedDeviceCount++] = new IrqDevice(line, device);
                }
            }
            return (parsedDeviceCount > 0) ? Arrays.copyOf(parsedDevices, parsedDeviceCount) : null;
            if (parsedDeviceCount == 0) {
                return null;
            }
            return new Wakeup(Arrays.copyOf(parsedDevices, parsedDeviceCount), elapsedMillis,
                    uptimeMillis);
        }

        @Override
        public String toString() {
            return "Wakeup{"
                    + "mRawReason='" + mRawReason + '\''
                    + ", mElapsedMillis=" + mElapsedMillis
                    + "mElapsedMillis=" + mElapsedMillis
                    + ", mUptimeMillis=" + TimeUtils.formatDuration(mUptimeMillis)
                    + ", mDevices=" + Arrays.toString(mDevices)
                    + '}';
@@ -514,7 +517,7 @@ public class CpuWakeupStats {

            @Override
            public String toString() {
                return "IrqDevice{" + "mLine=" + mLine + ", mDevice='" + mDevice + '\'' + '}';
                return "IrqDevice{" + "mLine=" + mLine + ", mDevice=\'" + mDevice + '\'' + '}';
            }
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -21,6 +21,6 @@
        <subsystem>Alarm</subsystem>
    </device>
    <device name="test.wifi.device">
        <subsystem>undefined</subsystem>
        <subsystem>Wifi</subsystem>
    </device>
</irq-device-map>
 No newline at end of file
+73 −16
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.power.stats;

import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM;
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI;

import static com.android.server.power.stats.CpuWakeupStats.WAKEUP_REASON_HALF_WINDOW_MS;
import static com.android.server.power.stats.CpuWakeupStats.WAKEUP_RETENTION_MS;
@@ -45,6 +46,7 @@ import java.util.concurrent.ThreadLocalRandom;
@RunWith(AndroidJUnit4.class)
public class CpuWakeupStatsTest {
    private static final String KERNEL_REASON_ALARM_IRQ = "120 test.alarm.device";
    private static final String KERNEL_REASON_WIFI_IRQ = "120 test.wifi.device";
    private static final String KERNEL_REASON_UNKNOWN_IRQ = "140 test.unknown.device";
    private static final String KERNEL_REASON_UNKNOWN = "free-form-reason test.alarm.device";
    private static final String KERNEL_REASON_UNSUPPORTED = "-1 test.alarm.device";
@@ -68,22 +70,23 @@ public class CpuWakeupStatsTest {
        final Set<Long> timestamps = new HashSet<>();
        final long firstWakeup = 453192;

        obj.noteWakeupTimeAndReason(firstWakeup, 32, "unused");
        obj.noteWakeupTimeAndReason(firstWakeup, 32, KERNEL_REASON_UNKNOWN_IRQ);
        timestamps.add(firstWakeup);
        for (int i = 1; i < 1000; i++) {
            final long delta = mRandom.nextLong(WAKEUP_RETENTION_MS);
            if (timestamps.add(firstWakeup + delta)) {
                obj.noteWakeupTimeAndReason(firstWakeup + delta, i, "unused");
                obj.noteWakeupTimeAndReason(firstWakeup + delta, i, KERNEL_REASON_UNKNOWN_IRQ);
            }
        }
        assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size());

        obj.noteWakeupTimeAndReason(firstWakeup + WAKEUP_RETENTION_MS + 1242, 231, "unused");
        obj.noteWakeupTimeAndReason(firstWakeup + WAKEUP_RETENTION_MS + 1242, 231,
                KERNEL_REASON_UNKNOWN_IRQ);
        assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size());

        for (int i = 0; i < 100; i++) {
            final long now = mRandom.nextLong(WAKEUP_RETENTION_MS + 1, 100 * WAKEUP_RETENTION_MS);
            obj.noteWakeupTimeAndReason(now, i, "unused");
            obj.noteWakeupTimeAndReason(now, i, KERNEL_REASON_UNKNOWN_IRQ);
            assertThat(obj.mWakeupEvents.closestIndexOnOrBefore(now - WAKEUP_RETENTION_MS))
                    .isLessThan(0);
        }
@@ -111,17 +114,45 @@ public class CpuWakeupStatsTest {
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_1)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_2)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_3)).isEqualTo(true);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_4)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_5)).isEqualTo(true);
    }

    @Test
    public void alarmIrqAttributionCombined() {
    public void wifiIrqAttributionSolo() {
        final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
        final long wakeupTime = 12423121;

        obj.noteWakeupTimeAndReason(wakeupTime, 1, KERNEL_REASON_WIFI_IRQ);

        // Outside the window, so should be ignored.
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
                wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
                wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
        // Should be attributed
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 3, TEST_UID_4, TEST_UID_5);

        final SparseArray<SparseBooleanArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
        assertThat(attribution).isNotNull();
        assertThat(attribution.size()).isEqualTo(1);
        assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_WIFI)).isTrue();
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_1)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_2)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_3)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_4)).isEqualTo(true);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_5)).isEqualTo(true);
    }

    @Test
    public void alarmAndWifiIrqAttribution() {
        final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
        final long wakeupTime = 92123210;

        obj.noteWakeupTimeAndReason(wakeupTime, 4,
                KERNEL_REASON_UNKNOWN_IRQ + ":" + KERNEL_REASON_ALARM_IRQ);
                KERNEL_REASON_WIFI_IRQ + ":" + KERNEL_REASON_ALARM_IRQ);

        // Alarm activity
        // Outside the window, so should be ignored.
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
                wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
@@ -132,16 +163,34 @@ public class CpuWakeupStatsTest {
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4,
                TEST_UID_5);

        // Wifi activity
        // Outside the window, so should be ignored.
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
                wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_4);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
                wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_3);
        // Should be attributed
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 1, TEST_UID_2,
                TEST_UID_5);

        final SparseArray<SparseBooleanArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
        assertThat(attribution).isNotNull();
        assertThat(attribution.size()).isEqualTo(2);

        assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_ALARM)).isTrue();
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_1)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_2)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_3)).isEqualTo(true);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_4)).isEqualTo(true);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_ALARM).get(TEST_UID_5)).isEqualTo(true);
        assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isTrue();

        assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_WIFI)).isTrue();
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_1)).isEqualTo(true);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_2)).isEqualTo(true);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_3)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_4)).isEqualTo(false);
        assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_5)).isEqualTo(true);
    }

    @Test
@@ -151,9 +200,11 @@ public class CpuWakeupStatsTest {

        obj.noteWakeupTimeAndReason(wakeupTime, 24, KERNEL_REASON_UNKNOWN_IRQ);

        assertThat(obj.mWakeupEvents.size()).isEqualTo(1);

        // Unrelated subsystems, should not be attributed
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4,
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 3, TEST_UID_4,
                TEST_UID_5);

        final SparseArray<SparseBooleanArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
@@ -165,42 +216,48 @@ public class CpuWakeupStatsTest {
    }

    @Test
    public void unknownAttribution() {
    public void unknownWakeupIgnored() {
        final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
        final long wakeupTime = 72123210;

        obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN);

        // Should be ignored as this type of wakeup is unsupported.
        // Should be ignored as this type of wakeup is not known.
        assertThat(obj.mWakeupEvents.size()).isEqualTo(0);

        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4);

        // There should be nothing in the attribution map.
        // Any nearby activity should not end up in the attribution map.
        assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
    }

    @Test
    public void unsupportedAttribution() {
    public void unsupportedWakeupIgnored() {
        final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);

        long wakeupTime = 970934;
        obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNSUPPORTED);

        // Should be ignored as this type of wakeup is unsupported.
        assertThat(obj.mWakeupEvents.size()).isEqualTo(0);

        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4);

        // There should be nothing in the attribution map.
        // Any nearby activity should not end up in the attribution map.
        assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);

        wakeupTime = 883124;
        obj.noteWakeupTimeAndReason(wakeupTime, 3, KERNEL_REASON_ABORT);

        // Should be ignored as this type of wakeup is unsupported.
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 2, TEST_UID_1, TEST_UID_4);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 5, TEST_UID_3);
        assertThat(obj.mWakeupEvents.size()).isEqualTo(0);

        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1, TEST_UID_4);
        obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 5, TEST_UID_3);

        // There should be nothing in the attribution map.
        // Any nearby activity should not end up in the attribution map.
        assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
    }
}