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 android.os.BatteryConsumer; 20 import android.os.BatteryStats; 21 import android.os.BatteryUsageStats; 22 import android.os.BatteryUsageStatsQuery; 23 import android.os.Process; 24 import android.os.UidBatteryConsumer; 25 import android.util.Log; 26 import android.util.SparseArray; 27 28 import com.android.internal.os.PowerProfile; 29 30 /** 31 * Estimates the amount of power consumed by the System Server handling requests from 32 * a given app. 33 */ 34 public class SystemServicePowerCalculator extends PowerCalculator { 35 private static final boolean DEBUG = false; 36 private static final String TAG = "SystemServicePowerCalc"; 37 38 // Power estimators per CPU cluster, per CPU frequency. The array is flattened according 39 // to this layout: 40 // {cluster1-speed1, cluster1-speed2, ..., cluster2-speed1, cluster2-speed2, ...} 41 private final UsageBasedPowerEstimator[] mPowerEstimators; 42 private final com.android.server.power.stats.CpuPowerCalculator mCpuPowerCalculator; 43 SystemServicePowerCalculator(PowerProfile powerProfile)44 public SystemServicePowerCalculator(PowerProfile powerProfile) { 45 mCpuPowerCalculator = new CpuPowerCalculator(powerProfile); 46 int numFreqs = 0; 47 final int numCpuClusters = powerProfile.getNumCpuClusters(); 48 for (int cluster = 0; cluster < numCpuClusters; cluster++) { 49 numFreqs += powerProfile.getNumSpeedStepsInCpuCluster(cluster); 50 } 51 52 mPowerEstimators = new UsageBasedPowerEstimator[numFreqs]; 53 int index = 0; 54 for (int cluster = 0; cluster < numCpuClusters; cluster++) { 55 final int numSpeeds = powerProfile.getNumSpeedStepsInCpuCluster(cluster); 56 for (int speed = 0; speed < numSpeeds; speed++) { 57 mPowerEstimators[index++] = new UsageBasedPowerEstimator( 58 powerProfile.getAveragePowerForCpuCore(cluster, speed)); 59 } 60 } 61 } 62 63 @Override isPowerComponentSupported(@atteryConsumer.PowerComponent int powerComponent)64 public boolean isPowerComponentSupported(@BatteryConsumer.PowerComponent int powerComponent) { 65 return powerComponent == BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES; 66 } 67 68 @Override calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query)69 public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats, 70 long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) { 71 final BatteryStats.Uid systemUid = batteryStats.getUidStats().get(Process.SYSTEM_UID); 72 if (systemUid == null) { 73 return; 74 } 75 76 final long consumptionUC = systemUid.getCpuEnergyConsumptionUC(); 77 final int powerModel = getPowerModel(consumptionUC, query); 78 79 double systemServicePowerMah; 80 if (powerModel == BatteryConsumer.POWER_MODEL_ENERGY_CONSUMPTION) { 81 systemServicePowerMah = calculatePowerUsingEnergyConsumption(batteryStats, 82 systemUid, consumptionUC); 83 } else { 84 systemServicePowerMah = calculatePowerUsingPowerProfile(batteryStats); 85 } 86 87 final SparseArray<UidBatteryConsumer.Builder> uidBatteryConsumerBuilders = 88 builder.getUidBatteryConsumerBuilders(); 89 final UidBatteryConsumer.Builder systemServerConsumer = uidBatteryConsumerBuilders.get( 90 Process.SYSTEM_UID); 91 92 if (systemServerConsumer != null) { 93 systemServicePowerMah = Math.min(systemServicePowerMah, 94 systemServerConsumer.getTotalPower()); 95 96 // The system server power needs to be adjusted because part of it got 97 // distributed to applications 98 systemServerConsumer.setConsumedPower( 99 BatteryConsumer.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS, 100 -systemServicePowerMah, powerModel); 101 } 102 103 for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) { 104 final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i); 105 if (app != systemServerConsumer) { 106 final BatteryStats.Uid uid = app.getBatteryStatsUid(); 107 app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, 108 systemServicePowerMah * uid.getProportionalSystemServiceUsage(), 109 powerModel); 110 } 111 } 112 113 builder.getAggregateBatteryConsumerBuilder( 114 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_DEVICE) 115 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, 116 systemServicePowerMah); 117 builder.getAggregateBatteryConsumerBuilder( 118 BatteryUsageStats.AGGREGATE_BATTERY_CONSUMER_SCOPE_ALL_APPS) 119 .setConsumedPower(BatteryConsumer.POWER_COMPONENT_SYSTEM_SERVICES, 120 systemServicePowerMah); 121 } 122 calculatePowerUsingEnergyConsumption(BatteryStats batteryStats, BatteryStats.Uid systemUid, long consumptionUC)123 private double calculatePowerUsingEnergyConsumption(BatteryStats batteryStats, 124 BatteryStats.Uid systemUid, long consumptionUC) { 125 // Use the PowerProfile based model to estimate the ratio between the power consumed 126 // while handling incoming binder calls and the entire System UID power consumption. 127 // Apply that ratio to the _EnergyConsumer_ system UID power consumption to get a more 128 // accurate estimate of the power consumed by incoming binder calls. 129 final double systemServiceModeledPowerMah = calculatePowerUsingPowerProfile(batteryStats); 130 final double systemUidModeledPowerMah = mCpuPowerCalculator.calculateUidModeledPowerMah( 131 systemUid, BatteryStats.STATS_SINCE_CHARGED); 132 133 if (systemUidModeledPowerMah > 0) { 134 return uCtoMah(consumptionUC) * systemServiceModeledPowerMah / systemUidModeledPowerMah; 135 } else { 136 return 0; 137 } 138 } 139 calculatePowerUsingPowerProfile(BatteryStats batteryStats)140 private double calculatePowerUsingPowerProfile(BatteryStats batteryStats) { 141 final long[] systemServiceTimeAtCpuSpeeds = batteryStats.getSystemServiceTimeAtCpuSpeeds(); 142 if (systemServiceTimeAtCpuSpeeds == null) { 143 return 0; 144 } 145 146 // TODO(179210707): additionally account for CPU active and per cluster battery use 147 148 double powerMah = 0; 149 final int size = Math.min(mPowerEstimators.length, systemServiceTimeAtCpuSpeeds.length); 150 for (int i = 0; i < size; i++) { 151 powerMah += mPowerEstimators[i].calculatePower(systemServiceTimeAtCpuSpeeds[i] / 1000); 152 } 153 154 if (DEBUG) { 155 Log.d(TAG, "System service power:" + powerMah); 156 } 157 return powerMah; 158 } 159 } 160