Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2007 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 static android.os.Process.*;
     20 
     21 import android.os.FileUtils;
     22 import android.os.Process;
     23 import android.os.StrictMode;
     24 import android.os.SystemClock;
     25 import android.util.Slog;
     26 import com.android.internal.util.FastPrintWriter;
     27 
     28 import java.io.File;
     29 import java.io.FileInputStream;
     30 import java.io.PrintWriter;
     31 import java.io.StringWriter;
     32 import java.util.ArrayList;
     33 import java.util.Collections;
     34 import java.util.Comparator;
     35 import java.util.StringTokenizer;
     36 
     37 public class ProcessCpuTracker {
     38     private static final String TAG = "ProcessCpuTracker";
     39     private static final boolean DEBUG = false;
     40     private static final boolean localLOGV = DEBUG || false;
     41 
     42     private static final int[] PROCESS_STATS_FORMAT = new int[] {
     43         PROC_SPACE_TERM,
     44         PROC_SPACE_TERM|PROC_PARENS,
     45         PROC_SPACE_TERM,
     46         PROC_SPACE_TERM,
     47         PROC_SPACE_TERM,
     48         PROC_SPACE_TERM,
     49         PROC_SPACE_TERM,
     50         PROC_SPACE_TERM,
     51         PROC_SPACE_TERM,
     52         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
     53         PROC_SPACE_TERM,
     54         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
     55         PROC_SPACE_TERM,
     56         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
     57         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
     58     };
     59 
     60     static final int PROCESS_STAT_MINOR_FAULTS = 0;
     61     static final int PROCESS_STAT_MAJOR_FAULTS = 1;
     62     static final int PROCESS_STAT_UTIME = 2;
     63     static final int PROCESS_STAT_STIME = 3;
     64 
     65     /** Stores user time and system time in 100ths of a second. */
     66     private final long[] mProcessStatsData = new long[4];
     67     /** Stores user time and system time in 100ths of a second. */
     68     private final long[] mSinglePidStatsData = new long[4];
     69 
     70     private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
     71         PROC_SPACE_TERM,
     72         PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING,    // 2: name
     73         PROC_SPACE_TERM,
     74         PROC_SPACE_TERM,
     75         PROC_SPACE_TERM,
     76         PROC_SPACE_TERM,
     77         PROC_SPACE_TERM,
     78         PROC_SPACE_TERM,
     79         PROC_SPACE_TERM,
     80         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 10: minor faults
     81         PROC_SPACE_TERM,
     82         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 12: major faults
     83         PROC_SPACE_TERM,
     84         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 14: utime
     85         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 15: stime
     86         PROC_SPACE_TERM,
     87         PROC_SPACE_TERM,
     88         PROC_SPACE_TERM,
     89         PROC_SPACE_TERM,
     90         PROC_SPACE_TERM,
     91         PROC_SPACE_TERM,
     92         PROC_SPACE_TERM,
     93         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 23: vsize
     94     };
     95 
     96     static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
     97     static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
     98     static final int PROCESS_FULL_STAT_UTIME = 3;
     99     static final int PROCESS_FULL_STAT_STIME = 4;
    100     static final int PROCESS_FULL_STAT_VSIZE = 5;
    101 
    102     private final String[] mProcessFullStatsStringData = new String[6];
    103     private final long[] mProcessFullStatsData = new long[6];
    104 
    105     private static final int[] SYSTEM_CPU_FORMAT = new int[] {
    106         PROC_SPACE_TERM|PROC_COMBINE,
    107         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 1: user time
    108         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 2: nice time
    109         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 3: sys time
    110         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 4: idle time
    111         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 5: iowait time
    112         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 6: irq time
    113         PROC_SPACE_TERM|PROC_OUT_LONG                   // 7: softirq time
    114     };
    115 
    116     private final long[] mSystemCpuData = new long[7];
    117 
    118     private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
    119         PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 0: 1 min
    120         PROC_SPACE_TERM|PROC_OUT_FLOAT,                 // 1: 5 mins
    121         PROC_SPACE_TERM|PROC_OUT_FLOAT                  // 2: 15 mins
    122     };
    123 
    124     private final float[] mLoadAverageData = new float[3];
    125 
    126     private final boolean mIncludeThreads;
    127 
    128     private float mLoad1 = 0;
    129     private float mLoad5 = 0;
    130     private float mLoad15 = 0;
    131 
    132     private long mCurrentSampleTime;
    133     private long mLastSampleTime;
    134 
    135     private long mCurrentSampleRealTime;
    136     private long mLastSampleRealTime;
    137 
    138     private long mBaseUserTime;
    139     private long mBaseSystemTime;
    140     private long mBaseIoWaitTime;
    141     private long mBaseIrqTime;
    142     private long mBaseSoftIrqTime;
    143     private long mBaseIdleTime;
    144     private int mRelUserTime;
    145     private int mRelSystemTime;
    146     private int mRelIoWaitTime;
    147     private int mRelIrqTime;
    148     private int mRelSoftIrqTime;
    149     private int mRelIdleTime;
    150 
    151     private int[] mCurPids;
    152     private int[] mCurThreadPids;
    153 
    154     private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
    155     private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
    156     private boolean mWorkingProcsSorted;
    157 
    158     private boolean mFirst = true;
    159 
    160     private byte[] mBuffer = new byte[4096];
    161 
    162     /**
    163      * The time in microseconds that the CPU has been running at each speed.
    164      */
    165     private long[] mCpuSpeedTimes;
    166 
    167     /**
    168      * The relative time in microseconds that the CPU has been running at each speed.
    169      */
    170     private long[] mRelCpuSpeedTimes;
    171 
    172     /**
    173      * The different speeds that the CPU can be running at.
    174      */
    175     private long[] mCpuSpeeds;
    176 
    177     public static class Stats {
    178         public final int pid;
    179         public final int uid;
    180         final String statFile;
    181         final String cmdlineFile;
    182         final String threadsDir;
    183         final ArrayList<Stats> threadStats;
    184         final ArrayList<Stats> workingThreads;
    185 
    186         public BatteryStatsImpl.Uid.Proc batteryStats;
    187 
    188         public boolean interesting;
    189 
    190         public String baseName;
    191         public String name;
    192         public int nameWidth;
    193 
    194         // vsize capture when process first detected; can be used to
    195         // filter out kernel processes.
    196         public long vsize;
    197 
    198         public long base_uptime;
    199         public long rel_uptime;
    200 
    201         public long base_utime;
    202         public long base_stime;
    203         public int rel_utime;
    204         public int rel_stime;
    205 
    206         public long base_minfaults;
    207         public long base_majfaults;
    208         public int rel_minfaults;
    209         public int rel_majfaults;
    210 
    211         public boolean active;
    212         public boolean working;
    213         public boolean added;
    214         public boolean removed;
    215 
    216         Stats(int _pid, int parentPid, boolean includeThreads) {
    217             pid = _pid;
    218             if (parentPid < 0) {
    219                 final File procDir = new File("/proc", Integer.toString(pid));
    220                 statFile = new File(procDir, "stat").toString();
    221                 cmdlineFile = new File(procDir, "cmdline").toString();
    222                 threadsDir = (new File(procDir, "task")).toString();
    223                 if (includeThreads) {
    224                     threadStats = new ArrayList<Stats>();
    225                     workingThreads = new ArrayList<Stats>();
    226                 } else {
    227                     threadStats = null;
    228                     workingThreads = null;
    229                 }
    230             } else {
    231                 final File procDir = new File("/proc", Integer.toString(
    232                         parentPid));
    233                 final File taskDir = new File(
    234                         new File(procDir, "task"), Integer.toString(pid));
    235                 statFile = new File(taskDir, "stat").toString();
    236                 cmdlineFile = null;
    237                 threadsDir = null;
    238                 threadStats = null;
    239                 workingThreads = null;
    240             }
    241             uid = FileUtils.getUid(statFile.toString());
    242         }
    243     }
    244 
    245     private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
    246         public final int
    247         compare(Stats sta, Stats stb) {
    248             int ta = sta.rel_utime + sta.rel_stime;
    249             int tb = stb.rel_utime + stb.rel_stime;
    250             if (ta != tb) {
    251                 return ta > tb ? -1 : 1;
    252             }
    253             if (sta.added != stb.added) {
    254                 return sta.added ? -1 : 1;
    255             }
    256             if (sta.removed != stb.removed) {
    257                 return sta.added ? -1 : 1;
    258             }
    259             return 0;
    260         }
    261     };
    262 
    263 
    264     public ProcessCpuTracker(boolean includeThreads) {
    265         mIncludeThreads = includeThreads;
    266     }
    267 
    268     public void onLoadChanged(float load1, float load5, float load15) {
    269     }
    270 
    271     public int onMeasureProcessName(String name) {
    272         return 0;
    273     }
    274 
    275     public void init() {
    276         if (DEBUG) Slog.v(TAG, "Init: " + this);
    277         mFirst = true;
    278         update();
    279     }
    280 
    281     public void update() {
    282         if (DEBUG) Slog.v(TAG, "Update: " + this);
    283         mLastSampleTime = mCurrentSampleTime;
    284         mCurrentSampleTime = SystemClock.uptimeMillis();
    285         mLastSampleRealTime = mCurrentSampleRealTime;
    286         mCurrentSampleRealTime = SystemClock.elapsedRealtime();
    287 
    288         final long[] sysCpu = mSystemCpuData;
    289         if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
    290                 null, sysCpu, null)) {
    291             // Total user time is user + nice time.
    292             final long usertime = sysCpu[0]+sysCpu[1];
    293             // Total system time is simply system time.
    294             final long systemtime = sysCpu[2];
    295             // Total idle time is simply idle time.
    296             final long idletime = sysCpu[3];
    297             // Total irq time is iowait + irq + softirq time.
    298             final long iowaittime = sysCpu[4];
    299             final long irqtime = sysCpu[5];
    300             final long softirqtime = sysCpu[6];
    301 
    302             mRelUserTime = (int)(usertime - mBaseUserTime);
    303             mRelSystemTime = (int)(systemtime - mBaseSystemTime);
    304             mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
    305             mRelIrqTime = (int)(irqtime - mBaseIrqTime);
    306             mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
    307             mRelIdleTime = (int)(idletime - mBaseIdleTime);
    308 
    309             if (DEBUG) {
    310                 Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
    311                       + " S:" + sysCpu[2] + " I:" + sysCpu[3]
    312                       + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
    313                       + " O:" + sysCpu[6]);
    314                 Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
    315                       + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
    316             }
    317 
    318             mBaseUserTime = usertime;
    319             mBaseSystemTime = systemtime;
    320             mBaseIoWaitTime = iowaittime;
    321             mBaseIrqTime = irqtime;
    322             mBaseSoftIrqTime = softirqtime;
    323             mBaseIdleTime = idletime;
    324         }
    325 
    326         mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
    327 
    328         final float[] loadAverages = mLoadAverageData;
    329         if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
    330                 null, null, loadAverages)) {
    331             float load1 = loadAverages[0];
    332             float load5 = loadAverages[1];
    333             float load15 = loadAverages[2];
    334             if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
    335                 mLoad1 = load1;
    336                 mLoad5 = load5;
    337                 mLoad15 = load15;
    338                 onLoadChanged(load1, load5, load15);
    339             }
    340         }
    341 
    342         if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
    343                 + (SystemClock.uptimeMillis()-mCurrentSampleTime));
    344 
    345         mWorkingProcsSorted = false;
    346         mFirst = false;
    347     }
    348 
    349     private int[] collectStats(String statsFile, int parentPid, boolean first,
    350             int[] curPids, ArrayList<Stats> allProcs) {
    351 
    352         int[] pids = Process.getPids(statsFile, curPids);
    353         int NP = (pids == null) ? 0 : pids.length;
    354         int NS = allProcs.size();
    355         int curStatsIndex = 0;
    356         for (int i=0; i<NP; i++) {
    357             int pid = pids[i];
    358             if (pid < 0) {
    359                 NP = pid;
    360                 break;
    361             }
    362             Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
    363 
    364             if (st != null && st.pid == pid) {
    365                 // Update an existing process...
    366                 st.added = false;
    367                 st.working = false;
    368                 curStatsIndex++;
    369                 if (DEBUG) Slog.v(TAG, "Existing "
    370                         + (parentPid < 0 ? "process" : "thread")
    371                         + " pid " + pid + ": " + st);
    372 
    373                 if (st.interesting) {
    374                     final long uptime = SystemClock.uptimeMillis();
    375 
    376                     final long[] procStats = mProcessStatsData;
    377                     if (!Process.readProcFile(st.statFile.toString(),
    378                             PROCESS_STATS_FORMAT, null, procStats, null)) {
    379                         continue;
    380                     }
    381 
    382                     final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
    383                     final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
    384                     final long utime = procStats[PROCESS_STAT_UTIME];
    385                     final long stime = procStats[PROCESS_STAT_STIME];
    386 
    387                     if (utime == st.base_utime && stime == st.base_stime) {
    388                         st.rel_utime = 0;
    389                         st.rel_stime = 0;
    390                         st.rel_minfaults = 0;
    391                         st.rel_majfaults = 0;
    392                         if (st.active) {
    393                             st.active = false;
    394                         }
    395                         continue;
    396                     }
    397 
    398                     if (!st.active) {
    399                         st.active = true;
    400                     }
    401 
    402                     if (parentPid < 0) {
    403                         getName(st, st.cmdlineFile);
    404                         if (st.threadStats != null) {
    405                             mCurThreadPids = collectStats(st.threadsDir, pid, false,
    406                                     mCurThreadPids, st.threadStats);
    407                         }
    408                     }
    409 
    410                     if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
    411                             + " utime=" + utime + "-" + st.base_utime
    412                             + " stime=" + stime + "-" + st.base_stime
    413                             + " minfaults=" + minfaults + "-" + st.base_minfaults
    414                             + " majfaults=" + majfaults + "-" + st.base_majfaults);
    415 
    416                     st.rel_uptime = uptime - st.base_uptime;
    417                     st.base_uptime = uptime;
    418                     st.rel_utime = (int)(utime - st.base_utime);
    419                     st.rel_stime = (int)(stime - st.base_stime);
    420                     st.base_utime = utime;
    421                     st.base_stime = stime;
    422                     st.rel_minfaults = (int)(minfaults - st.base_minfaults);
    423                     st.rel_majfaults = (int)(majfaults - st.base_majfaults);
    424                     st.base_minfaults = minfaults;
    425                     st.base_majfaults = majfaults;
    426                     st.working = true;
    427                 }
    428 
    429                 continue;
    430             }
    431 
    432             if (st == null || st.pid > pid) {
    433                 // We have a new process!
    434                 st = new Stats(pid, parentPid, mIncludeThreads);
    435                 allProcs.add(curStatsIndex, st);
    436                 curStatsIndex++;
    437                 NS++;
    438                 if (DEBUG) Slog.v(TAG, "New "
    439                         + (parentPid < 0 ? "process" : "thread")
    440                         + " pid " + pid + ": " + st);
    441 
    442                 final String[] procStatsString = mProcessFullStatsStringData;
    443                 final long[] procStats = mProcessFullStatsData;
    444                 st.base_uptime = SystemClock.uptimeMillis();
    445                 if (Process.readProcFile(st.statFile.toString(),
    446                         PROCESS_FULL_STATS_FORMAT, procStatsString,
    447                         procStats, null)) {
    448                     // This is a possible way to filter out processes that
    449                     // are actually kernel threads...  do we want to?  Some
    450                     // of them do use CPU, but there can be a *lot* that are
    451                     // not doing anything.
    452                     st.vsize = procStats[PROCESS_FULL_STAT_VSIZE];
    453                     if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
    454                         st.interesting = true;
    455                         st.baseName = procStatsString[0];
    456                         st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
    457                         st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
    458                         st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
    459                         st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
    460                     } else {
    461                         Slog.i(TAG, "Skipping kernel process pid " + pid
    462                                 + " name " + procStatsString[0]);
    463                         st.baseName = procStatsString[0];
    464                     }
    465                 } else {
    466                     Slog.w(TAG, "Skipping unknown process pid " + pid);
    467                     st.baseName = "<unknown>";
    468                     st.base_utime = st.base_stime = 0;
    469                     st.base_minfaults = st.base_majfaults = 0;
    470                 }
    471 
    472                 if (parentPid < 0) {
    473                     getName(st, st.cmdlineFile);
    474                     if (st.threadStats != null) {
    475                         mCurThreadPids = collectStats(st.threadsDir, pid, true,
    476                                 mCurThreadPids, st.threadStats);
    477                     }
    478                 } else if (st.interesting) {
    479                     st.name = st.baseName;
    480                     st.nameWidth = onMeasureProcessName(st.name);
    481                 }
    482 
    483                 if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
    484                         + " utime=" + st.base_utime + " stime=" + st.base_stime
    485                         + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
    486 
    487                 st.rel_utime = 0;
    488                 st.rel_stime = 0;
    489                 st.rel_minfaults = 0;
    490                 st.rel_majfaults = 0;
    491                 st.added = true;
    492                 if (!first && st.interesting) {
    493                     st.working = true;
    494                 }
    495                 continue;
    496             }
    497 
    498             // This process has gone away!
    499             st.rel_utime = 0;
    500             st.rel_stime = 0;
    501             st.rel_minfaults = 0;
    502             st.rel_majfaults = 0;
    503             st.removed = true;
    504             st.working = true;
    505             allProcs.remove(curStatsIndex);
    506             NS--;
    507             if (DEBUG) Slog.v(TAG, "Removed "
    508                     + (parentPid < 0 ? "process" : "thread")
    509                     + " pid " + pid + ": " + st);
    510             // Decrement the loop counter so that we process the current pid
    511             // again the next time through the loop.
    512             i--;
    513             continue;
    514         }
    515 
    516         while (curStatsIndex < NS) {
    517             // This process has gone away!
    518             final Stats st = allProcs.get(curStatsIndex);
    519             st.rel_utime = 0;
    520             st.rel_stime = 0;
    521             st.rel_minfaults = 0;
    522             st.rel_majfaults = 0;
    523             st.removed = true;
    524             st.working = true;
    525             allProcs.remove(curStatsIndex);
    526             NS--;
    527             if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
    528         }
    529 
    530         return pids;
    531     }
    532 
    533     /**
    534      * Returns the total time (in clock ticks, or 1/100 sec) spent executing in
    535      * both user and system code.
    536      */
    537     public long getCpuTimeForPid(int pid) {
    538         final String statFile = "/proc/" + pid + "/stat";
    539         final long[] statsData = mSinglePidStatsData;
    540         if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
    541                 null, statsData, null)) {
    542             long time = statsData[PROCESS_STAT_UTIME]
    543                     + statsData[PROCESS_STAT_STIME];
    544             return time;
    545         }
    546         return 0;
    547     }
    548 
    549     /**
    550      * Returns the delta time (in clock ticks, or 1/100 sec) spent at each CPU
    551      * speed, since the last call to this method. If this is the first call, it
    552      * will return 1 for each value.
    553      */
    554     public long[] getLastCpuSpeedTimes() {
    555         if (mCpuSpeedTimes == null) {
    556             mCpuSpeedTimes = getCpuSpeedTimes(null);
    557             mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
    558             for (int i = 0; i < mCpuSpeedTimes.length; i++) {
    559                 mRelCpuSpeedTimes[i] = 1; // Initialize
    560             }
    561         } else {
    562             getCpuSpeedTimes(mRelCpuSpeedTimes);
    563             for (int i = 0; i < mCpuSpeedTimes.length; i++) {
    564                 long temp = mRelCpuSpeedTimes[i];
    565                 mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
    566                 mCpuSpeedTimes[i] = temp;
    567             }
    568         }
    569         return mRelCpuSpeedTimes;
    570     }
    571 
    572     private long[] getCpuSpeedTimes(long[] out) {
    573         long[] tempTimes = out;
    574         long[] tempSpeeds = mCpuSpeeds;
    575         final int MAX_SPEEDS = 60;
    576         if (out == null) {
    577             tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
    578             tempSpeeds = new long[MAX_SPEEDS];
    579         }
    580         int speed = 0;
    581         String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
    582         // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
    583         if (file != null) {
    584             StringTokenizer st = new StringTokenizer(file, "\n ");
    585             while (st.hasMoreElements()) {
    586                 String token = st.nextToken();
    587                 try {
    588                     long val = Long.parseLong(token);
    589                     tempSpeeds[speed] = val;
    590                     token = st.nextToken();
    591                     val = Long.parseLong(token);
    592                     tempTimes[speed] = val;
    593                     speed++;
    594                     if (speed == MAX_SPEEDS) break; // No more
    595                     if (localLOGV && out == null) {
    596                         Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
    597                               + "\t" + tempTimes[speed - 1]);
    598                     }
    599                 } catch (NumberFormatException nfe) {
    600                     Slog.i(TAG, "Unable to parse time_in_state");
    601                 }
    602             }
    603         }
    604         if (out == null) {
    605             out = new long[speed];
    606             mCpuSpeeds = new long[speed];
    607             System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
    608             System.arraycopy(tempTimes, 0, out, 0, speed);
    609         }
    610         return out;
    611     }
    612 
    613     final public int getLastUserTime() {
    614         return mRelUserTime;
    615     }
    616 
    617     final public int getLastSystemTime() {
    618         return mRelSystemTime;
    619     }
    620 
    621     final public int getLastIoWaitTime() {
    622         return mRelIoWaitTime;
    623     }
    624 
    625     final public int getLastIrqTime() {
    626         return mRelIrqTime;
    627     }
    628 
    629     final public int getLastSoftIrqTime() {
    630         return mRelSoftIrqTime;
    631     }
    632 
    633     final public int getLastIdleTime() {
    634         return mRelIdleTime;
    635     }
    636 
    637     final public float getTotalCpuPercent() {
    638         int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
    639         if (denom <= 0) {
    640             return 0;
    641         }
    642         return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
    643     }
    644 
    645     final void buildWorkingProcs() {
    646         if (!mWorkingProcsSorted) {
    647             mWorkingProcs.clear();
    648             final int N = mProcStats.size();
    649             for (int i=0; i<N; i++) {
    650                 Stats stats = mProcStats.get(i);
    651                 if (stats.working) {
    652                     mWorkingProcs.add(stats);
    653                     if (stats.threadStats != null && stats.threadStats.size() > 1) {
    654                         stats.workingThreads.clear();
    655                         final int M = stats.threadStats.size();
    656                         for (int j=0; j<M; j++) {
    657                             Stats tstats = stats.threadStats.get(j);
    658                             if (tstats.working) {
    659                                 stats.workingThreads.add(tstats);
    660                             }
    661                         }
    662                         Collections.sort(stats.workingThreads, sLoadComparator);
    663                     }
    664                 }
    665             }
    666             Collections.sort(mWorkingProcs, sLoadComparator);
    667             mWorkingProcsSorted = true;
    668         }
    669     }
    670 
    671     final public int countStats() {
    672         return mProcStats.size();
    673     }
    674 
    675     final public Stats getStats(int index) {
    676         return mProcStats.get(index);
    677     }
    678 
    679     final public int countWorkingStats() {
    680         buildWorkingProcs();
    681         return mWorkingProcs.size();
    682     }
    683 
    684     final public Stats getWorkingStats(int index) {
    685         return mWorkingProcs.get(index);
    686     }
    687 
    688     final public String printCurrentLoad() {
    689         StringWriter sw = new StringWriter();
    690         PrintWriter pw = new FastPrintWriter(sw, false, 128);
    691         pw.print("Load: ");
    692         pw.print(mLoad1);
    693         pw.print(" / ");
    694         pw.print(mLoad5);
    695         pw.print(" / ");
    696         pw.println(mLoad15);
    697         pw.flush();
    698         return sw.toString();
    699     }
    700 
    701     final public String printCurrentState(long now) {
    702         buildWorkingProcs();
    703 
    704         StringWriter sw = new StringWriter();
    705         PrintWriter pw = new FastPrintWriter(sw, false, 1024);
    706 
    707         pw.print("CPU usage from ");
    708         if (now > mLastSampleTime) {
    709             pw.print(now-mLastSampleTime);
    710             pw.print("ms to ");
    711             pw.print(now-mCurrentSampleTime);
    712             pw.print("ms ago");
    713         } else {
    714             pw.print(mLastSampleTime-now);
    715             pw.print("ms to ");
    716             pw.print(mCurrentSampleTime-now);
    717             pw.print("ms later");
    718         }
    719 
    720         long sampleTime = mCurrentSampleTime - mLastSampleTime;
    721         long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
    722         long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0;
    723         if (percAwake != 100) {
    724             pw.print(" with ");
    725             pw.print(percAwake);
    726             pw.print("% awake");
    727         }
    728         pw.println(":");
    729 
    730         final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
    731                 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
    732 
    733         if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
    734                 + (mCurrentSampleTime-mLastSampleTime));
    735 
    736         int N = mWorkingProcs.size();
    737         for (int i=0; i<N; i++) {
    738             Stats st = mWorkingProcs.get(i);
    739             printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
    740                     st.pid, st.name, (int)(st.rel_uptime+5)/10,
    741                     st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
    742             if (!st.removed && st.workingThreads != null) {
    743                 int M = st.workingThreads.size();
    744                 for (int j=0; j<M; j++) {
    745                     Stats tst = st.workingThreads.get(j);
    746                     printProcessCPU(pw,
    747                             tst.added ? "   +" : (tst.removed ? "   -": "    "),
    748                             tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
    749                             tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
    750                 }
    751             }
    752         }
    753 
    754         printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
    755                 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
    756 
    757         pw.flush();
    758         return sw.toString();
    759     }
    760 
    761     private void printRatio(PrintWriter pw, long numerator, long denominator) {
    762         long thousands = (numerator*1000)/denominator;
    763         long hundreds = thousands/10;
    764         pw.print(hundreds);
    765         if (hundreds < 10) {
    766             long remainder = thousands - (hundreds*10);
    767             if (remainder != 0) {
    768                 pw.print('.');
    769                 pw.print(remainder);
    770             }
    771         }
    772     }
    773 
    774     private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
    775             int totalTime, int user, int system, int iowait, int irq, int softIrq,
    776             int minFaults, int majFaults) {
    777         pw.print(prefix);
    778         if (totalTime == 0) totalTime = 1;
    779         printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
    780         pw.print("% ");
    781         if (pid >= 0) {
    782             pw.print(pid);
    783             pw.print("/");
    784         }
    785         pw.print(label);
    786         pw.print(": ");
    787         printRatio(pw, user, totalTime);
    788         pw.print("% user + ");
    789         printRatio(pw, system, totalTime);
    790         pw.print("% kernel");
    791         if (iowait > 0) {
    792             pw.print(" + ");
    793             printRatio(pw, iowait, totalTime);
    794             pw.print("% iowait");
    795         }
    796         if (irq > 0) {
    797             pw.print(" + ");
    798             printRatio(pw, irq, totalTime);
    799             pw.print("% irq");
    800         }
    801         if (softIrq > 0) {
    802             pw.print(" + ");
    803             printRatio(pw, softIrq, totalTime);
    804             pw.print("% softirq");
    805         }
    806         if (minFaults > 0 || majFaults > 0) {
    807             pw.print(" / faults:");
    808             if (minFaults > 0) {
    809                 pw.print(" ");
    810                 pw.print(minFaults);
    811                 pw.print(" minor");
    812             }
    813             if (majFaults > 0) {
    814                 pw.print(" ");
    815                 pw.print(majFaults);
    816                 pw.print(" major");
    817             }
    818         }
    819         pw.println();
    820     }
    821 
    822     private String readFile(String file, char endChar) {
    823         // Permit disk reads here, as /proc/meminfo isn't really "on
    824         // disk" and should be fast.  TODO: make BlockGuard ignore
    825         // /proc/ and /sys/ files perhaps?
    826         StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
    827         FileInputStream is = null;
    828         try {
    829             is = new FileInputStream(file);
    830             int len = is.read(mBuffer);
    831             is.close();
    832 
    833             if (len > 0) {
    834                 int i;
    835                 for (i=0; i<len; i++) {
    836                     if (mBuffer[i] == endChar) {
    837                         break;
    838                     }
    839                 }
    840                 return new String(mBuffer, 0, i);
    841             }
    842         } catch (java.io.FileNotFoundException e) {
    843         } catch (java.io.IOException e) {
    844         } finally {
    845             if (is != null) {
    846                 try {
    847                     is.close();
    848                 } catch (java.io.IOException e) {
    849                 }
    850             }
    851             StrictMode.setThreadPolicy(savedPolicy);
    852         }
    853         return null;
    854     }
    855 
    856     private void getName(Stats st, String cmdlineFile) {
    857         String newName = st.name;
    858         if (st.name == null || st.name.equals("app_process")
    859                 || st.name.equals("<pre-initialized>")) {
    860             String cmdName = readFile(cmdlineFile, '\0');
    861             if (cmdName != null && cmdName.length() > 1) {
    862                 newName = cmdName;
    863                 int i = newName.lastIndexOf("/");
    864                 if (i > 0 && i < newName.length()-1) {
    865                     newName = newName.substring(i+1);
    866                 }
    867             }
    868             if (newName == null) {
    869                 newName = st.baseName;
    870             }
    871         }
    872         if (st.name == null || !newName.equals(st.name)) {
    873             st.name = newName;
    874             st.nameWidth = onMeasureProcessName(st.name);
    875         }
    876     }
    877 }
    878