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.annotation.Nullable; 20 import android.os.Process; 21 22 import com.android.internal.annotations.VisibleForTesting; 23 import com.android.internal.os.KernelSingleProcessCpuThreadReader; 24 25 import java.io.IOException; 26 27 /** 28 * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage 29 * by various threads of the System Server. 30 */ 31 public class SystemServerCpuThreadReader { 32 private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader; 33 34 private long[] mLastThreadCpuTimesUs; 35 private long[] mLastBinderThreadCpuTimesUs; 36 37 /** 38 * Times (in microseconds) spent by the system server UID. 39 */ 40 public static class SystemServiceCpuThreadTimes { 41 // All threads 42 public long[] threadCpuTimesUs; 43 // Just the threads handling incoming binder calls 44 public long[] binderThreadCpuTimesUs; 45 } 46 47 private final SystemServiceCpuThreadTimes mDeltaCpuThreadTimes = 48 new SystemServiceCpuThreadTimes(); 49 50 /** 51 * Creates a configured instance of SystemServerCpuThreadReader. 52 */ create()53 public static SystemServerCpuThreadReader create() { 54 return new SystemServerCpuThreadReader( 55 KernelSingleProcessCpuThreadReader.create(Process.myPid())); 56 } 57 58 @VisibleForTesting SystemServerCpuThreadReader(int pid, KernelSingleProcessCpuThreadReader.CpuTimeInStateReader cpuTimeInStateReader)59 public SystemServerCpuThreadReader(int pid, 60 KernelSingleProcessCpuThreadReader.CpuTimeInStateReader cpuTimeInStateReader) 61 throws IOException { 62 this(new KernelSingleProcessCpuThreadReader(pid, cpuTimeInStateReader)); 63 } 64 65 @VisibleForTesting SystemServerCpuThreadReader(KernelSingleProcessCpuThreadReader kernelCpuThreadReader)66 public SystemServerCpuThreadReader(KernelSingleProcessCpuThreadReader kernelCpuThreadReader) { 67 mKernelCpuThreadReader = kernelCpuThreadReader; 68 } 69 70 /** 71 * Start tracking CPU time-in-state for the process specified in the constructor. 72 */ startTrackingThreadCpuTime()73 public void startTrackingThreadCpuTime() { 74 mKernelCpuThreadReader.startTrackingThreadCpuTimes(); 75 } 76 setBinderThreadNativeTids(int[] nativeTids)77 public void setBinderThreadNativeTids(int[] nativeTids) { 78 mKernelCpuThreadReader.setSelectedThreadIds(nativeTids); 79 } 80 81 /** 82 * Returns delta of CPU times, per thread, since the previous call to this method. 83 */ 84 @Nullable readDelta()85 public SystemServiceCpuThreadTimes readDelta() { 86 final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount(); 87 if (mLastThreadCpuTimesUs == null) { 88 mLastThreadCpuTimesUs = new long[numCpuFrequencies]; 89 mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies]; 90 91 mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies]; 92 mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies]; 93 } 94 95 final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage = 96 mKernelCpuThreadReader.getProcessCpuUsage(); 97 if (processCpuUsage == null) { 98 return null; 99 } 100 101 for (int i = numCpuFrequencies - 1; i >= 0; i--) { 102 long threadCpuTimesUs = processCpuUsage.threadCpuTimesMillis[i] * 1000; 103 long binderThreadCpuTimesUs = processCpuUsage.selectedThreadCpuTimesMillis[i] * 1000; 104 mDeltaCpuThreadTimes.threadCpuTimesUs[i] = 105 Math.max(0, threadCpuTimesUs - mLastThreadCpuTimesUs[i]); 106 mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] = 107 Math.max(0, binderThreadCpuTimesUs - mLastBinderThreadCpuTimesUs[i]); 108 mLastThreadCpuTimesUs[i] = threadCpuTimesUs; 109 mLastBinderThreadCpuTimesUs[i] = binderThreadCpuTimesUs; 110 } 111 112 return mDeltaCpuThreadTimes; 113 } 114 115 /** Returns CPU times, per thread group, since tracking started. */ 116 @Nullable readAbsolute()117 public SystemServiceCpuThreadTimes readAbsolute() { 118 final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount(); 119 final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage = 120 mKernelCpuThreadReader.getProcessCpuUsage(); 121 if (processCpuUsage == null) { 122 return null; 123 } 124 final SystemServiceCpuThreadTimes result = new SystemServiceCpuThreadTimes(); 125 result.threadCpuTimesUs = new long[numCpuFrequencies]; 126 result.binderThreadCpuTimesUs = new long[numCpuFrequencies]; 127 for (int i = 0; i < numCpuFrequencies; ++i) { 128 result.threadCpuTimesUs[i] = processCpuUsage.threadCpuTimesMillis[i] * 1_000; 129 result.binderThreadCpuTimesUs[i] = 130 processCpuUsage.selectedThreadCpuTimesMillis[i] * 1_000; 131 } 132 return result; 133 } 134 } 135