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