Merge "Reduce unnecessary overhead in CpuWakeupStats" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
fd8948a928
@@ -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:
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER
|
||||
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.Arrays;
|
||||
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 @@ public class CpuWakeupStats {
|
||||
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 class CpuWakeupStats {
|
||||
|
||||
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 @@ 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 = 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 @@ public class CpuWakeupStats {
|
||||
}
|
||||
|
||||
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 @@ public class CpuWakeupStats {
|
||||
|
||||
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 @@ public class CpuWakeupStats {
|
||||
*/
|
||||
@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 @@ public class CpuWakeupStats {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 @@ public class CpuWakeupStats {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class CpuWakeupStats {
|
||||
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 @@ public class CpuWakeupStats {
|
||||
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 @@ public class CpuWakeupStats {
|
||||
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 @@ public class CpuWakeupStats {
|
||||
+ ", mElapsedMillis=" + mElapsedMillis
|
||||
+ ", mUptimeMillis=" + mUptimeMillis
|
||||
+ ", mDevices=" + Arrays.toString(mDevices)
|
||||
+ ", mResponsibleSubsystems=" + mResponsibleSubsystems
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -672,18 +658,28 @@ public class CpuWakeupStats {
|
||||
|
||||
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 @@ public class CpuWakeupStats {
|
||||
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 @@ public class CpuWakeupStats {
|
||||
|
||||
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();
|
||||
|
||||
@@ -23,8 +23,6 @@ import static android.os.BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_SOUND_TRIGGER
|
||||
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 @@ public class CpuWakeupStatsTest {
|
||||
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 @@ public class CpuWakeupStatsTest {
|
||||
|
||||
@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 @@ public class CpuWakeupStatsTest {
|
||||
|
||||
// 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 @@ public class CpuWakeupStatsTest {
|
||||
|
||||
// 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 @@ public class CpuWakeupStatsTest {
|
||||
|
||||
// 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 @@ public class CpuWakeupStatsTest {
|
||||
// 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 @@ public class CpuWakeupStatsTest {
|
||||
// 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 @@ public class CpuWakeupStatsTest {
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
@@ -28,8 +28,11 @@ import com.android.server.power.stats.wakeups.CpuWakeupStats.WakingActivityHisto
|
||||
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 @@ public class WakingActivityHistoryTest {
|
||||
|
||||
@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 @@ public class WakingActivityHistoryTest {
|
||||
|
||||
@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 @@ public class WakingActivityHistoryTest {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user