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