19b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka/* 29b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * Copyright (C) 2017 The Android Open Source Project 39b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * 49b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * Licensed under the Apache License, Version 2.0 (the "License"); 59b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * you may not use this file except in compliance with the License. 69b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * You may obtain a copy of the License at 79b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * 89b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * http://www.apache.org/licenses/LICENSE-2.0 99b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * 109b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * Unless required by applicable law or agreed to in writing, software 119b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * distributed under the License is distributed on an "AS IS" BASIS, 129b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * See the License for the specific language governing permissions and 149b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * limitations under the License. 159b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka */ 169b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 179b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankapackage com.android.internal.os; 189b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 199b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport android.annotation.Nullable; 209b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport android.util.Slog; 219b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport android.util.SparseArray; 229b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 239b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport com.android.internal.annotations.VisibleForTesting; 249b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 259b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport java.io.BufferedReader; 269b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport java.io.FileReader; 279b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankaimport java.io.IOException; 289b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 299b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka/** 309b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * Reads /proc/uid_time_in_state which has the format: 319b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * 329b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * uid: [freq1] [freq2] [freq3] ... 339b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * [uid1]: [time in freq1] [time in freq2] [time in freq3] ... 349b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * [uid2]: [time in freq1] [time in freq2] [time in freq3] ... 359b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * ... 369b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * 379b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * This provides the times a UID's processes spent executing at each different cpu frequency. 389b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * The file contains a monotonically increasing count of time for a single boot. This class 399b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * maintains the previous results of a call to {@link #readDelta} in order to provide a proper 409b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka * delta. 419b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka */ 429b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shankapublic class KernelUidCpuFreqTimeReader { 439b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private static final String TAG = "KernelUidCpuFreqTimeReader"; 449b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; 459b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 469b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka public interface Callback { 479b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka void onCpuFreqs(long[] cpuFreqs); 489b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs); 499b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 509b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 519b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private long[] mCpuFreqs; 529b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private int mCpuFreqsCount; 539b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 549b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private SparseArray<long[]> mLastUidCpuFreqTimeMs = new SparseArray<>(); 559b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 56acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka // We check the existence of proc file a few times (just in case it is not ready yet when we 57acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka // start reading) and if it is not available, we simply ignore further read requests. 58acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka private static final int TOTAL_READ_ERROR_COUNT = 5; 59acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka private int mReadErrorCounter; 60acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka private boolean mProcFileAvailable; 61acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka 629b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka public void readDelta(@Nullable Callback callback) { 63acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka if (!mProcFileAvailable && mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) { 64acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka return; 65acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka } 669b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { 679b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka readDelta(reader, callback); 68acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka mProcFileAvailable = true; 699b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } catch (IOException e) { 70acd7f2c78320051ddf85448b067e35a71ca3b400Sudheer Shanka mReadErrorCounter++; 719b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e); 729b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 739b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 749b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 756d8dcec87200e75ca62715c8feb87794d113e957Sudheer Shanka public void removeUid(int uid) { 766d8dcec87200e75ca62715c8feb87794d113e957Sudheer Shanka mLastUidCpuFreqTimeMs.delete(uid); 776d8dcec87200e75ca62715c8feb87794d113e957Sudheer Shanka } 786d8dcec87200e75ca62715c8feb87794d113e957Sudheer Shanka 799b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka @VisibleForTesting 809b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka public void readDelta(BufferedReader reader, @Nullable Callback callback) throws IOException { 819b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka String line = reader.readLine(); 829b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka if (line == null) { 839b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka return; 849b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 859b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka readCpuFreqs(line, callback); 869b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka while ((line = reader.readLine()) != null) { 879b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final int index = line.indexOf(' '); 889b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final int uid = Integer.parseInt(line.substring(0, index - 1), 10); 899b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka readTimesForUid(uid, line.substring(index + 1, line.length()), callback); 909b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 919b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 929b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 939b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private void readTimesForUid(int uid, String line, Callback callback) { 949b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka long[] uidTimeMs = mLastUidCpuFreqTimeMs.get(uid); 959b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka if (uidTimeMs == null) { 969b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka uidTimeMs = new long[mCpuFreqsCount]; 979b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka mLastUidCpuFreqTimeMs.put(uid, uidTimeMs); 989b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 999b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final String[] timesStr = line.split(" "); 1009b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final int size = timesStr.length; 1019b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka if (size != uidTimeMs.length) { 1029b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka Slog.e(TAG, "No. of readings don't match cpu freqs, readings: " + size 1039b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka + " cpuFreqsCount: " + uidTimeMs.length); 1049b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka return; 1059b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1069b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final long[] deltaUidTimeMs = new long[size]; 1079b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka for (int i = 0; i < size; ++i) { 1089b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka // Times read will be in units of 10ms 1099b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final long totalTimeMs = Long.parseLong(timesStr[i], 10) * 10; 1109b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka deltaUidTimeMs[i] = totalTimeMs - uidTimeMs[i]; 1119b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka uidTimeMs[i] = totalTimeMs; 1129b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1139b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka if (callback != null) { 1149b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka callback.onUidCpuFreqTime(uid, deltaUidTimeMs); 1159b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1169b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1179b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka 1189b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka private void readCpuFreqs(String line, Callback callback) { 1199b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka if (mCpuFreqs == null) { 1209b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka final String[] freqStr = line.split(" "); 1219b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka // First item would be "uid:" which needs to be ignored 1229b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka mCpuFreqsCount = freqStr.length - 1; 1239b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka mCpuFreqs = new long[mCpuFreqsCount]; 1249b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka for (int i = 0; i < mCpuFreqsCount; ++i) { 1259b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka mCpuFreqs[i] = Long.parseLong(freqStr[i + 1], 10); 1269b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1279b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1289b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka if (callback != null) { 1299b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka callback.onCpuFreqs(mCpuFreqs); 1309b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1319b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka } 1329b735c5c1a4575d9f0ea9f3229ad8bf9401caee0Sudheer Shanka} 133