• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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