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