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