Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2015 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 package com.android.internal.os;
     17 
     18 import android.os.BatteryStats;
     19 import android.util.ArrayMap;
     20 import android.util.Log;
     21 
     22 public class CpuPowerCalculator extends PowerCalculator {
     23     private static final String TAG = "CpuPowerCalculator";
     24     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
     25     private final PowerProfile mProfile;
     26 
     27     public CpuPowerCalculator(PowerProfile profile) {
     28         mProfile = profile;
     29     }
     30 
     31     @Override
     32     public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
     33                              long rawUptimeUs, int statsType) {
     34 
     35         app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
     36 
     37         // Aggregate total time spent on each cluster.
     38         long totalTime = 0;
     39         final int numClusters = mProfile.getNumCpuClusters();
     40         for (int cluster = 0; cluster < numClusters; cluster++) {
     41             final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster);
     42             for (int speed = 0; speed < speedsForCluster; speed++) {
     43                 totalTime += u.getTimeAtCpuSpeed(cluster, speed, statsType);
     44             }
     45         }
     46         totalTime = Math.max(totalTime, 1);
     47 
     48         double cpuPowerMaMs = 0;
     49         for (int cluster = 0; cluster < numClusters; cluster++) {
     50             final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster);
     51             for (int speed = 0; speed < speedsForCluster; speed++) {
     52                 final double ratio = (double) u.getTimeAtCpuSpeed(cluster, speed, statsType) /
     53                         totalTime;
     54                 final double cpuSpeedStepPower = ratio * app.cpuTimeMs *
     55                         mProfile.getAveragePowerForCpu(cluster, speed);
     56                 if (DEBUG && ratio != 0) {
     57                     Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
     58                             + speed + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
     59                             + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
     60                 }
     61                 cpuPowerMaMs += cpuSpeedStepPower;
     62             }
     63         }
     64         app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
     65 
     66         if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
     67             Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
     68                     + BatteryStatsHelper.makemAh(app.cpuPowerMah));
     69         }
     70 
     71         // Keep track of the package with highest drain.
     72         double highestDrain = 0;
     73 
     74         app.cpuFgTimeMs = 0;
     75         final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
     76         final int processStatsCount = processStats.size();
     77         for (int i = 0; i < processStatsCount; i++) {
     78             final BatteryStats.Uid.Proc ps = processStats.valueAt(i);
     79             final String processName = processStats.keyAt(i);
     80             app.cpuFgTimeMs += ps.getForegroundTime(statsType);
     81 
     82             final long costValue = ps.getUserTime(statsType) + ps.getSystemTime(statsType)
     83                     + ps.getForegroundTime(statsType);
     84 
     85             // Each App can have multiple packages and with multiple running processes.
     86             // Keep track of the package who's process has the highest drain.
     87             if (app.packageWithHighestDrain == null ||
     88                     app.packageWithHighestDrain.startsWith("*")) {
     89                 highestDrain = costValue;
     90                 app.packageWithHighestDrain = processName;
     91             } else if (highestDrain < costValue && !processName.startsWith("*")) {
     92                 highestDrain = costValue;
     93                 app.packageWithHighestDrain = processName;
     94             }
     95         }
     96 
     97         // Ensure that the CPU times make sense.
     98         if (app.cpuFgTimeMs > app.cpuTimeMs) {
     99             if (DEBUG && app.cpuFgTimeMs > app.cpuTimeMs + 10000) {
    100                 Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
    101             }
    102 
    103             // Statistics may not have been gathered yet.
    104             app.cpuTimeMs = app.cpuFgTimeMs;
    105         }
    106     }
    107 }
    108