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