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