blob: 3ed59f1d437085f2a92b639a9ac7bad4277ae0fe [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.os;
import android.annotation.Nullable;
import android.os.Process;
import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
/**
* Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
* by various threads of the System Server.
*/
public class SystemServerCpuThreadReader {
private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
private long[] mLastThreadCpuTimesUs;
private long[] mLastBinderThreadCpuTimesUs;
/**
* Times (in microseconds) spent by the system server UID.
*/
public static class SystemServiceCpuThreadTimes {
// All threads
public long[] threadCpuTimesUs;
// Just the threads handling incoming binder calls
public long[] binderThreadCpuTimesUs;
}
private final SystemServiceCpuThreadTimes mDeltaCpuThreadTimes =
new SystemServiceCpuThreadTimes();
/**
* Creates a configured instance of SystemServerCpuThreadReader.
*/
public static SystemServerCpuThreadReader create() {
return new SystemServerCpuThreadReader(
KernelSingleProcessCpuThreadReader.create(Process.myPid()));
}
@VisibleForTesting
public SystemServerCpuThreadReader(int pid,
KernelSingleProcessCpuThreadReader.CpuTimeInStateReader cpuTimeInStateReader)
throws IOException {
this(new KernelSingleProcessCpuThreadReader(pid, cpuTimeInStateReader));
}
@VisibleForTesting
public SystemServerCpuThreadReader(KernelSingleProcessCpuThreadReader kernelCpuThreadReader) {
mKernelCpuThreadReader = kernelCpuThreadReader;
}
/**
* Start tracking CPU time-in-state for the process specified in the constructor.
*/
public void startTrackingThreadCpuTime() {
mKernelCpuThreadReader.startTrackingThreadCpuTimes();
}
public void setBinderThreadNativeTids(int[] nativeTids) {
mKernelCpuThreadReader.setSelectedThreadIds(nativeTids);
}
/**
* Returns delta of CPU times, per thread, since the previous call to this method.
*/
@Nullable
public SystemServiceCpuThreadTimes readDelta() {
final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
if (mLastThreadCpuTimesUs == null) {
mLastThreadCpuTimesUs = new long[numCpuFrequencies];
mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
}
final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
mKernelCpuThreadReader.getProcessCpuUsage();
if (processCpuUsage == null) {
return null;
}
for (int i = numCpuFrequencies - 1; i >= 0; i--) {
long threadCpuTimesUs = processCpuUsage.threadCpuTimesMillis[i] * 1000;
long binderThreadCpuTimesUs = processCpuUsage.selectedThreadCpuTimesMillis[i] * 1000;
mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
Math.max(0, threadCpuTimesUs - mLastThreadCpuTimesUs[i]);
mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
Math.max(0, binderThreadCpuTimesUs - mLastBinderThreadCpuTimesUs[i]);
mLastThreadCpuTimesUs[i] = threadCpuTimesUs;
mLastBinderThreadCpuTimesUs[i] = binderThreadCpuTimesUs;
}
return mDeltaCpuThreadTimes;
}
/** Returns CPU times, per thread group, since tracking started. */
@Nullable
public SystemServiceCpuThreadTimes readAbsolute() {
final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
mKernelCpuThreadReader.getProcessCpuUsage();
if (processCpuUsage == null) {
return null;
}
final SystemServiceCpuThreadTimes result = new SystemServiceCpuThreadTimes();
result.threadCpuTimesUs = new long[numCpuFrequencies];
result.binderThreadCpuTimesUs = new long[numCpuFrequencies];
for (int i = 0; i < numCpuFrequencies; ++i) {
result.threadCpuTimesUs[i] = processCpuUsage.threadCpuTimesMillis[i] * 1_000;
result.binderThreadCpuTimesUs[i] =
processCpuUsage.selectedThreadCpuTimesMillis[i] * 1_000;
}
return result;
}
}