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 */ 16package com.android.internal.os; 17 18import android.text.TextUtils; 19import android.system.OsConstants; 20import android.util.Slog; 21 22import libcore.io.Libcore; 23 24import java.io.BufferedReader; 25import java.io.FileReader; 26import java.io.IOException; 27import 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 */ 37public class KernelCpuSpeedReader { 38 private static final String TAG = "KernelCpuSpeedReader"; 39 40 private final String mProcFile; 41 private final long[] mLastSpeedTimes; 42 private final long[] mDeltaSpeedTimes; 43 44 // How long a CPU jiffy is in milliseconds. 45 private final long mJiffyMillis; 46 47 /** 48 * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read. 49 */ 50 public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) { 51 mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", 52 cpuNumber); 53 mLastSpeedTimes = new long[numSpeedSteps]; 54 mDeltaSpeedTimes = new long[numSpeedSteps]; 55 long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK); 56 mJiffyMillis = 1000/jiffyHz; 57 } 58 59 /** 60 * The returned array is modified in subsequent calls to {@link #readDelta}. 61 * @return The time (in milliseconds) spent at different cpu speeds since the last call to 62 * {@link #readDelta}. 63 */ 64 public long[] readDelta() { 65 try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) { 66 TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' '); 67 String line; 68 int speedIndex = 0; 69 while (speedIndex < mLastSpeedTimes.length && (line = reader.readLine()) != null) { 70 splitter.setString(line); 71 Long.parseLong(splitter.next()); 72 73 long time = Long.parseLong(splitter.next()) * mJiffyMillis; 74 if (time < mLastSpeedTimes[speedIndex]) { 75 // The stats reset when the cpu hotplugged. That means that the time 76 // we read is offset from 0, so the time is the delta. 77 mDeltaSpeedTimes[speedIndex] = time; 78 } else { 79 mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex]; 80 } 81 mLastSpeedTimes[speedIndex] = time; 82 speedIndex++; 83 } 84 } catch (IOException e) { 85 Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage()); 86 Arrays.fill(mDeltaSpeedTimes, 0); 87 } 88 return mDeltaSpeedTimes; 89 } 90} 91