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 batteryPowerChanged(boolean onBattery)61 void batteryPowerChanged(boolean onBattery) { 62 if (PROFILING_DISABLED) { 63 return; 64 } 65 synchronized (this) { 66 scheduleSystemServerCpuTimeUpdate(); 67 mOnBattery = onBattery; 68 } 69 } 70 onWakefulnessChanged(int wakefulness)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 oomAdjStarted()81 void oomAdjStarted() { 82 if (PROFILING_DISABLED) { 83 return; 84 } 85 synchronized (this) { 86 mOomAdjStartTimeMs = SystemClock.currentThreadTimeMillis(); 87 mOomAdjStarted = true; 88 } 89 } 90 oomAdjEnded()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 scheduleSystemServerCpuTimeUpdate()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 updateSystemServerCpuTime(boolean onBattery, boolean screenOff)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 reset()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 dump(PrintWriter pw)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 addCpuTimeMs(long cpuTimeMs)188 public void addCpuTimeMs(long cpuTimeMs) { 189 addCpuTimeMs(cpuTimeMs, mOnBattery, mScreenOff); 190 } 191 addCpuTimeMs(long cpuTimeMs, boolean onBattery, boolean screenOff)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 isEmpty()201 public boolean isEmpty() { 202 return mOnBatteryTimeMs == 0 && mOnBatteryScreenOffTimeMs == 0; 203 } 204 toString()205 public String toString() { 206 return "[" + mOnBatteryTimeMs + "," + mOnBatteryScreenOffTimeMs + "]"; 207 } 208 } 209 } 210