Merge "Reduce unnecessary overhead in CpuWakeupStats" into udc-dev
diff --git a/core/res/res/xml/irq_device_map.xml b/core/res/res/xml/irq_device_map.xml
index 8b3667e..2f894b9 100644
--- a/core/res/res/xml/irq_device_map.xml
+++ b/core/res/res/xml/irq_device_map.xml
@@ -28,6 +28,8 @@
- Wifi: Use this to denote network traffic that uses the wifi transport.
- Sound_trigger: Use this to denote sound phrase detection, like the ones supported by
SoundTriggerManager.
+ - Sensor: Use this to denote wakeups due to sensor events.
+ - Cellular_data: Use this to denote network traffic on the cellular transport.
The overlay should use tags <device> and <subsystem> to describe this mapping in the
following way:
diff --git a/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java b/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java
index 73ab782..712a696 100644
--- a/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java
+++ b/services/core/java/com/android/server/power/stats/wakeups/CpuWakeupStats.java
@@ -23,6 +23,7 @@
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_UNKNOWN;
import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_WIFI;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Handler;
@@ -48,6 +49,7 @@
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
+import java.util.function.LongSupplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -62,15 +64,14 @@
private static final String SUBSYSTEM_SENSOR_STRING = "Sensor";
private static final String SUBSYSTEM_CELLULAR_DATA_STRING = "Cellular_data";
private static final String TRACE_TRACK_WAKEUP_ATTRIBUTION = "wakeup_attribution";
- @VisibleForTesting
- static final long WAKEUP_REASON_HALF_WINDOW_MS = 500;
+
private static final long WAKEUP_WRITE_DELAY_MS = TimeUnit.SECONDS.toMillis(30);
private final Handler mHandler;
private final IrqDeviceMap mIrqDeviceMap;
@VisibleForTesting
final Config mConfig = new Config();
- private final WakingActivityHistory mRecentWakingActivity = new WakingActivityHistory();
+ private final WakingActivityHistory mRecentWakingActivity;
@VisibleForTesting
final TimeSparseArray<Wakeup> mWakeupEvents = new TimeSparseArray<>();
@@ -85,6 +86,8 @@
public CpuWakeupStats(Context context, int mapRes, Handler handler) {
mIrqDeviceMap = IrqDeviceMap.getInstance(context, mapRes);
+ mRecentWakingActivity = new WakingActivityHistory(
+ () -> mConfig.WAKING_ACTIVITY_RETENTION_MS);
mHandler = handler;
}
@@ -202,15 +205,14 @@
/** Notes a wakeup reason as reported by SuspendControlService to battery stats. */
public synchronized void noteWakeupTimeAndReason(long elapsedRealtime, long uptime,
String rawReason) {
- final Wakeup parsedWakeup = Wakeup.parseWakeup(rawReason, elapsedRealtime, uptime);
+ final Wakeup parsedWakeup = Wakeup.parseWakeup(rawReason, elapsedRealtime, uptime,
+ mIrqDeviceMap);
if (parsedWakeup == null) {
+ // This wakeup is unsupported for attribution. Exit.
return;
}
mWakeupEvents.put(elapsedRealtime, parsedWakeup);
attemptAttributionFor(parsedWakeup);
- // Assuming that wakeups always arrive in monotonically increasing elapsedRealtime order,
- // we can delete all history that will not be useful in attributing future wakeups.
- mRecentWakingActivity.clearAllBefore(elapsedRealtime - WAKEUP_REASON_HALF_WINDOW_MS);
// Limit history of wakeups and their attribution to the last retentionDuration. Note that
// the last wakeup and its attribution (if computed) is always stored, even if that wakeup
@@ -244,25 +246,22 @@
}
private synchronized void attemptAttributionFor(Wakeup wakeup) {
- final SparseBooleanArray subsystems = getResponsibleSubsystemsForWakeup(wakeup);
- if (subsystems == null) {
- // We don't support attribution for this kind of wakeup yet.
- return;
- }
+ final SparseBooleanArray subsystems = wakeup.mResponsibleSubsystems;
SparseArray<SparseIntArray> attribution = mWakeupAttribution.get(wakeup.mElapsedMillis);
if (attribution == null) {
attribution = new SparseArray<>();
mWakeupAttribution.put(wakeup.mElapsedMillis, attribution);
}
+ final long matchingWindowMillis = mConfig.WAKEUP_MATCHING_WINDOW_MS;
for (int subsystemIdx = 0; subsystemIdx < subsystems.size(); subsystemIdx++) {
final int subsystem = subsystems.keyAt(subsystemIdx);
- // Blame all activity that happened WAKEUP_REASON_HALF_WINDOW_MS before or after
+ // Blame all activity that happened matchingWindowMillis before or after
// the wakeup from each responsible subsystem.
- final long startTime = wakeup.mElapsedMillis - WAKEUP_REASON_HALF_WINDOW_MS;
- final long endTime = wakeup.mElapsedMillis + WAKEUP_REASON_HALF_WINDOW_MS;
+ final long startTime = wakeup.mElapsedMillis - matchingWindowMillis;
+ final long endTime = wakeup.mElapsedMillis + matchingWindowMillis;
final SparseIntArray uidsToBlame = mRecentWakingActivity.removeBetween(subsystem,
startTime, endTime);
@@ -272,18 +271,16 @@
private synchronized boolean attemptAttributionWith(int subsystem, long activityElapsed,
SparseIntArray uidProcStates) {
+ final long matchingWindowMillis = mConfig.WAKEUP_MATCHING_WINDOW_MS;
+
final int startIdx = mWakeupEvents.closestIndexOnOrAfter(
- activityElapsed - WAKEUP_REASON_HALF_WINDOW_MS);
+ activityElapsed - matchingWindowMillis);
final int endIdx = mWakeupEvents.closestIndexOnOrBefore(
- activityElapsed + WAKEUP_REASON_HALF_WINDOW_MS);
+ activityElapsed + matchingWindowMillis);
for (int wakeupIdx = startIdx; wakeupIdx <= endIdx; wakeupIdx++) {
final Wakeup wakeup = mWakeupEvents.valueAt(wakeupIdx);
- final SparseBooleanArray subsystems = getResponsibleSubsystemsForWakeup(wakeup);
- if (subsystems == null) {
- // Unsupported for attribution
- continue;
- }
+ final SparseBooleanArray subsystems = wakeup.mResponsibleSubsystems;
if (subsystems.get(subsystem)) {
// We don't expect more than one wakeup to be found within such a short window, so
// just attribute this one and exit
@@ -405,11 +402,13 @@
*/
@VisibleForTesting
static final class WakingActivityHistory {
- private static final long WAKING_ACTIVITY_RETENTION_MS = TimeUnit.MINUTES.toMillis(10);
-
+ private LongSupplier mRetentionSupplier;
@VisibleForTesting
- final SparseArray<TimeSparseArray<SparseIntArray>> mWakingActivity =
- new SparseArray<>();
+ final SparseArray<TimeSparseArray<SparseIntArray>> mWakingActivity = new SparseArray<>();
+
+ WakingActivityHistory(LongSupplier retentionSupplier) {
+ mRetentionSupplier = retentionSupplier;
+ }
void recordActivity(int subsystem, long elapsedRealtime, SparseIntArray uidProcStates) {
if (uidProcStates == null) {
@@ -433,27 +432,13 @@
}
}
}
- // Limit activity history per subsystem to the last WAKING_ACTIVITY_RETENTION_MS.
- // Note that the last activity is always present, even if it occurred before
- // WAKING_ACTIVITY_RETENTION_MS.
+ // Limit activity history per subsystem to the last retention period as supplied by
+ // mRetentionSupplier. Note that the last activity is always present, even if it
+ // occurred before the retention period.
final int endIdx = wakingActivity.closestIndexOnOrBefore(
- elapsedRealtime - WAKING_ACTIVITY_RETENTION_MS);
+ elapsedRealtime - mRetentionSupplier.getAsLong());
for (int i = endIdx; i >= 0; i--) {
- wakingActivity.removeAt(endIdx);
- }
- }
-
- void clearAllBefore(long elapsedRealtime) {
- for (int subsystemIdx = mWakingActivity.size() - 1; subsystemIdx >= 0; subsystemIdx--) {
- final TimeSparseArray<SparseIntArray> activityPerSubsystem =
- mWakingActivity.valueAt(subsystemIdx);
- final int endIdx = activityPerSubsystem.closestIndexOnOrBefore(elapsedRealtime);
- for (int removeIdx = endIdx; removeIdx >= 0; removeIdx--) {
- activityPerSubsystem.removeAt(removeIdx);
- }
- // Generally waking activity is a high frequency occurrence for any subsystem, so we
- // don't delete the TimeSparseArray even if it is now empty, to avoid object churn.
- // This will leave one TimeSparseArray per subsystem, which are few right now.
+ wakingActivity.removeAt(i);
}
}
@@ -515,33 +500,6 @@
}
}
- private SparseBooleanArray getResponsibleSubsystemsForWakeup(Wakeup wakeup) {
- if (ArrayUtils.isEmpty(wakeup.mDevices)) {
- return null;
- }
- final SparseBooleanArray result = new SparseBooleanArray();
- for (final Wakeup.IrqDevice device : wakeup.mDevices) {
- final List<String> rawSubsystems = mIrqDeviceMap.getSubsystemsForDevice(device.mDevice);
-
- boolean anyKnownSubsystem = false;
- if (rawSubsystems != null) {
- for (int i = 0; i < rawSubsystems.size(); i++) {
- final int subsystem = stringToKnownSubsystem(rawSubsystems.get(i));
- if (subsystem != CPU_WAKEUP_SUBSYSTEM_UNKNOWN) {
- // Just in case the xml had arbitrary subsystem names, we want to make sure
- // that we only put the known ones into our attribution map.
- result.put(subsystem, true);
- anyKnownSubsystem = true;
- }
- }
- }
- if (!anyKnownSubsystem) {
- result.put(CPU_WAKEUP_SUBSYSTEM_UNKNOWN, true);
- }
- }
- return result;
- }
-
static int stringToKnownSubsystem(String rawSubsystem) {
switch (rawSubsystem) {
case SUBSYSTEM_ALARM_STRING:
@@ -598,15 +556,19 @@
long mElapsedMillis;
long mUptimeMillis;
IrqDevice[] mDevices;
+ SparseBooleanArray mResponsibleSubsystems;
- private Wakeup(int type, IrqDevice[] devices, long elapsedMillis, long uptimeMillis) {
+ private Wakeup(int type, IrqDevice[] devices, long elapsedMillis, long uptimeMillis,
+ SparseBooleanArray responsibleSubsystems) {
mType = type;
mDevices = devices;
mElapsedMillis = elapsedMillis;
mUptimeMillis = uptimeMillis;
+ mResponsibleSubsystems = responsibleSubsystems;
}
- static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis) {
+ static Wakeup parseWakeup(String rawReason, long elapsedMillis, long uptimeMillis,
+ IrqDeviceMap deviceMap) {
final String[] components = rawReason.split(":");
if (ArrayUtils.isEmpty(components) || components[0].startsWith(ABORT_REASON_PREFIX)) {
// Accounting of aborts is not supported yet.
@@ -616,6 +578,7 @@
int type = TYPE_IRQ;
int parsedDeviceCount = 0;
final IrqDevice[] parsedDevices = new IrqDevice[components.length];
+ final SparseBooleanArray responsibleSubsystems = new SparseBooleanArray();
for (String component : components) {
final Matcher matcher = sIrqPattern.matcher(component.trim());
@@ -635,13 +598,35 @@
continue;
}
parsedDevices[parsedDeviceCount++] = new IrqDevice(line, device);
+
+ final List<String> rawSubsystems = deviceMap.getSubsystemsForDevice(device);
+ boolean anyKnownSubsystem = false;
+ if (rawSubsystems != null) {
+ for (int i = 0; i < rawSubsystems.size(); i++) {
+ final int subsystem = stringToKnownSubsystem(rawSubsystems.get(i));
+ if (subsystem != CPU_WAKEUP_SUBSYSTEM_UNKNOWN) {
+ // Just in case the xml had arbitrary subsystem names, we want to
+ // make sure that we only put the known ones into our map.
+ responsibleSubsystems.put(subsystem, true);
+ anyKnownSubsystem = true;
+ }
+ }
+ }
+ if (!anyKnownSubsystem) {
+ responsibleSubsystems.put(CPU_WAKEUP_SUBSYSTEM_UNKNOWN, true);
+ }
}
}
if (parsedDeviceCount == 0) {
return null;
}
+ if (responsibleSubsystems.size() == 1 && responsibleSubsystems.get(
+ CPU_WAKEUP_SUBSYSTEM_UNKNOWN, false)) {
+ // There is no attributable subsystem here, so we do not support it.
+ return null;
+ }
return new Wakeup(type, Arrays.copyOf(parsedDevices, parsedDeviceCount), elapsedMillis,
- uptimeMillis);
+ uptimeMillis, responsibleSubsystems);
}
@Override
@@ -651,6 +636,7 @@
+ ", mElapsedMillis=" + mElapsedMillis
+ ", mUptimeMillis=" + mUptimeMillis
+ ", mDevices=" + Arrays.toString(mDevices)
+ + ", mResponsibleSubsystems=" + mResponsibleSubsystems
+ '}';
}
@@ -672,18 +658,28 @@
static final class Config implements DeviceConfig.OnPropertiesChangedListener {
static final String KEY_WAKEUP_STATS_RETENTION_MS = "wakeup_stats_retention_ms";
+ static final String KEY_WAKEUP_MATCHING_WINDOW_MS = "wakeup_matching_window_ms";
+ static final String KEY_WAKING_ACTIVITY_RETENTION_MS = "waking_activity_retention_ms";
private static final String[] PROPERTY_NAMES = {
KEY_WAKEUP_STATS_RETENTION_MS,
+ KEY_WAKEUP_MATCHING_WINDOW_MS,
+ KEY_WAKING_ACTIVITY_RETENTION_MS,
};
static final long DEFAULT_WAKEUP_STATS_RETENTION_MS = TimeUnit.DAYS.toMillis(3);
+ private static final long DEFAULT_WAKEUP_MATCHING_WINDOW_MS = TimeUnit.SECONDS.toMillis(1);
+ private static final long DEFAULT_WAKING_ACTIVITY_RETENTION_MS =
+ TimeUnit.MINUTES.toMillis(5);
/**
* Wakeup stats are retained only for this duration.
*/
public volatile long WAKEUP_STATS_RETENTION_MS = DEFAULT_WAKEUP_STATS_RETENTION_MS;
+ public volatile long WAKEUP_MATCHING_WINDOW_MS = DEFAULT_WAKEUP_MATCHING_WINDOW_MS;
+ public volatile long WAKING_ACTIVITY_RETENTION_MS = DEFAULT_WAKING_ACTIVITY_RETENTION_MS;
+ @SuppressLint("MissingPermission")
void register(Executor executor) {
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_BATTERY_STATS,
executor, this);
@@ -702,6 +698,15 @@
WAKEUP_STATS_RETENTION_MS = properties.getLong(
KEY_WAKEUP_STATS_RETENTION_MS, DEFAULT_WAKEUP_STATS_RETENTION_MS);
break;
+ case KEY_WAKEUP_MATCHING_WINDOW_MS:
+ WAKEUP_MATCHING_WINDOW_MS = properties.getLong(
+ KEY_WAKEUP_MATCHING_WINDOW_MS, DEFAULT_WAKEUP_MATCHING_WINDOW_MS);
+ break;
+ case KEY_WAKING_ACTIVITY_RETENTION_MS:
+ WAKING_ACTIVITY_RETENTION_MS = properties.getLong(
+ KEY_WAKING_ACTIVITY_RETENTION_MS,
+ DEFAULT_WAKING_ACTIVITY_RETENTION_MS);
+ break;
}
}
}
@@ -711,7 +716,19 @@
pw.increaseIndent();
- pw.print(KEY_WAKEUP_STATS_RETENTION_MS, WAKEUP_STATS_RETENTION_MS);
+ pw.print(KEY_WAKEUP_STATS_RETENTION_MS);
+ pw.print("=");
+ TimeUtils.formatDuration(WAKEUP_STATS_RETENTION_MS, pw);
+ pw.println();
+
+ pw.print(KEY_WAKEUP_MATCHING_WINDOW_MS);
+ pw.print("=");
+ TimeUtils.formatDuration(WAKEUP_MATCHING_WINDOW_MS, pw);
+ pw.println();
+
+ pw.print(KEY_WAKING_ACTIVITY_RETENTION_MS);
+ pw.print("=");
+ TimeUtils.formatDuration(WAKING_ACTIVITY_RETENTION_MS, pw);
pw.println();
pw.decreaseIndent();
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
index 76b6a82..d181419 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/CpuWakeupStatsTest.java
@@ -23,8 +23,6 @@
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.wakeups.CpuWakeupStats.WAKEUP_REASON_HALF_WINDOW_MS;
-
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -55,7 +53,7 @@
private static final String KERNEL_REASON_SENSOR_IRQ = "15 test.sensor.device";
private static final String KERNEL_REASON_CELLULAR_DATA_IRQ = "18 test.cellular_data.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_UNKNOWN_FORMAT = "free-form-reason test.alarm.device";
private static final String KERNEL_REASON_ALARM_ABNORMAL = "-1 test.alarm.device";
private static final String KERNEL_REASON_ABORT = "Abort: due to test.alarm.device";
@@ -85,30 +83,29 @@
@Test
public void removesOldWakeups() {
- // The xml resource doesn't matter for this test.
- final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_1, mHandler);
+ final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
final long retention = obj.mConfig.WAKEUP_STATS_RETENTION_MS;
final Set<Long> timestamps = new HashSet<>();
final long firstWakeup = 453192;
- obj.noteWakeupTimeAndReason(firstWakeup, 32, KERNEL_REASON_UNKNOWN_IRQ);
+ // Reasons do not matter for this test, as long as they map to known subsystems
+ obj.noteWakeupTimeAndReason(firstWakeup, 32, KERNEL_REASON_ALARM_IRQ);
timestamps.add(firstWakeup);
for (int i = 1; i < 1000; i++) {
final long delta = mRandom.nextLong(retention);
if (timestamps.add(firstWakeup + delta)) {
- obj.noteWakeupTimeAndReason(firstWakeup + delta, i, KERNEL_REASON_UNKNOWN_IRQ);
+ obj.noteWakeupTimeAndReason(firstWakeup + delta, i, KERNEL_REASON_SENSOR_IRQ);
}
}
assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size());
- obj.noteWakeupTimeAndReason(firstWakeup + retention + 1242, 231,
- KERNEL_REASON_UNKNOWN_IRQ);
+ obj.noteWakeupTimeAndReason(firstWakeup + retention, 231, KERNEL_REASON_WIFI_IRQ);
assertThat(obj.mWakeupEvents.size()).isEqualTo(timestamps.size());
for (int i = 0; i < 100; i++) {
final long now = mRandom.nextLong(retention + 1, 100 * retention);
- obj.noteWakeupTimeAndReason(now, i, KERNEL_REASON_UNKNOWN_IRQ);
+ obj.noteWakeupTimeAndReason(now, i, KERNEL_REASON_SOUND_TRIGGER_IRQ);
assertThat(obj.mWakeupEvents.closestIndexOnOrBefore(now - retention)).isLessThan(0);
}
}
@@ -201,9 +198,9 @@
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3, TEST_UID_5);
@@ -234,9 +231,9 @@
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER, wakeupTime + 5, TEST_UID_3,
TEST_UID_5);
@@ -268,9 +265,9 @@
// Outside the window, so should be ignored.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime - WAKEUP_REASON_HALF_WINDOW_MS - 1, TEST_UID_1);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 3, TEST_UID_4, TEST_UID_5);
@@ -300,9 +297,9 @@
// 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);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_1);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_2);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_WINDOW_MS + 1, TEST_UID_2);
// Should be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4,
@@ -311,9 +308,9 @@
// 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);
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_4);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
- wakeupTime + WAKEUP_REASON_HALF_WINDOW_MS + 1, TEST_UID_3);
+ wakeupTime + obj.mConfig.WAKEUP_MATCHING_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,
@@ -347,33 +344,67 @@
}
@Test
- public void unknownIrqAttribution() {
+ public void unknownIrqSoloIgnored() {
final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
final long wakeupTime = 92123410;
obj.noteWakeupTimeAndReason(wakeupTime, 24, KERNEL_REASON_UNKNOWN_IRQ);
- assertThat(obj.mWakeupEvents.size()).isEqualTo(1);
+ assertThat(obj.mWakeupEvents.size()).isEqualTo(0);
- // Unrelated subsystems, should not be attributed
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 3, TEST_UID_4,
TEST_UID_5);
- final SparseArray<SparseIntArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
- assertThat(attribution).isNotNull();
- assertThat(attribution.size()).isEqualTo(1);
- assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isTrue();
- final SparseIntArray uidProcStates = attribution.get(CPU_WAKEUP_SUBSYSTEM_UNKNOWN);
- assertThat(uidProcStates == null || uidProcStates.size() == 0).isTrue();
+ // Any nearby activity should not end up in the attribution map.
+ assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
}
@Test
- public void unknownWakeupIgnored() {
+ public void unknownAndWifiAttribution() {
+ final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
+ final long wakeupTime = 92123410;
+
+ populateDefaultProcStates(obj);
+
+ obj.noteWakeupTimeAndReason(wakeupTime, 24,
+ KERNEL_REASON_UNKNOWN_IRQ + ":" + KERNEL_REASON_WIFI_IRQ);
+
+ // Wifi activity
+ // Outside the window, so should be ignored.
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI,
+ wakeupTime - obj.mConfig.WAKEUP_MATCHING_WINDOW_MS - 1, TEST_UID_4);
+ // Should be attributed
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime + 2, TEST_UID_1);
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_WIFI, wakeupTime - 1, TEST_UID_3,
+ TEST_UID_5);
+
+ // Unrelated, should be ignored.
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
+
+ final SparseArray<SparseIntArray> attribution = obj.mWakeupAttribution.get(wakeupTime);
+ assertThat(attribution).isNotNull();
+ assertThat(attribution.size()).isEqualTo(2);
+ assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_WIFI)).isTrue();
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_1)).isEqualTo(
+ TEST_PROC_STATE_1);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).indexOfKey(TEST_UID_2)).isLessThan(0);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_3)).isEqualTo(
+ TEST_PROC_STATE_3);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).indexOfKey(TEST_UID_4)).isLessThan(0);
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_WIFI).get(TEST_UID_5)).isEqualTo(
+ TEST_PROC_STATE_5);
+ assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isTrue();
+ assertThat(attribution.get(CPU_WAKEUP_SUBSYSTEM_UNKNOWN)).isNull();
+ assertThat(attribution.contains(CPU_WAKEUP_SUBSYSTEM_ALARM)).isFalse();
+ }
+
+ @Test
+ public void unknownFormatWakeupIgnored() {
final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3, mHandler);
final long wakeupTime = 72123210;
- obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN);
+ obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN_FORMAT);
// Should be ignored as this type of wakeup is not known.
assertThat(obj.mWakeupEvents.size()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
index cba7dbe..b02618e 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/wakeups/WakingActivityHistoryTest.java
@@ -28,8 +28,11 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.concurrent.ThreadLocalRandom;
+
@RunWith(AndroidJUnit4.class)
public class WakingActivityHistoryTest {
+ private volatile long mTestRetention = 54;
private static boolean areSame(SparseIntArray a, SparseIntArray b) {
if (a == b) {
@@ -55,7 +58,7 @@
@Test
public void recordActivityAppendsUids() {
- final WakingActivityHistory history = new WakingActivityHistory();
+ final WakingActivityHistory history = new WakingActivityHistory(() -> Long.MAX_VALUE);
final int subsystem = 42;
final long timestamp = 54;
@@ -100,7 +103,7 @@
@Test
public void recordActivityDoesNotDeleteExistingUids() {
- final WakingActivityHistory history = new WakingActivityHistory();
+ final WakingActivityHistory history = new WakingActivityHistory(() -> Long.MAX_VALUE);
final int subsystem = 42;
long timestamp = 101;
@@ -151,4 +154,120 @@
assertThat(recordedUids.get(62, -1)).isEqualTo(31);
assertThat(recordedUids.get(85, -1)).isEqualTo(39);
}
+
+ @Test
+ public void removeBetween() {
+ final WakingActivityHistory history = new WakingActivityHistory(() -> Long.MAX_VALUE);
+
+ final int subsystem = 43;
+
+ final SparseIntArray uids = new SparseIntArray();
+ uids.put(1, 17);
+ uids.put(15, 2);
+ uids.put(62, 31);
+ history.recordActivity(subsystem, 123, uids);
+
+ uids.put(54, 91);
+ history.recordActivity(subsystem, 150, uids);
+
+ uids.put(101, 32);
+ uids.delete(1);
+ history.recordActivity(subsystem, 191, uids);
+
+ SparseIntArray removedUids = history.removeBetween(subsystem, 100, 122);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 124, 149);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 151, 190);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 192, 240);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+
+ // Removing from a different subsystem should do nothing.
+ removedUids = history.removeBetween(subsystem + 1, 0, 300);
+ assertThat(removedUids).isNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(3);
+
+ removedUids = history.removeBetween(subsystem, 0, 300);
+ assertThat(removedUids.size()).isEqualTo(5);
+ assertThat(removedUids.get(1, -1)).isEqualTo(17);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(0);
+
+ history.recordActivity(subsystem, 23, uids);
+ uids.put(31, 123);
+ history.recordActivity(subsystem, 49, uids);
+ uids.put(177, 432);
+ history.recordActivity(subsystem, 89, uids);
+
+ removedUids = history.removeBetween(subsystem, 23, 23);
+ assertThat(removedUids.size()).isEqualTo(4);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(2);
+
+ removedUids = history.removeBetween(subsystem, 49, 54);
+ assertThat(removedUids.size()).isEqualTo(5);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+ assertThat(removedUids.get(31, -1)).isEqualTo(123);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(1);
+
+ removedUids = history.removeBetween(subsystem, 23, 89);
+ assertThat(removedUids.size()).isEqualTo(6);
+ assertThat(removedUids.get(15, -1)).isEqualTo(2);
+ assertThat(removedUids.get(62, -1)).isEqualTo(31);
+ assertThat(removedUids.get(54, -1)).isEqualTo(91);
+ assertThat(removedUids.get(101, -1)).isEqualTo(32);
+ assertThat(removedUids.get(31, -1)).isEqualTo(123);
+ assertThat(removedUids.get(177, -1)).isEqualTo(432);
+
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(0);
+ }
+
+ @Test
+ public void deletesActivityPastRetention() {
+ final WakingActivityHistory history = new WakingActivityHistory(() -> mTestRetention);
+ final int subsystem = 49;
+
+ mTestRetention = 454;
+
+ final long firstTime = 342;
+ for (int i = 0; i < mTestRetention; i++) {
+ history.recordActivity(subsystem, firstTime + i, new SparseIntArray());
+ }
+ assertThat(history.mWakingActivity.get(subsystem)).isNotNull();
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(mTestRetention);
+
+ history.recordActivity(subsystem, firstTime + mTestRetention + 7, new SparseIntArray());
+ assertThat(history.mWakingActivity.get(subsystem).size()).isEqualTo(mTestRetention - 7);
+
+ final ThreadLocalRandom random = ThreadLocalRandom.current();
+
+ for (int i = 0; i < 100; i++) {
+ final long time = random.nextLong(firstTime + mTestRetention + 100,
+ 456 * mTestRetention);
+ history.recordActivity(subsystem, time, new SparseIntArray());
+ assertThat(history.mWakingActivity.get(subsystem).closestIndexOnOrBefore(
+ time - mTestRetention)).isLessThan(0);
+ }
+ }
}