1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.power.stats; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 import static org.junit.Assert.assertNull; 24 25 import android.hardware.power.stats.EnergyConsumer; 26 import android.hardware.power.stats.EnergyConsumerAttribution; 27 import android.hardware.power.stats.EnergyConsumerResult; 28 import android.hardware.power.stats.EnergyConsumerType; 29 import android.util.SparseArray; 30 import android.util.SparseLongArray; 31 32 import androidx.test.filters.SmallTest; 33 34 import com.android.server.power.stats.EnergyConsumerSnapshot.EnergyConsumerDeltaData; 35 36 import org.junit.Test; 37 38 /** 39 * Test class for {@link EnergyConsumerSnapshot}. 40 * 41 * To run the tests, use 42 * atest FrameworksServicesTests:com.android.server.power.stats.MeasuredEnergySnapshotTest 43 */ 44 @SmallTest 45 public final class EnergyConsumerSnapshotTest { 46 private static final EnergyConsumer CONSUMER_DISPLAY = createEnergyConsumer( 47 0, 0, EnergyConsumerType.DISPLAY, "Display"); 48 private static final EnergyConsumer CONSUMER_OTHER_0 = createEnergyConsumer( 49 47, 0, EnergyConsumerType.OTHER, "GPU"); 50 private static final EnergyConsumer CONSUMER_OTHER_1 = createEnergyConsumer( 51 1, 1, EnergyConsumerType.OTHER, "HPU"); 52 private static final EnergyConsumer CONSUMER_OTHER_2 = createEnergyConsumer( 53 436, 2, EnergyConsumerType.OTHER, "IPU\n&\005"); 54 55 private static final SparseArray<EnergyConsumer> ALL_ID_CONSUMER_MAP = createIdToConsumerMap( 56 CONSUMER_DISPLAY, CONSUMER_OTHER_0, CONSUMER_OTHER_1, CONSUMER_OTHER_2); 57 private static final SparseArray<EnergyConsumer> SOME_ID_CONSUMER_MAP = createIdToConsumerMap( 58 CONSUMER_DISPLAY); 59 60 private static final int VOLTAGE_0 = 4_000; 61 private static final int VOLTAGE_1 = 3_500; 62 private static final int VOLTAGE_2 = 3_100; 63 private static final int VOLTAGE_3 = 3_000; 64 private static final int VOLTAGE_4 = 2_800; 65 66 // Elements in each results are purposefully out of order. 67 private static final EnergyConsumerResult[] RESULTS_0 = new EnergyConsumerResult[]{ 68 createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90_000, new int[]{47, 3}, 69 new long[]{14_000, 13_000}), 70 createEnergyConsumerResult(CONSUMER_DISPLAY.id, 14_000, null, null), 71 createEnergyConsumerResult(CONSUMER_OTHER_1.id, 0, null, null), 72 // No CONSUMER_OTHER_2 73 }; 74 private static final EnergyConsumerResult[] RESULTS_1 = new EnergyConsumerResult[]{ 75 createEnergyConsumerResult(CONSUMER_DISPLAY.id, 24_000, null, null), 76 createEnergyConsumerResult(CONSUMER_OTHER_0.id, 90_000, new int[]{47, 3}, 77 new long[]{14_000, 13_000}), 78 createEnergyConsumerResult(CONSUMER_OTHER_2.id, 12_000, new int[]{6}, 79 new long[]{10_000}), 80 createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000_000, null, null), 81 }; 82 private static final EnergyConsumerResult[] RESULTS_2 = new EnergyConsumerResult[]{ 83 createEnergyConsumerResult(CONSUMER_DISPLAY.id, 36_000, null, null), 84 // No CONSUMER_OTHER_0 85 // No CONSUMER_OTHER_1 86 // No CONSUMER_OTHER_2 87 }; 88 private static final EnergyConsumerResult[] RESULTS_3 = new EnergyConsumerResult[]{ 89 // No CONSUMER_DISPLAY 90 createEnergyConsumerResult(CONSUMER_OTHER_2.id, 13_000, new int[]{6}, 91 new long[]{10_000}), 92 createEnergyConsumerResult( 93 CONSUMER_OTHER_0.id, 190_000, new int[]{2, 3, 47, 7}, 94 new long[]{9_000, 18_000, 14_000, 6_000}), 95 createEnergyConsumerResult(CONSUMER_OTHER_1.id, 12_000_000, null, null), 96 }; 97 private static final EnergyConsumerResult[] RESULTS_4 = new EnergyConsumerResult[]{ 98 createEnergyConsumerResult(CONSUMER_DISPLAY.id, 43_000, null, null), 99 createEnergyConsumerResult( 100 CONSUMER_OTHER_0.id, 290_000, new int[]{7, 47, 3, 2}, 101 new long[]{6_000, 14_000, 18_000, 11_000}), 102 // No CONSUMER_OTHER_1 103 createEnergyConsumerResult(CONSUMER_OTHER_2.id, 165_000, new int[]{6, 47}, 104 new long[]{10_000, 8_000}), 105 }; 106 107 @Test testUpdateAndGetDelta_empty()108 public void testUpdateAndGetDelta_empty() { 109 final EnergyConsumerSnapshot snapshot = new EnergyConsumerSnapshot(ALL_ID_CONSUMER_MAP); 110 assertNull(snapshot.updateAndGetDelta(null, VOLTAGE_0)); 111 assertNull(snapshot.updateAndGetDelta(new EnergyConsumerResult[0], VOLTAGE_0)); 112 } 113 114 @Test testUpdateAndGetDelta()115 public void testUpdateAndGetDelta() { 116 final EnergyConsumerSnapshot snapshot = new EnergyConsumerSnapshot(ALL_ID_CONSUMER_MAP); 117 118 // results0 119 EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0); 120 if (delta != null) { // null is fine here. If non-null, it better be uninteresting though. 121 assertNull(delta.displayChargeUC); 122 assertNull(delta.otherTotalChargeUC); 123 assertNull(delta.otherUidChargesUC); 124 } 125 126 // results1 127 delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1); 128 assertNotNull(delta); 129 long expectedChargeUC; 130 expectedChargeUC = calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1); 131 assertEquals(expectedChargeUC, delta.displayChargeUC[0]); 132 133 assertNotNull(delta.otherTotalChargeUC); 134 135 expectedChargeUC = calculateChargeConsumedUC(90_000, VOLTAGE_0, 90_000, VOLTAGE_1); 136 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]); 137 expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_0, 12_000_000, VOLTAGE_1); 138 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[1]); 139 assertEquals(0, delta.otherTotalChargeUC[2]); // First good pull. Treat delta as 0. 140 141 assertNotNull(delta.otherUidChargesUC); 142 assertNullOrEmpty(delta.otherUidChargesUC[0]); // No change in uid energies 143 assertNullOrEmpty(delta.otherUidChargesUC[1]); 144 assertNullOrEmpty(delta.otherUidChargesUC[2]); 145 146 // results2 147 delta = snapshot.updateAndGetDelta(RESULTS_2, VOLTAGE_2); 148 assertNotNull(delta); 149 expectedChargeUC = calculateChargeConsumedUC(24_000, VOLTAGE_1, 36_000, VOLTAGE_2); 150 assertEquals(expectedChargeUC, delta.displayChargeUC[0]); 151 assertNull(delta.otherUidChargesUC); 152 assertNull(delta.otherTotalChargeUC); 153 154 // results3 155 delta = snapshot.updateAndGetDelta(RESULTS_3, VOLTAGE_3); 156 assertNotNull(delta); 157 assertNull(delta.displayChargeUC); 158 159 assertNotNull(delta.otherTotalChargeUC); 160 161 expectedChargeUC = calculateChargeConsumedUC(90_000, VOLTAGE_1, 190_000, VOLTAGE_3); 162 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]); 163 expectedChargeUC = calculateChargeConsumedUC(12_000_000, VOLTAGE_1, 12_000_000, VOLTAGE_3); 164 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[1]); 165 expectedChargeUC = calculateChargeConsumedUC(12_000, VOLTAGE_1, 13_000, VOLTAGE_3); 166 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[2]); 167 168 assertNotNull(delta.otherUidChargesUC); 169 170 assertEquals(3, delta.otherUidChargesUC[0].size()); 171 expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_1, 9_000, VOLTAGE_3); 172 assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(2)); 173 expectedChargeUC = calculateChargeConsumedUC(13_000, VOLTAGE_1, 18_000, VOLTAGE_3); 174 assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(3)); 175 expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_1, 6_000, VOLTAGE_3); 176 assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(7)); 177 assertNullOrEmpty(delta.otherUidChargesUC[1]); 178 assertNullOrEmpty(delta.otherUidChargesUC[2]); 179 180 // results4 181 delta = snapshot.updateAndGetDelta(RESULTS_4, VOLTAGE_4); 182 assertNotNull(delta); 183 expectedChargeUC = calculateChargeConsumedUC(36_000, VOLTAGE_2, 43_000, VOLTAGE_4); 184 assertEquals(expectedChargeUC, delta.displayChargeUC[0]); 185 186 assertNotNull(delta.otherTotalChargeUC); 187 expectedChargeUC = calculateChargeConsumedUC(190_000, VOLTAGE_3, 290_000, VOLTAGE_4); 188 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[0]); 189 assertEquals(0, delta.otherTotalChargeUC[1]); // Not present (e.g. missing data) 190 expectedChargeUC = calculateChargeConsumedUC(13_000, VOLTAGE_3, 165_000, VOLTAGE_4); 191 assertEquals(expectedChargeUC, delta.otherTotalChargeUC[2]); 192 193 assertNotNull(delta.otherUidChargesUC); 194 assertEquals(1, delta.otherUidChargesUC[0].size()); 195 expectedChargeUC = calculateChargeConsumedUC(9_000, VOLTAGE_3, 11_000, VOLTAGE_4); 196 assertEquals(expectedChargeUC, delta.otherUidChargesUC[0].get(2)); 197 assertNullOrEmpty(delta.otherUidChargesUC[1]); // Not present 198 assertEquals(1, delta.otherUidChargesUC[2].size()); 199 expectedChargeUC = calculateChargeConsumedUC(0, VOLTAGE_3, 8_000, VOLTAGE_4); 200 assertEquals(expectedChargeUC, delta.otherUidChargesUC[2].get(47)); 201 } 202 203 /** Test updateAndGetDelta() when the results have consumers absent from idToConsumerMap. */ 204 @Test testUpdateAndGetDelta_some()205 public void testUpdateAndGetDelta_some() { 206 final EnergyConsumerSnapshot snapshot = new EnergyConsumerSnapshot(SOME_ID_CONSUMER_MAP); 207 208 // results0 209 EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0); 210 if (delta != null) { // null is fine here. If non-null, it better be uninteresting though. 211 assertNull(delta.displayChargeUC); 212 assertNull(delta.otherTotalChargeUC); 213 assertNull(delta.otherUidChargesUC); 214 } 215 216 // results1 217 delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1); 218 assertNotNull(delta); 219 final long expectedChargeUC = 220 calculateChargeConsumedUC(14_000, VOLTAGE_0, 24_000, VOLTAGE_1); 221 assertEquals(expectedChargeUC, delta.displayChargeUC[0]); 222 assertNull(delta.otherTotalChargeUC); // Although in the results, they're not in the idMap 223 assertNull(delta.otherUidChargesUC); 224 } 225 226 @Test testGetOtherOrdinalNames()227 public void testGetOtherOrdinalNames() { 228 final EnergyConsumerSnapshot snapshot = new EnergyConsumerSnapshot(ALL_ID_CONSUMER_MAP); 229 assertThat(snapshot.getOtherOrdinalNames()).asList() 230 .containsExactly("GPU", "HPU", "IPU &_"); 231 } 232 233 @Test testGetOtherOrdinalNames_none()234 public void testGetOtherOrdinalNames_none() { 235 final EnergyConsumerSnapshot snapshot = new EnergyConsumerSnapshot(SOME_ID_CONSUMER_MAP); 236 assertEquals(0, snapshot.getOtherOrdinalNames().length); 237 } 238 239 @Test testUpdateAndGetDelta_updatesCameraCharge()240 public void testUpdateAndGetDelta_updatesCameraCharge() { 241 EnergyConsumer cameraConsumer = 242 createEnergyConsumer(7, 0, EnergyConsumerType.CAMERA, "CAMERA"); 243 final EnergyConsumerSnapshot snapshot = 244 new EnergyConsumerSnapshot(createIdToConsumerMap(cameraConsumer)); 245 246 // An initial result with only one energy consumer 247 EnergyConsumerResult[] result0 = new EnergyConsumerResult[]{ 248 createEnergyConsumerResult(cameraConsumer.id, 60_000, null, null), 249 }; 250 snapshot.updateAndGetDelta(result0, VOLTAGE_1); 251 252 // A subsequent result 253 EnergyConsumerResult[] result1 = new EnergyConsumerResult[]{ 254 createEnergyConsumerResult(cameraConsumer.id, 90_000, null, null), 255 }; 256 EnergyConsumerDeltaData delta = snapshot.updateAndGetDelta(result1, VOLTAGE_1); 257 long expectedDeltaUC = calculateChargeConsumedUC(60_000, VOLTAGE_1, 90_000, VOLTAGE_1); 258 assertThat(delta.cameraChargeUC).isEqualTo(expectedDeltaUC); 259 } 260 createEnergyConsumer(int id, int ord, byte type, String name)261 private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) { 262 final EnergyConsumer ec = new EnergyConsumer(); 263 ec.id = id; 264 ec.ordinal = ord; 265 ec.type = type; 266 ec.name = name; 267 return ec; 268 } 269 createIdToConsumerMap(EnergyConsumer .... ecs)270 private static SparseArray<EnergyConsumer> createIdToConsumerMap(EnergyConsumer ... ecs) { 271 final SparseArray<EnergyConsumer> map = new SparseArray<>(); 272 for (EnergyConsumer ec : ecs) { 273 map.put(ec.id, ec); 274 } 275 return map; 276 } 277 createEnergyConsumerResult( int id, long energyUWs, int[] uids, long[] uidEnergies)278 private static EnergyConsumerResult createEnergyConsumerResult( 279 int id, long energyUWs, int[] uids, long[] uidEnergies) { 280 final EnergyConsumerResult ecr = new EnergyConsumerResult(); 281 ecr.id = id; 282 ecr.energyUWs = energyUWs; 283 if (uids != null) { 284 ecr.attribution = new EnergyConsumerAttribution[uids.length]; 285 for (int i = 0; i < uids.length; i++) { 286 ecr.attribution[i] = new EnergyConsumerAttribution(); 287 ecr.attribution[i].uid = uids[i]; 288 ecr.attribution[i].energyUWs = uidEnergies[i]; 289 } 290 } 291 return ecr; 292 } 293 calculateChargeConsumedUC(long energyUWs0, long voltageMv0, long energyUWs1, long voltageMv1)294 private static long calculateChargeConsumedUC(long energyUWs0, long voltageMv0, long energyUWs1, 295 long voltageMv1) { 296 final long deltaEnergyUWs = energyUWs1 - energyUWs0; 297 final long avgVoltageMv = (voltageMv1 + voltageMv0 + 1) / 2; 298 299 // Charge uC = Energy uWs * (1000 mV/V) / (voltage mV) + 0.5 (for rounding) 300 return (deltaEnergyUWs * 1000 + (avgVoltageMv / 2)) / avgVoltageMv; 301 } 302 assertNullOrEmpty(SparseLongArray a)303 private void assertNullOrEmpty(SparseLongArray a) { 304 if (a != null) assertEquals("Array should be null or empty", 0, a.size()); 305 } 306 } 307