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