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