blob: 874bc0eb4dcb31c541857bd9ca03cc2f60e41e65 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Dianne Hackborn45ce8642011-07-14 16:10:16 -070017package com.android.internal.os;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
19import static android.os.Process.*;
20
Dianne Hackborn053f61d2013-06-26 18:07:43 -070021import android.os.FileUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.os.Process;
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -070023import android.os.StrictMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.os.SystemClock;
Joe Onorato8a9b2202010-02-26 18:56:32 -080025import android.util.Slog;
Dianne Hackborn8c841092013-06-24 13:46:13 -070026import com.android.internal.util.FastPrintWriter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
28import java.io.File;
29import java.io.FileInputStream;
30import java.io.PrintWriter;
31import java.io.StringWriter;
32import java.util.ArrayList;
33import java.util.Collections;
34import java.util.Comparator;
Amith Yamasanie43530a2009-08-21 13:11:37 -070035import java.util.StringTokenizer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
37public class ProcessStats {
38 private static final String TAG = "ProcessStats";
39 private static final boolean DEBUG = false;
Joe Onorato43a17652011-04-06 19:22:23 -070040 private static final boolean localLOGV = DEBUG || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42 private static final int[] PROCESS_STATS_FORMAT = new int[] {
43 PROC_SPACE_TERM,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070044 PROC_SPACE_TERM|PROC_PARENS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045 PROC_SPACE_TERM,
46 PROC_SPACE_TERM,
47 PROC_SPACE_TERM,
48 PROC_SPACE_TERM,
49 PROC_SPACE_TERM,
50 PROC_SPACE_TERM,
51 PROC_SPACE_TERM,
Dianne Hackborn151ceb92009-08-06 12:40:56 -070052 PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 PROC_SPACE_TERM,
Dianne Hackborn151ceb92009-08-06 12:40:56 -070054 PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 PROC_SPACE_TERM,
56 PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
57 PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
58 };
59
Dianne Hackborn151ceb92009-08-06 12:40:56 -070060 static final int PROCESS_STAT_MINOR_FAULTS = 0;
61 static final int PROCESS_STAT_MAJOR_FAULTS = 1;
62 static final int PROCESS_STAT_UTIME = 2;
63 static final int PROCESS_STAT_STIME = 3;
64
Amith Yamasanieaeb6632009-06-03 15:16:10 -070065 /** Stores user time and system time in 100ths of a second. */
Dianne Hackborn151ceb92009-08-06 12:40:56 -070066 private final long[] mProcessStatsData = new long[4];
Amith Yamasanieaeb6632009-06-03 15:16:10 -070067 /** Stores user time and system time in 100ths of a second. */
Dianne Hackborn151ceb92009-08-06 12:40:56 -070068 private final long[] mSinglePidStatsData = new long[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70 private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
71 PROC_SPACE_TERM,
72 PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 1: name
73 PROC_SPACE_TERM,
74 PROC_SPACE_TERM,
75 PROC_SPACE_TERM,
76 PROC_SPACE_TERM,
77 PROC_SPACE_TERM,
78 PROC_SPACE_TERM,
79 PROC_SPACE_TERM,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070080 PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 PROC_SPACE_TERM,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070082 PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 PROC_SPACE_TERM,
84 PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
Dianne Hackborn287952c2010-09-22 22:34:31 -070085 PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime
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, // 21: vsize
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 };
94
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070095 static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
96 static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
97 static final int PROCESS_FULL_STAT_UTIME = 3;
98 static final int PROCESS_FULL_STAT_STIME = 4;
Dianne Hackborn287952c2010-09-22 22:34:31 -070099 static final int PROCESS_FULL_STAT_VSIZE = 5;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700100
Dianne Hackborn287952c2010-09-22 22:34:31 -0700101 private final String[] mProcessFullStatsStringData = new String[6];
102 private final long[] mProcessFullStatsData = new long[6];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
104 private static final int[] SYSTEM_CPU_FORMAT = new int[] {
105 PROC_SPACE_TERM|PROC_COMBINE,
106 PROC_SPACE_TERM|PROC_OUT_LONG, // 1: user time
107 PROC_SPACE_TERM|PROC_OUT_LONG, // 2: nice time
108 PROC_SPACE_TERM|PROC_OUT_LONG, // 3: sys time
109 PROC_SPACE_TERM|PROC_OUT_LONG, // 4: idle time
110 PROC_SPACE_TERM|PROC_OUT_LONG, // 5: iowait time
111 PROC_SPACE_TERM|PROC_OUT_LONG, // 6: irq time
112 PROC_SPACE_TERM|PROC_OUT_LONG // 7: softirq time
113 };
114
115 private final long[] mSystemCpuData = new long[7];
116
117 private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
118 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 0: 1 min
119 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 1: 5 mins
120 PROC_SPACE_TERM|PROC_OUT_FLOAT // 2: 15 mins
121 };
122
123 private final float[] mLoadAverageData = new float[3];
124
125 private final boolean mIncludeThreads;
126
127 private float mLoad1 = 0;
128 private float mLoad5 = 0;
129 private float mLoad15 = 0;
130
131 private long mCurrentSampleTime;
132 private long mLastSampleTime;
133
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700134 private long mCurrentSampleRealTime;
135 private long mLastSampleRealTime;
136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private long mBaseUserTime;
138 private long mBaseSystemTime;
139 private long mBaseIoWaitTime;
140 private long mBaseIrqTime;
141 private long mBaseSoftIrqTime;
142 private long mBaseIdleTime;
143 private int mRelUserTime;
144 private int mRelSystemTime;
145 private int mRelIoWaitTime;
146 private int mRelIrqTime;
147 private int mRelSoftIrqTime;
148 private int mRelIdleTime;
149
150 private int[] mCurPids;
151 private int[] mCurThreadPids;
152
153 private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
154 private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
155 private boolean mWorkingProcsSorted;
156
157 private boolean mFirst = true;
158
Martin Wallgrenca894b32011-09-20 13:45:48 +0200159 private byte[] mBuffer = new byte[4096];
Amith Yamasanie43530a2009-08-21 13:11:37 -0700160
161 /**
162 * The time in microseconds that the CPU has been running at each speed.
163 */
164 private long[] mCpuSpeedTimes;
165
166 /**
167 * The relative time in microseconds that the CPU has been running at each speed.
168 */
169 private long[] mRelCpuSpeedTimes;
170
171 /**
172 * The different speeds that the CPU can be running at.
173 */
174 private long[] mCpuSpeeds;
175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 public static class Stats {
177 public final int pid;
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700178 public final int uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 final String statFile;
180 final String cmdlineFile;
181 final String threadsDir;
182 final ArrayList<Stats> threadStats;
183 final ArrayList<Stats> workingThreads;
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700184
185 public BatteryStatsImpl.Uid.Proc batteryStats;
186
Dianne Hackborn287952c2010-09-22 22:34:31 -0700187 public boolean interesting;
188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 public String baseName;
190 public String name;
Dianne Hackborn45ce8642011-07-14 16:10:16 -0700191 public int nameWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700193 public long base_uptime;
194 public long rel_uptime;
195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 public long base_utime;
197 public long base_stime;
198 public int rel_utime;
199 public int rel_stime;
200
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700201 public long base_minfaults;
202 public long base_majfaults;
203 public int rel_minfaults;
204 public int rel_majfaults;
205
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 public boolean active;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700207 public boolean working;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 public boolean added;
209 public boolean removed;
210
211 Stats(int _pid, int parentPid, boolean includeThreads) {
212 pid = _pid;
213 if (parentPid < 0) {
214 final File procDir = new File("/proc", Integer.toString(pid));
215 statFile = new File(procDir, "stat").toString();
216 cmdlineFile = new File(procDir, "cmdline").toString();
217 threadsDir = (new File(procDir, "task")).toString();
218 if (includeThreads) {
219 threadStats = new ArrayList<Stats>();
220 workingThreads = new ArrayList<Stats>();
221 } else {
222 threadStats = null;
223 workingThreads = null;
224 }
225 } else {
226 final File procDir = new File("/proc", Integer.toString(
227 parentPid));
228 final File taskDir = new File(
229 new File(procDir, "task"), Integer.toString(pid));
230 statFile = new File(taskDir, "stat").toString();
231 cmdlineFile = null;
232 threadsDir = null;
233 threadStats = null;
234 workingThreads = null;
235 }
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700236 uid = FileUtils.getUid(statFile.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 }
238 }
239
240 private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
241 public final int
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700242 compare(Stats sta, Stats stb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 int ta = sta.rel_utime + sta.rel_stime;
244 int tb = stb.rel_utime + stb.rel_stime;
245 if (ta != tb) {
246 return ta > tb ? -1 : 1;
247 }
248 if (sta.added != stb.added) {
249 return sta.added ? -1 : 1;
250 }
251 if (sta.removed != stb.removed) {
252 return sta.added ? -1 : 1;
253 }
254 return 0;
255 }
256 };
257
258
259 public ProcessStats(boolean includeThreads) {
260 mIncludeThreads = includeThreads;
261 }
262
263 public void onLoadChanged(float load1, float load5, float load15) {
264 }
265
266 public int onMeasureProcessName(String name) {
267 return 0;
268 }
269
270 public void init() {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700271 if (DEBUG) Slog.v(TAG, "Init: " + this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 mFirst = true;
273 update();
274 }
275
276 public void update() {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700277 if (DEBUG) Slog.v(TAG, "Update: " + this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 mLastSampleTime = mCurrentSampleTime;
279 mCurrentSampleTime = SystemClock.uptimeMillis();
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700280 mLastSampleRealTime = mCurrentSampleRealTime;
281 mCurrentSampleRealTime = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282
283 final long[] sysCpu = mSystemCpuData;
284 if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
285 null, sysCpu, null)) {
286 // Total user time is user + nice time.
287 final long usertime = sysCpu[0]+sysCpu[1];
288 // Total system time is simply system time.
289 final long systemtime = sysCpu[2];
290 // Total idle time is simply idle time.
291 final long idletime = sysCpu[3];
292 // Total irq time is iowait + irq + softirq time.
293 final long iowaittime = sysCpu[4];
294 final long irqtime = sysCpu[5];
295 final long softirqtime = sysCpu[6];
296
297 mRelUserTime = (int)(usertime - mBaseUserTime);
298 mRelSystemTime = (int)(systemtime - mBaseSystemTime);
299 mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
300 mRelIrqTime = (int)(irqtime - mBaseIrqTime);
301 mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
302 mRelIdleTime = (int)(idletime - mBaseIdleTime);
303
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700304 if (DEBUG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800305 Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 + " S:" + sysCpu[2] + " I:" + sysCpu[3]
307 + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
308 + " O:" + sysCpu[6]);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800309 Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
311 }
312
313 mBaseUserTime = usertime;
314 mBaseSystemTime = systemtime;
315 mBaseIoWaitTime = iowaittime;
316 mBaseIrqTime = irqtime;
317 mBaseSoftIrqTime = softirqtime;
318 mBaseIdleTime = idletime;
319 }
320
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700321 mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
322
323 final float[] loadAverages = mLoadAverageData;
324 if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
325 null, null, loadAverages)) {
326 float load1 = loadAverages[0];
327 float load5 = loadAverages[1];
328 float load15 = loadAverages[2];
329 if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
330 mLoad1 = load1;
331 mLoad5 = load5;
332 mLoad15 = load15;
333 onLoadChanged(load1, load5, load15);
334 }
335 }
336
337 if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
338 + (SystemClock.uptimeMillis()-mCurrentSampleTime));
339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 mWorkingProcsSorted = false;
341 mFirst = false;
342 }
343
344 private int[] collectStats(String statsFile, int parentPid, boolean first,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700345 int[] curPids, ArrayList<Stats> allProcs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 int[] pids = Process.getPids(statsFile, curPids);
348 int NP = (pids == null) ? 0 : pids.length;
349 int NS = allProcs.size();
350 int curStatsIndex = 0;
351 for (int i=0; i<NP; i++) {
352 int pid = pids[i];
353 if (pid < 0) {
354 NP = pid;
355 break;
356 }
357 Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
358
359 if (st != null && st.pid == pid) {
360 // Update an existing process...
361 st.added = false;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700362 st.working = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 curStatsIndex++;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700364 if (DEBUG) Slog.v(TAG, "Existing "
365 + (parentPid < 0 ? "process" : "thread")
366 + " pid " + pid + ": " + st);
367
Dianne Hackborn287952c2010-09-22 22:34:31 -0700368 if (st.interesting) {
369 final long uptime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370
Dianne Hackborn287952c2010-09-22 22:34:31 -0700371 final long[] procStats = mProcessStatsData;
372 if (!Process.readProcFile(st.statFile.toString(),
373 PROCESS_STATS_FORMAT, null, procStats, null)) {
374 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376
Dianne Hackborn287952c2010-09-22 22:34:31 -0700377 final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
378 final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
379 final long utime = procStats[PROCESS_STAT_UTIME];
380 final long stime = procStats[PROCESS_STAT_STIME];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381
Dianne Hackborn287952c2010-09-22 22:34:31 -0700382 if (utime == st.base_utime && stime == st.base_stime) {
383 st.rel_utime = 0;
384 st.rel_stime = 0;
385 st.rel_minfaults = 0;
386 st.rel_majfaults = 0;
387 if (st.active) {
388 st.active = false;
389 }
390 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
Dianne Hackborn287952c2010-09-22 22:34:31 -0700392
393 if (!st.active) {
394 st.active = true;
395 }
396
397 if (parentPid < 0) {
398 getName(st, st.cmdlineFile);
399 if (st.threadStats != null) {
400 mCurThreadPids = collectStats(st.threadsDir, pid, false,
401 mCurThreadPids, st.threadStats);
402 }
403 }
404
405 if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
406 + " utime=" + utime + "-" + st.base_utime
407 + " stime=" + stime + "-" + st.base_stime
408 + " minfaults=" + minfaults + "-" + st.base_minfaults
409 + " majfaults=" + majfaults + "-" + st.base_majfaults);
410
411 st.rel_uptime = uptime - st.base_uptime;
412 st.base_uptime = uptime;
413 st.rel_utime = (int)(utime - st.base_utime);
414 st.rel_stime = (int)(stime - st.base_stime);
415 st.base_utime = utime;
416 st.base_stime = stime;
417 st.rel_minfaults = (int)(minfaults - st.base_minfaults);
418 st.rel_majfaults = (int)(majfaults - st.base_majfaults);
419 st.base_minfaults = minfaults;
420 st.base_majfaults = majfaults;
421 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 }
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 continue;
425 }
426
427 if (st == null || st.pid > pid) {
428 // We have a new process!
429 st = new Stats(pid, parentPid, mIncludeThreads);
430 allProcs.add(curStatsIndex, st);
431 curStatsIndex++;
432 NS++;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700433 if (DEBUG) Slog.v(TAG, "New "
434 + (parentPid < 0 ? "process" : "thread")
435 + " pid " + pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436
437 final String[] procStatsString = mProcessFullStatsStringData;
438 final long[] procStats = mProcessFullStatsData;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700439 st.base_uptime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 if (Process.readProcFile(st.statFile.toString(),
441 PROCESS_FULL_STATS_FORMAT, procStatsString,
442 procStats, null)) {
Dianne Hackborn287952c2010-09-22 22:34:31 -0700443 // This is a possible way to filter out processes that
444 // are actually kernel threads... do we want to? Some
445 // of them do use CPU, but there can be a *lot* that are
446 // not doing anything.
447 if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
448 st.interesting = true;
449 st.baseName = procStatsString[0];
450 st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
451 st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
452 st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
453 st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
454 } else {
455 Slog.i(TAG, "Skipping kernel process pid " + pid
456 + " name " + procStatsString[0]);
457 st.baseName = procStatsString[0];
458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 } else {
Dianne Hackborn287952c2010-09-22 22:34:31 -0700460 Slog.w(TAG, "Skipping unknown process pid " + pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 st.baseName = "<unknown>";
462 st.base_utime = st.base_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700463 st.base_minfaults = st.base_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 }
465
466 if (parentPid < 0) {
467 getName(st, st.cmdlineFile);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700468 if (st.threadStats != null) {
469 mCurThreadPids = collectStats(st.threadsDir, pid, true,
470 mCurThreadPids, st.threadStats);
471 }
Dianne Hackborn287952c2010-09-22 22:34:31 -0700472 } else if (st.interesting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 st.name = st.baseName;
474 st.nameWidth = onMeasureProcessName(st.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700476
477 if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
478 + " utime=" + st.base_utime + " stime=" + st.base_stime
479 + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 st.rel_utime = 0;
482 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700483 st.rel_minfaults = 0;
484 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 st.added = true;
Dianne Hackborn287952c2010-09-22 22:34:31 -0700486 if (!first && st.interesting) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700487 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 }
489 continue;
490 }
491
492 // This process has gone away!
493 st.rel_utime = 0;
494 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700495 st.rel_minfaults = 0;
496 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 st.removed = true;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700498 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 allProcs.remove(curStatsIndex);
500 NS--;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700501 if (DEBUG) Slog.v(TAG, "Removed "
502 + (parentPid < 0 ? "process" : "thread")
503 + " pid " + pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 // Decrement the loop counter so that we process the current pid
505 // again the next time through the loop.
506 i--;
507 continue;
508 }
509
510 while (curStatsIndex < NS) {
511 // This process has gone away!
512 final Stats st = allProcs.get(curStatsIndex);
513 st.rel_utime = 0;
514 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700515 st.rel_minfaults = 0;
516 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 st.removed = true;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700518 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 allProcs.remove(curStatsIndex);
520 NS--;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800521 if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
523
524 return pids;
525 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700526
Jeff Sharkey3e013e82013-04-25 14:48:19 -0700527 /**
528 * Returns the total time (in clock ticks, or 1/100 sec) spent executing in
529 * both user and system code.
530 */
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700531 public long getCpuTimeForPid(int pid) {
532 final String statFile = "/proc/" + pid + "/stat";
533 final long[] statsData = mSinglePidStatsData;
534 if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
535 null, statsData, null)) {
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700536 long time = statsData[PROCESS_STAT_UTIME]
537 + statsData[PROCESS_STAT_STIME];
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700538 return time;
539 }
540 return 0;
541 }
542
Amith Yamasanie43530a2009-08-21 13:11:37 -0700543 /**
Jeff Sharkey3e013e82013-04-25 14:48:19 -0700544 * Returns the delta time (in clock ticks, or 1/100 sec) spent at each CPU
545 * speed, since the last call to this method. If this is the first call, it
546 * will return 1 for each value.
Amith Yamasanie43530a2009-08-21 13:11:37 -0700547 */
548 public long[] getLastCpuSpeedTimes() {
549 if (mCpuSpeedTimes == null) {
550 mCpuSpeedTimes = getCpuSpeedTimes(null);
551 mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
552 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
553 mRelCpuSpeedTimes[i] = 1; // Initialize
554 }
555 } else {
556 getCpuSpeedTimes(mRelCpuSpeedTimes);
557 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
558 long temp = mRelCpuSpeedTimes[i];
559 mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
560 mCpuSpeedTimes[i] = temp;
561 }
562 }
563 return mRelCpuSpeedTimes;
564 }
565
566 private long[] getCpuSpeedTimes(long[] out) {
567 long[] tempTimes = out;
568 long[] tempSpeeds = mCpuSpeeds;
Martin Wallgrenca894b32011-09-20 13:45:48 +0200569 final int MAX_SPEEDS = 60;
Amith Yamasanie43530a2009-08-21 13:11:37 -0700570 if (out == null) {
571 tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
572 tempSpeeds = new long[MAX_SPEEDS];
573 }
574 int speed = 0;
575 String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400576 // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
577 if (file != null) {
578 StringTokenizer st = new StringTokenizer(file, "\n ");
579 while (st.hasMoreElements()) {
580 String token = st.nextToken();
581 try {
582 long val = Long.parseLong(token);
583 tempSpeeds[speed] = val;
584 token = st.nextToken();
585 val = Long.parseLong(token);
586 tempTimes[speed] = val;
587 speed++;
588 if (speed == MAX_SPEEDS) break; // No more
589 if (localLOGV && out == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800590 Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400591 + "\t" + tempTimes[speed - 1]);
592 }
593 } catch (NumberFormatException nfe) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800594 Slog.i(TAG, "Unable to parse time_in_state");
Amith Yamasanie43530a2009-08-21 13:11:37 -0700595 }
Amith Yamasanie43530a2009-08-21 13:11:37 -0700596 }
597 }
598 if (out == null) {
599 out = new long[speed];
600 mCpuSpeeds = new long[speed];
601 System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
602 System.arraycopy(tempTimes, 0, out, 0, speed);
603 }
604 return out;
605 }
606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 final public int getLastUserTime() {
608 return mRelUserTime;
609 }
610
611 final public int getLastSystemTime() {
612 return mRelSystemTime;
613 }
614
615 final public int getLastIoWaitTime() {
616 return mRelIoWaitTime;
617 }
618
619 final public int getLastIrqTime() {
620 return mRelIrqTime;
621 }
622
623 final public int getLastSoftIrqTime() {
624 return mRelSoftIrqTime;
625 }
626
627 final public int getLastIdleTime() {
628 return mRelIdleTime;
629 }
630
631 final public float getTotalCpuPercent() {
Dianne Hackborncdadee62012-06-06 11:48:46 -0700632 int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
633 if (denom <= 0) {
634 return 0;
635 }
636 return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 }
638
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700639 final void buildWorkingProcs() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640 if (!mWorkingProcsSorted) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700641 mWorkingProcs.clear();
642 final int N = mProcStats.size();
643 for (int i=0; i<N; i++) {
644 Stats stats = mProcStats.get(i);
645 if (stats.working) {
646 mWorkingProcs.add(stats);
647 if (stats.threadStats != null && stats.threadStats.size() > 1) {
648 stats.workingThreads.clear();
649 final int M = stats.threadStats.size();
650 for (int j=0; j<M; j++) {
651 Stats tstats = stats.threadStats.get(j);
652 if (tstats.working) {
653 stats.workingThreads.add(tstats);
654 }
655 }
656 Collections.sort(stats.workingThreads, sLoadComparator);
657 }
658 }
659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 Collections.sort(mWorkingProcs, sLoadComparator);
661 mWorkingProcsSorted = true;
662 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700663 }
664
Dianne Hackborn287952c2010-09-22 22:34:31 -0700665 final public int countStats() {
666 return mProcStats.size();
667 }
668
669 final public Stats getStats(int index) {
670 return mProcStats.get(index);
671 }
672
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700673 final public int countWorkingStats() {
674 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 return mWorkingProcs.size();
676 }
677
678 final public Stats getWorkingStats(int index) {
679 return mWorkingProcs.get(index);
680 }
681
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700682 final public String printCurrentLoad() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 StringWriter sw = new StringWriter();
Dianne Hackborn8c841092013-06-24 13:46:13 -0700684 PrintWriter pw = new FastPrintWriter(sw, false, 128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 pw.print("Load: ");
686 pw.print(mLoad1);
687 pw.print(" / ");
688 pw.print(mLoad5);
689 pw.print(" / ");
690 pw.println(mLoad15);
Dianne Hackborn8c841092013-06-24 13:46:13 -0700691 pw.flush();
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700692 return sw.toString();
693 }
694
695 final public String printCurrentState(long now) {
696 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700698 StringWriter sw = new StringWriter();
Dianne Hackborn8c841092013-06-24 13:46:13 -0700699 PrintWriter pw = new FastPrintWriter(sw, false, 1024);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700
701 pw.print("CPU usage from ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700702 if (now > mLastSampleTime) {
703 pw.print(now-mLastSampleTime);
704 pw.print("ms to ");
705 pw.print(now-mCurrentSampleTime);
706 pw.print("ms ago");
707 } else {
708 pw.print(mLastSampleTime-now);
709 pw.print("ms to ");
710 pw.print(mCurrentSampleTime-now);
711 pw.print("ms later");
712 }
713
714 long sampleTime = mCurrentSampleTime - mLastSampleTime;
715 long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
Dianne Hackborncdadee62012-06-06 11:48:46 -0700716 long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700717 if (percAwake != 100) {
718 pw.print(" with ");
719 pw.print(percAwake);
720 pw.print("% awake");
721 }
722 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700724 final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
725 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700727 if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
728 + (mCurrentSampleTime-mLastSampleTime));
729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 int N = mWorkingProcs.size();
731 for (int i=0; i<N; i++) {
732 Stats st = mWorkingProcs.get(i);
733 printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700734 st.pid, st.name, (int)(st.rel_uptime+5)/10,
735 st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 if (!st.removed && st.workingThreads != null) {
737 int M = st.workingThreads.size();
738 for (int j=0; j<M; j++) {
739 Stats tst = st.workingThreads.get(j);
740 printProcessCPU(pw,
741 tst.added ? " +" : (tst.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700742 tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
743 tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 }
745 }
746 }
747
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700748 printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700749 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
Dianne Hackborn8c841092013-06-24 13:46:13 -0700750
751 pw.flush();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 return sw.toString();
753 }
754
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700755 private void printRatio(PrintWriter pw, long numerator, long denominator) {
756 long thousands = (numerator*1000)/denominator;
757 long hundreds = thousands/10;
758 pw.print(hundreds);
759 if (hundreds < 10) {
760 long remainder = thousands - (hundreds*10);
761 if (remainder != 0) {
762 pw.print('.');
763 pw.print(remainder);
764 }
765 }
766 }
767
768 private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
769 int totalTime, int user, int system, int iowait, int irq, int softIrq,
770 int minFaults, int majFaults) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 pw.print(prefix);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700772 if (totalTime == 0) totalTime = 1;
773 printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
774 pw.print("% ");
775 if (pid >= 0) {
776 pw.print(pid);
777 pw.print("/");
778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 pw.print(label);
780 pw.print(": ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700781 printRatio(pw, user, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 pw.print("% user + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700783 printRatio(pw, system, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 pw.print("% kernel");
785 if (iowait > 0) {
786 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700787 printRatio(pw, iowait, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 pw.print("% iowait");
789 }
790 if (irq > 0) {
791 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700792 printRatio(pw, irq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 pw.print("% irq");
794 }
795 if (softIrq > 0) {
796 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700797 printRatio(pw, softIrq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 pw.print("% softirq");
799 }
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700800 if (minFaults > 0 || majFaults > 0) {
801 pw.print(" / faults:");
802 if (minFaults > 0) {
803 pw.print(" ");
804 pw.print(minFaults);
805 pw.print(" minor");
806 }
807 if (majFaults > 0) {
808 pw.print(" ");
809 pw.print(majFaults);
810 pw.print(" major");
811 }
812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 pw.println();
814 }
815
816 private String readFile(String file, char endChar) {
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -0700817 // Permit disk reads here, as /proc/meminfo isn't really "on
818 // disk" and should be fast. TODO: make BlockGuard ignore
819 // /proc/ and /sys/ files perhaps?
820 StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800821 FileInputStream is = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 try {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800823 is = new FileInputStream(file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 int len = is.read(mBuffer);
825 is.close();
826
827 if (len > 0) {
828 int i;
829 for (i=0; i<len; i++) {
830 if (mBuffer[i] == endChar) {
831 break;
832 }
833 }
Christian Mehlmauer4136c982010-05-25 20:04:09 +0200834 return new String(mBuffer, 0, i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 }
836 } catch (java.io.FileNotFoundException e) {
837 } catch (java.io.IOException e) {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800838 } finally {
839 if (is != null) {
840 try {
841 is.close();
842 } catch (java.io.IOException e) {
843 }
844 }
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -0700845 StrictMode.setThreadPolicy(savedPolicy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 }
847 return null;
848 }
849
850 private void getName(Stats st, String cmdlineFile) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700851 String newName = st.name;
Dianne Hackborn287952c2010-09-22 22:34:31 -0700852 if (st.name == null || st.name.equals("app_process")
853 || st.name.equals("<pre-initialized>")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 String cmdName = readFile(cmdlineFile, '\0');
855 if (cmdName != null && cmdName.length() > 1) {
856 newName = cmdName;
857 int i = newName.lastIndexOf("/");
858 if (i > 0 && i < newName.length()-1) {
859 newName = newName.substring(i+1);
860 }
861 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700862 if (newName == null) {
863 newName = st.baseName;
864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 }
866 if (st.name == null || !newName.equals(st.name)) {
867 st.name = newName;
868 st.nameWidth = onMeasureProcessName(st.name);
869 }
870 }
871}