1 /* 2 * Copyright (C) 2015 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 package com.android.internal.os; 17 18 import android.system.Os; 19 import android.text.TextUtils; 20 import android.os.StrictMode; 21 import android.system.OsConstants; 22 import android.util.Slog; 23 24 import java.io.BufferedReader; 25 import java.io.FileReader; 26 import java.io.IOException; 27 import java.util.Arrays; 28 29 /** 30 * Reads CPU time of a specific core spent at various frequencies and provides a delta from the 31 * last call to {@link #readDelta}. Each line in the proc file has the format: 32 * 33 * freq time 34 * 35 * where time is measured in jiffies. 36 */ 37 public class KernelCpuSpeedReader { 38 private static final String TAG = "KernelCpuSpeedReader"; 39 40 private final String mProcFile; 41 private final int mNumSpeedSteps; 42 private final long[] mLastSpeedTimesMs; 43 private final long[] mDeltaSpeedTimesMs; 44 45 // How long a CPU jiffy is in milliseconds. 46 private final long mJiffyMillis; 47 48 /** 49 * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read. 50 */ KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps)51 public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) { 52 mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", 53 cpuNumber); 54 mNumSpeedSteps = numSpeedSteps; 55 mLastSpeedTimesMs = new long[numSpeedSteps]; 56 mDeltaSpeedTimesMs = new long[numSpeedSteps]; 57 long jiffyHz = Os.sysconf(OsConstants._SC_CLK_TCK); 58 mJiffyMillis = 1000/jiffyHz; 59 } 60 61 /** 62 * The returned array is modified in subsequent calls to {@link #readDelta}. 63 * @return The time (in milliseconds) spent at different cpu speeds since the last call to 64 * {@link #readDelta}. 65 */ readDelta()66 public long[] readDelta() { 67 StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads(); 68 try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) { 69 TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); 70 String line; 71 int speedIndex = 0; 72 while (speedIndex < mLastSpeedTimesMs.length && (line = reader.readLine()) != null) { 73 splitter.setString(line); 74 splitter.next(); 75 76 long time = Long.parseLong(splitter.next()) * mJiffyMillis; 77 if (time < mLastSpeedTimesMs[speedIndex]) { 78 // The stats reset when the cpu hotplugged. That means that the time 79 // we read is offset from 0, so the time is the delta. 80 mDeltaSpeedTimesMs[speedIndex] = time; 81 } else { 82 mDeltaSpeedTimesMs[speedIndex] = time - mLastSpeedTimesMs[speedIndex]; 83 } 84 mLastSpeedTimesMs[speedIndex] = time; 85 speedIndex++; 86 } 87 } catch (IOException e) { 88 Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage()); 89 Arrays.fill(mDeltaSpeedTimesMs, 0); 90 } finally { 91 StrictMode.setThreadPolicy(policy); 92 } 93 return mDeltaSpeedTimesMs; 94 } 95 96 /** 97 * @return The time (in milliseconds) spent at different cpu speeds. The values should be 98 * monotonically increasing, unless the cpu was hotplugged. 99 */ readAbsolute()100 public long[] readAbsolute() { 101 StrictMode.ThreadPolicy policy = StrictMode.allowThreadDiskReads(); 102 long[] speedTimeMs = new long[mNumSpeedSteps]; 103 try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) { 104 TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); 105 String line; 106 int speedIndex = 0; 107 while (speedIndex < mNumSpeedSteps && (line = reader.readLine()) != null) { 108 splitter.setString(line); 109 splitter.next(); 110 long time = Long.parseLong(splitter.next()) * mJiffyMillis; 111 speedTimeMs[speedIndex] = time; 112 speedIndex++; 113 } 114 } catch (IOException e) { 115 Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage()); 116 Arrays.fill(speedTimeMs, 0); 117 } finally { 118 StrictMode.setThreadPolicy(policy); 119 } 120 return speedTimeMs; 121 } 122 } 123