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