Home | History | Annotate | Download | only in am
      1 /*
      2  * Copyright (C) 2018 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.am;
     18 
     19 import android.os.PowerManagerInternal;
     20 import android.os.Process;
     21 import android.os.SystemClock;
     22 
     23 import com.android.internal.annotations.GuardedBy;
     24 import com.android.internal.os.BackgroundThread;
     25 import com.android.internal.os.ProcessCpuTracker;
     26 import com.android.internal.util.RingBuffer;
     27 import com.android.internal.util.function.pooled.PooledLambda;
     28 
     29 import java.io.PrintWriter;
     30 
     31 public class OomAdjProfiler {
     32     // Disable profiling for Q. Re-enable once b/130635979 is fixed.
     33     private static final boolean PROFILING_DISABLED = true;
     34 
     35     @GuardedBy("this")
     36     private boolean mOnBattery;
     37     @GuardedBy("this")
     38     private boolean mScreenOff;
     39 
     40     @GuardedBy("this")
     41     private long mOomAdjStartTimeMs;
     42     @GuardedBy("this")
     43     private boolean mOomAdjStarted;
     44 
     45     @GuardedBy("this")
     46     private CpuTimes mOomAdjRunTime = new CpuTimes();
     47     @GuardedBy("this")
     48     private CpuTimes mSystemServerCpuTime = new CpuTimes();
     49 
     50     @GuardedBy("this")
     51     private long mLastSystemServerCpuTimeMs;
     52     @GuardedBy("this")
     53     private boolean mSystemServerCpuTimeUpdateScheduled;
     54     private final ProcessCpuTracker mProcessCpuTracker = new ProcessCpuTracker(false);
     55 
     56     @GuardedBy("this")
     57     final RingBuffer<CpuTimes> mOomAdjRunTimesHist = new RingBuffer<>(CpuTimes.class, 10);
     58     @GuardedBy("this")
     59     final RingBuffer<CpuTimes> mSystemServerCpuTimesHist = new RingBuffer<>(CpuTimes.class, 10);
     60 
     61     void batteryPowerChanged(boolean onBattery) {
     62         if (PROFILING_DISABLED) {
     63             return;
     64         }
     65         synchronized (this) {
     66             scheduleSystemServerCpuTimeUpdate();
     67             mOnBattery = onBattery;
     68         }
     69     }
     70 
     71     void onWakefulnessChanged(int wakefulness) {
     72         if (PROFILING_DISABLED) {
     73             return;
     74         }
     75         synchronized (this) {
     76             scheduleSystemServerCpuTimeUpdate();
     77             mScreenOff = wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE;
     78         }
     79     }
     80 
     81     void oomAdjStarted() {
     82         if (PROFILING_DISABLED) {
     83             return;
     84         }
     85         synchronized (this) {
     86             mOomAdjStartTimeMs = SystemClock.currentThreadTimeMillis();
     87             mOomAdjStarted = true;
     88         }
     89     }
     90 
     91     void oomAdjEnded() {
     92         if (PROFILING_DISABLED) {
     93             return;
     94         }
     95         synchronized (this) {
     96             if (!mOomAdjStarted) {
     97                 return;
     98             }
     99             mOomAdjRunTime.addCpuTimeMs(SystemClock.currentThreadTimeMillis() - mOomAdjStartTimeMs);
    100         }
    101     }
    102 
    103     private void scheduleSystemServerCpuTimeUpdate() {
    104         if (PROFILING_DISABLED) {
    105             return;
    106         }
    107         synchronized (this) {
    108             if (mSystemServerCpuTimeUpdateScheduled) {
    109                 return;
    110             }
    111             mSystemServerCpuTimeUpdateScheduled = true;
    112             BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
    113                     OomAdjProfiler::updateSystemServerCpuTime,
    114                     this, mOnBattery, mScreenOff));
    115         }
    116     }
    117 
    118     private void updateSystemServerCpuTime(boolean onBattery, boolean screenOff) {
    119         if (PROFILING_DISABLED) {
    120             return;
    121         }
    122         final long cpuTimeMs = mProcessCpuTracker.getCpuTimeForPid(Process.myPid());
    123         synchronized (this) {
    124             mSystemServerCpuTime.addCpuTimeMs(
    125                     cpuTimeMs - mLastSystemServerCpuTimeMs, onBattery, screenOff);
    126             mLastSystemServerCpuTimeMs = cpuTimeMs;
    127             mSystemServerCpuTimeUpdateScheduled = false;
    128             notifyAll();
    129         }
    130     }
    131 
    132     void reset() {
    133         synchronized (this) {
    134             if (mSystemServerCpuTime.isEmpty()) {
    135                 return;
    136             }
    137             mOomAdjRunTimesHist.append(mOomAdjRunTime);
    138             mSystemServerCpuTimesHist.append(mSystemServerCpuTime);
    139             mOomAdjRunTime = new CpuTimes();
    140             mSystemServerCpuTime = new CpuTimes();
    141         }
    142     }
    143 
    144     void dump(PrintWriter pw) {
    145         if (PROFILING_DISABLED) {
    146             return;
    147         }
    148         synchronized (this) {
    149             if (mSystemServerCpuTimeUpdateScheduled) {
    150                 while (mSystemServerCpuTimeUpdateScheduled) {
    151                     try {
    152                         wait();
    153                     } catch (InterruptedException e) {
    154                         Thread.currentThread().interrupt();
    155                     }
    156                 }
    157             } else {
    158                 updateSystemServerCpuTime(mOnBattery, mScreenOff);
    159             }
    160 
    161             pw.println("System server and oomAdj runtimes (ms) in recent battery sessions "
    162                     + "(most recent first):");
    163             if (!mSystemServerCpuTime.isEmpty()) {
    164                 pw.print("  ");
    165                 pw.print("system_server=");
    166                 pw.print(mSystemServerCpuTime);
    167                 pw.print("  ");
    168                 pw.print("oom_adj=");
    169                 pw.println(mOomAdjRunTime);
    170             }
    171             final CpuTimes[] systemServerCpuTimes = mSystemServerCpuTimesHist.toArray();
    172             final CpuTimes[] oomAdjRunTimes = mOomAdjRunTimesHist.toArray();
    173             for (int i = oomAdjRunTimes.length - 1; i >= 0; --i) {
    174                 pw.print("  ");
    175                 pw.print("system_server=");
    176                 pw.print(systemServerCpuTimes[i]);
    177                 pw.print("  ");
    178                 pw.print("oom_adj=");
    179                 pw.println(oomAdjRunTimes[i]);
    180             }
    181         }
    182     }
    183 
    184     private class CpuTimes {
    185         private long mOnBatteryTimeMs;
    186         private long mOnBatteryScreenOffTimeMs;
    187 
    188         public void addCpuTimeMs(long cpuTimeMs) {
    189             addCpuTimeMs(cpuTimeMs, mOnBattery, mScreenOff);
    190         }
    191 
    192         public void addCpuTimeMs(long cpuTimeMs, boolean onBattery, boolean screenOff) {
    193             if (onBattery) {
    194                 mOnBatteryTimeMs += cpuTimeMs;
    195                 if (screenOff) {
    196                     mOnBatteryScreenOffTimeMs += cpuTimeMs;
    197                 }
    198             }
    199         }
    200 
    201         public boolean isEmpty() {
    202             return mOnBatteryTimeMs == 0 && mOnBatteryScreenOffTimeMs == 0;
    203         }
    204 
    205         public String toString() {
    206             return "[" + mOnBatteryTimeMs + "," + mOnBatteryScreenOffTimeMs + "]";
    207         }
    208     }
    209 }
    210