blob: 1efce39e00fa62ab1d247d242ce737412560e1a1 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.am;
import static com.android.server.am.MeasuredEnergySnapshot.UNAVAILABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import android.hardware.power.stats.EnergyConsumer;
import android.hardware.power.stats.EnergyConsumerAttribution;
import android.hardware.power.stats.EnergyConsumerResult;
import android.hardware.power.stats.EnergyConsumerType;
import android.util.SparseArray;
import android.util.SparseLongArray;
import androidx.test.filters.SmallTest;
import com.android.server.am.MeasuredEnergySnapshot.MeasuredEnergyDeltaData;
import org.junit.Test;
/**
* Test class for {@link MeasuredEnergySnapshot}.
*
* To run the tests, use
* atest FrameworksServicesTests:com.android.server.am.MeasuredEnergySnapshotTest
*/
@SmallTest
public final class MeasuredEnergySnapshotTest {
private static final EnergyConsumer CONSUMER_DISPLAY = createEnergyConsumer(
0, 0, EnergyConsumerType.DISPLAY, "Display");
private static final EnergyConsumer CONSUMER_OTHER_0 = createEnergyConsumer(
47, 0, EnergyConsumerType.OTHER, "GPU");
private static final EnergyConsumer CONSUMER_OTHER_1 = createEnergyConsumer(
1, 1, EnergyConsumerType.OTHER, "HPU");
private static final EnergyConsumer CONSUMER_OTHER_2 = createEnergyConsumer(
436, 2, EnergyConsumerType.OTHER, "IPU");
private static final SparseArray<EnergyConsumer> ALL_ID_CONSUMER_MAP = createIdToConsumerMap(
CONSUMER_DISPLAY, CONSUMER_OTHER_0, CONSUMER_OTHER_1, CONSUMER_OTHER_2);
private static final SparseArray<EnergyConsumer> SOME_ID_CONSUMER_MAP = createIdToConsumerMap(
CONSUMER_DISPLAY);
// Elements in each results are purposefully out of order.
private static final EnergyConsumerResult[] RESULTS_0 = new EnergyConsumerResult[] {
createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90, new int[] {47, 3}, new long[] {14, 13}),
createEnergyConsumerResult(CONSUMER_DISPLAY.id, 14, null, null),
createEnergyConsumerResult(CONSUMER_OTHER_1.id, 0, null, null),
// No CONSUMER_OTHER_2
};
private static final EnergyConsumerResult[] RESULTS_1 = new EnergyConsumerResult[] {
createEnergyConsumerResult(CONSUMER_DISPLAY.id, 24, null, null),
createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90, new int[] {47, 3}, new long[] {14, 13}),
createEnergyConsumerResult(CONSUMER_OTHER_2.id, 12, new int[] {6}, new long[] {10}),
createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000, null, null),
};
private static final EnergyConsumerResult[] RESULTS_2 = new EnergyConsumerResult[] {
createEnergyConsumerResult(CONSUMER_DISPLAY.id, 36, null, null),
// No CONSUMER_OTHER_0
// No CONSUMER_OTHER_1
// No CONSUMER_OTHER_2
};
private static final EnergyConsumerResult[] RESULTS_3 = new EnergyConsumerResult[] {
// No CONSUMER_DISPLAY
createEnergyConsumerResult(CONSUMER_OTHER_2.id, 13, new int[] {6}, new long[] {10}),
createEnergyConsumerResult(
CONSUMER_OTHER_0.id, 190, new int[] {2, 3, 47, 7}, new long[] {9, 18, 14, 6}),
createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000, null, null),
};
private static final EnergyConsumerResult[] RESULTS_4 = new EnergyConsumerResult[] {
createEnergyConsumerResult(CONSUMER_DISPLAY.id, 43, null, null),
createEnergyConsumerResult(
CONSUMER_OTHER_0.id, 290, new int[] {7, 47, 3, 2}, new long[] {6, 14, 18, 11}),
// No CONSUMER_OTHER_1
createEnergyConsumerResult(CONSUMER_OTHER_2.id, 165, new int[] {6, 47}, new long[] {10, 8}),
};
@Test
public void testUpdateAndGetDelta_empty() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
assertNull(snapshot.updateAndGetDelta(null));
assertNull(snapshot.updateAndGetDelta(new EnergyConsumerResult[0]));
}
@Test
public void testUpdateAndGetDelta() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
// results0
MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0);
if (delta != null) { // null is fine here. If non-null, it better be uninteresting though.
assertEquals(UNAVAILABLE, delta.displayEnergyUJ);
assertNull(delta.otherTotalEnergyUJ);
assertNull(delta.otherUidEnergiesUJ);
}
// results1
delta = snapshot.updateAndGetDelta(RESULTS_1);
assertNotNull(delta);
assertEquals(24 - 14, delta.displayEnergyUJ);
assertNotNull(delta.otherTotalEnergyUJ);
assertEquals(90 - 90, delta.otherTotalEnergyUJ[0]);
assertEquals(12_000 - 0, delta.otherTotalEnergyUJ[1]);
assertEquals(0, delta.otherTotalEnergyUJ[2]); // First good pull. Treat delta as 0.
assertNotNull(delta.otherUidEnergiesUJ);
assertNullOrEmpty(delta.otherUidEnergiesUJ[0]); // No change in uid energies
assertNullOrEmpty(delta.otherUidEnergiesUJ[1]);
assertNullOrEmpty(delta.otherUidEnergiesUJ[2]);
// results2
delta = snapshot.updateAndGetDelta(RESULTS_2);
assertNotNull(delta);
assertEquals(36 - 24, delta.displayEnergyUJ);
assertNull(delta.otherUidEnergiesUJ);
assertNull(delta.otherTotalEnergyUJ);
// results3
delta = snapshot.updateAndGetDelta(RESULTS_3);
assertNotNull(delta);
assertEquals(UNAVAILABLE, delta.displayEnergyUJ);
assertNotNull(delta.otherTotalEnergyUJ);
assertEquals(190 - 90, delta.otherTotalEnergyUJ[0]);
assertEquals(12_000 - 12_000, delta.otherTotalEnergyUJ[1]);
assertEquals(13 - 12, delta.otherTotalEnergyUJ[2]);
assertNotNull(delta.otherUidEnergiesUJ);
assertEquals(3, delta.otherUidEnergiesUJ[0].size());
assertEquals(9 - 0, delta.otherUidEnergiesUJ[0].get(2));
assertEquals(18 - 13, delta.otherUidEnergiesUJ[0].get(3));
assertEquals(6 - 0, delta.otherUidEnergiesUJ[0].get(7));
assertNullOrEmpty(delta.otherUidEnergiesUJ[1]);
assertNullOrEmpty(delta.otherUidEnergiesUJ[2]);
// results4
delta = snapshot.updateAndGetDelta(RESULTS_4);
assertNotNull(delta);
assertEquals(43 - 36, delta.displayEnergyUJ);
assertNotNull(delta.otherTotalEnergyUJ);
assertEquals(290 - 190, delta.otherTotalEnergyUJ[0]);
assertEquals(0, delta.otherTotalEnergyUJ[1]); // Not present (e.g. missing data)
assertEquals(165 - 13, delta.otherTotalEnergyUJ[2]);
assertNotNull(delta.otherUidEnergiesUJ);
assertEquals(1, delta.otherUidEnergiesUJ[0].size());
assertEquals(11 - 9, delta.otherUidEnergiesUJ[0].get(2));
assertNullOrEmpty(delta.otherUidEnergiesUJ[1]); // Not present
assertEquals(1, delta.otherUidEnergiesUJ[2].size());
assertEquals(8, delta.otherUidEnergiesUJ[2].get(47));
}
/** Test updateAndGetDelta() when the results have consumers absent from idToConsumerMap. */
@Test
public void testUpdateAndGetDelta_some() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(SOME_ID_CONSUMER_MAP);
// results0
MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0);
if (delta != null) { // null is fine here. If non-null, it better be uninteresting though.
assertEquals(UNAVAILABLE, delta.displayEnergyUJ);
assertNull(delta.otherTotalEnergyUJ);
assertNull(delta.otherUidEnergiesUJ);
}
// results1
delta = snapshot.updateAndGetDelta(RESULTS_1);
assertNotNull(delta);
assertEquals(24 - 14, delta.displayEnergyUJ);
assertNull(delta.otherTotalEnergyUJ); // Although in the results, they're not in the idMap
assertNull(delta.otherUidEnergiesUJ);
}
@Test
public void testGetNumOtherOrdinals() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
assertEquals(3, snapshot.getNumOtherOrdinals());
}
@Test
public void testGetNumOtherOrdinals_none() {
final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(SOME_ID_CONSUMER_MAP);
assertEquals(0, snapshot.getNumOtherOrdinals());
}
private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) {
final EnergyConsumer ec = new EnergyConsumer();
ec.id = id;
ec.ordinal = ord;
ec.type = type;
ec.name = name;
return ec;
}
private static SparseArray<EnergyConsumer> createIdToConsumerMap(EnergyConsumer ... ecs) {
final SparseArray<EnergyConsumer> map = new SparseArray<>();
for (EnergyConsumer ec : ecs) {
map.put(ec.id, ec);
}
return map;
}
private static EnergyConsumerResult createEnergyConsumerResult(
int id, long energyUWs, int[] uids, long[] uidEnergies) {
final EnergyConsumerResult ecr = new EnergyConsumerResult();
ecr.id = id;
ecr.energyUWs = energyUWs;
if (uids != null) {
ecr.attribution = new EnergyConsumerAttribution[uids.length];
for (int i = 0; i < uids.length; i++) {
ecr.attribution[i] = new EnergyConsumerAttribution();
ecr.attribution[i].uid = uids[i];
ecr.attribution[i].energyUWs = uidEnergies[i];
}
}
return ecr;
}
private void assertNullOrEmpty(SparseLongArray a) {
if (a != null) assertEquals("Array should be null or empty", 0, a.size());
}
}