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