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