blob: b1bb8c173a678e3cbdc822dae6ea8f96ca598fc4 [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
21import android.os.Process;
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -070022import android.os.StrictMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.os.SystemClock;
Joe Onorato8a9b2202010-02-26 18:56:32 -080024import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
26import java.io.File;
27import java.io.FileInputStream;
28import java.io.PrintWriter;
29import java.io.StringWriter;
30import java.util.ArrayList;
31import java.util.Collections;
32import java.util.Comparator;
Amith Yamasanie43530a2009-08-21 13:11:37 -070033import java.util.StringTokenizer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35public class ProcessStats {
36 private static final String TAG = "ProcessStats";
37 private static final boolean DEBUG = false;
Joe Onorato43a17652011-04-06 19:22:23 -070038 private static final boolean localLOGV = DEBUG || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
40 private static final int[] PROCESS_STATS_FORMAT = new int[] {
41 PROC_SPACE_TERM,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070042 PROC_SPACE_TERM|PROC_PARENS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 PROC_SPACE_TERM,
44 PROC_SPACE_TERM,
45 PROC_SPACE_TERM,
46 PROC_SPACE_TERM,
47 PROC_SPACE_TERM,
48 PROC_SPACE_TERM,
49 PROC_SPACE_TERM,
Dianne Hackborn151ceb92009-08-06 12:40:56 -070050 PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051 PROC_SPACE_TERM,
Dianne Hackborn151ceb92009-08-06 12:40:56 -070052 PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 PROC_SPACE_TERM,
54 PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
55 PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
56 };
57
Dianne Hackborn151ceb92009-08-06 12:40:56 -070058 static final int PROCESS_STAT_MINOR_FAULTS = 0;
59 static final int PROCESS_STAT_MAJOR_FAULTS = 1;
60 static final int PROCESS_STAT_UTIME = 2;
61 static final int PROCESS_STAT_STIME = 3;
62
Amith Yamasanieaeb6632009-06-03 15:16:10 -070063 /** Stores user time and system time in 100ths of a second. */
Dianne Hackborn151ceb92009-08-06 12:40:56 -070064 private final long[] mProcessStatsData = new long[4];
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[] mSinglePidStatsData = new long[4];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067
68 private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
69 PROC_SPACE_TERM,
70 PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 1: name
71 PROC_SPACE_TERM,
72 PROC_SPACE_TERM,
73 PROC_SPACE_TERM,
74 PROC_SPACE_TERM,
75 PROC_SPACE_TERM,
76 PROC_SPACE_TERM,
77 PROC_SPACE_TERM,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070078 PROC_SPACE_TERM|PROC_OUT_LONG, // 9: minor faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 PROC_SPACE_TERM,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070080 PROC_SPACE_TERM|PROC_OUT_LONG, // 11: major faults
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 PROC_SPACE_TERM,
82 PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
Dianne Hackborn287952c2010-09-22 22:34:31 -070083 PROC_SPACE_TERM|PROC_OUT_LONG, // 14: stime
84 PROC_SPACE_TERM,
85 PROC_SPACE_TERM,
86 PROC_SPACE_TERM,
87 PROC_SPACE_TERM,
88 PROC_SPACE_TERM,
89 PROC_SPACE_TERM,
90 PROC_SPACE_TERM|PROC_OUT_LONG, // 21: vsize
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 };
92
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070093 static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
94 static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
95 static final int PROCESS_FULL_STAT_UTIME = 3;
96 static final int PROCESS_FULL_STAT_STIME = 4;
Dianne Hackborn287952c2010-09-22 22:34:31 -070097 static final int PROCESS_FULL_STAT_VSIZE = 5;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070098
Dianne Hackborn287952c2010-09-22 22:34:31 -070099 private final String[] mProcessFullStatsStringData = new String[6];
100 private final long[] mProcessFullStatsData = new long[6];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101
102 private static final int[] SYSTEM_CPU_FORMAT = new int[] {
103 PROC_SPACE_TERM|PROC_COMBINE,
104 PROC_SPACE_TERM|PROC_OUT_LONG, // 1: user time
105 PROC_SPACE_TERM|PROC_OUT_LONG, // 2: nice time
106 PROC_SPACE_TERM|PROC_OUT_LONG, // 3: sys time
107 PROC_SPACE_TERM|PROC_OUT_LONG, // 4: idle time
108 PROC_SPACE_TERM|PROC_OUT_LONG, // 5: iowait time
109 PROC_SPACE_TERM|PROC_OUT_LONG, // 6: irq time
110 PROC_SPACE_TERM|PROC_OUT_LONG // 7: softirq time
111 };
112
113 private final long[] mSystemCpuData = new long[7];
114
115 private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
116 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 0: 1 min
117 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 1: 5 mins
118 PROC_SPACE_TERM|PROC_OUT_FLOAT // 2: 15 mins
119 };
120
121 private final float[] mLoadAverageData = new float[3];
122
123 private final boolean mIncludeThreads;
124
125 private float mLoad1 = 0;
126 private float mLoad5 = 0;
127 private float mLoad15 = 0;
128
129 private long mCurrentSampleTime;
130 private long mLastSampleTime;
131
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700132 private long mCurrentSampleRealTime;
133 private long mLastSampleRealTime;
134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private long mBaseUserTime;
136 private long mBaseSystemTime;
137 private long mBaseIoWaitTime;
138 private long mBaseIrqTime;
139 private long mBaseSoftIrqTime;
140 private long mBaseIdleTime;
141 private int mRelUserTime;
142 private int mRelSystemTime;
143 private int mRelIoWaitTime;
144 private int mRelIrqTime;
145 private int mRelSoftIrqTime;
146 private int mRelIdleTime;
147
148 private int[] mCurPids;
149 private int[] mCurThreadPids;
150
151 private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
152 private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
153 private boolean mWorkingProcsSorted;
154
155 private boolean mFirst = true;
156
Martin Wallgrenca894b32011-09-20 13:45:48 +0200157 private byte[] mBuffer = new byte[4096];
Amith Yamasanie43530a2009-08-21 13:11:37 -0700158
159 /**
160 * The time in microseconds that the CPU has been running at each speed.
161 */
162 private long[] mCpuSpeedTimes;
163
164 /**
165 * The relative time in microseconds that the CPU has been running at each speed.
166 */
167 private long[] mRelCpuSpeedTimes;
168
169 /**
170 * The different speeds that the CPU can be running at.
171 */
172 private long[] mCpuSpeeds;
173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 public static class Stats {
175 public final int pid;
176 final String statFile;
177 final String cmdlineFile;
178 final String threadsDir;
179 final ArrayList<Stats> threadStats;
180 final ArrayList<Stats> workingThreads;
181
Dianne Hackborn287952c2010-09-22 22:34:31 -0700182 public boolean interesting;
183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 public String baseName;
185 public String name;
Dianne Hackborn45ce8642011-07-14 16:10:16 -0700186 public int nameWidth;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700188 public long base_uptime;
189 public long rel_uptime;
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 public long base_utime;
192 public long base_stime;
193 public int rel_utime;
194 public int rel_stime;
195
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700196 public long base_minfaults;
197 public long base_majfaults;
198 public int rel_minfaults;
199 public int rel_majfaults;
200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 public boolean active;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700202 public boolean working;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 public boolean added;
204 public boolean removed;
205
206 Stats(int _pid, int parentPid, boolean includeThreads) {
207 pid = _pid;
208 if (parentPid < 0) {
209 final File procDir = new File("/proc", Integer.toString(pid));
210 statFile = new File(procDir, "stat").toString();
211 cmdlineFile = new File(procDir, "cmdline").toString();
212 threadsDir = (new File(procDir, "task")).toString();
213 if (includeThreads) {
214 threadStats = new ArrayList<Stats>();
215 workingThreads = new ArrayList<Stats>();
216 } else {
217 threadStats = null;
218 workingThreads = null;
219 }
220 } else {
221 final File procDir = new File("/proc", Integer.toString(
222 parentPid));
223 final File taskDir = new File(
224 new File(procDir, "task"), Integer.toString(pid));
225 statFile = new File(taskDir, "stat").toString();
226 cmdlineFile = null;
227 threadsDir = null;
228 threadStats = null;
229 workingThreads = null;
230 }
231 }
232 }
233
234 private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
235 public final int
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700236 compare(Stats sta, Stats stb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 int ta = sta.rel_utime + sta.rel_stime;
238 int tb = stb.rel_utime + stb.rel_stime;
239 if (ta != tb) {
240 return ta > tb ? -1 : 1;
241 }
242 if (sta.added != stb.added) {
243 return sta.added ? -1 : 1;
244 }
245 if (sta.removed != stb.removed) {
246 return sta.added ? -1 : 1;
247 }
248 return 0;
249 }
250 };
251
252
253 public ProcessStats(boolean includeThreads) {
254 mIncludeThreads = includeThreads;
255 }
256
257 public void onLoadChanged(float load1, float load5, float load15) {
258 }
259
260 public int onMeasureProcessName(String name) {
261 return 0;
262 }
263
264 public void init() {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700265 if (DEBUG) Slog.v(TAG, "Init: " + this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 mFirst = true;
267 update();
268 }
269
270 public void update() {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700271 if (DEBUG) Slog.v(TAG, "Update: " + this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 mLastSampleTime = mCurrentSampleTime;
273 mCurrentSampleTime = SystemClock.uptimeMillis();
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700274 mLastSampleRealTime = mCurrentSampleRealTime;
275 mCurrentSampleRealTime = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276
277 final long[] sysCpu = mSystemCpuData;
278 if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
279 null, sysCpu, null)) {
280 // Total user time is user + nice time.
281 final long usertime = sysCpu[0]+sysCpu[1];
282 // Total system time is simply system time.
283 final long systemtime = sysCpu[2];
284 // Total idle time is simply idle time.
285 final long idletime = sysCpu[3];
286 // Total irq time is iowait + irq + softirq time.
287 final long iowaittime = sysCpu[4];
288 final long irqtime = sysCpu[5];
289 final long softirqtime = sysCpu[6];
290
291 mRelUserTime = (int)(usertime - mBaseUserTime);
292 mRelSystemTime = (int)(systemtime - mBaseSystemTime);
293 mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
294 mRelIrqTime = (int)(irqtime - mBaseIrqTime);
295 mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
296 mRelIdleTime = (int)(idletime - mBaseIdleTime);
297
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700298 if (DEBUG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800299 Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 + " S:" + sysCpu[2] + " I:" + sysCpu[3]
301 + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
302 + " O:" + sysCpu[6]);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800303 Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
305 }
306
307 mBaseUserTime = usertime;
308 mBaseSystemTime = systemtime;
309 mBaseIoWaitTime = iowaittime;
310 mBaseIrqTime = irqtime;
311 mBaseSoftIrqTime = softirqtime;
312 mBaseIdleTime = idletime;
313 }
314
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700315 mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
316
317 final float[] loadAverages = mLoadAverageData;
318 if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
319 null, null, loadAverages)) {
320 float load1 = loadAverages[0];
321 float load5 = loadAverages[1];
322 float load15 = loadAverages[2];
323 if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
324 mLoad1 = load1;
325 mLoad5 = load5;
326 mLoad15 = load15;
327 onLoadChanged(load1, load5, load15);
328 }
329 }
330
331 if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
332 + (SystemClock.uptimeMillis()-mCurrentSampleTime));
333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 mWorkingProcsSorted = false;
335 mFirst = false;
336 }
337
338 private int[] collectStats(String statsFile, int parentPid, boolean first,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700339 int[] curPids, ArrayList<Stats> allProcs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 int[] pids = Process.getPids(statsFile, curPids);
342 int NP = (pids == null) ? 0 : pids.length;
343 int NS = allProcs.size();
344 int curStatsIndex = 0;
345 for (int i=0; i<NP; i++) {
346 int pid = pids[i];
347 if (pid < 0) {
348 NP = pid;
349 break;
350 }
351 Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
352
353 if (st != null && st.pid == pid) {
354 // Update an existing process...
355 st.added = false;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700356 st.working = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 curStatsIndex++;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700358 if (DEBUG) Slog.v(TAG, "Existing "
359 + (parentPid < 0 ? "process" : "thread")
360 + " pid " + pid + ": " + st);
361
Dianne Hackborn287952c2010-09-22 22:34:31 -0700362 if (st.interesting) {
363 final long uptime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364
Dianne Hackborn287952c2010-09-22 22:34:31 -0700365 final long[] procStats = mProcessStatsData;
366 if (!Process.readProcFile(st.statFile.toString(),
367 PROCESS_STATS_FORMAT, null, procStats, null)) {
368 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370
Dianne Hackborn287952c2010-09-22 22:34:31 -0700371 final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
372 final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
373 final long utime = procStats[PROCESS_STAT_UTIME];
374 final long stime = procStats[PROCESS_STAT_STIME];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375
Dianne Hackborn287952c2010-09-22 22:34:31 -0700376 if (utime == st.base_utime && stime == st.base_stime) {
377 st.rel_utime = 0;
378 st.rel_stime = 0;
379 st.rel_minfaults = 0;
380 st.rel_majfaults = 0;
381 if (st.active) {
382 st.active = false;
383 }
384 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 }
Dianne Hackborn287952c2010-09-22 22:34:31 -0700386
387 if (!st.active) {
388 st.active = true;
389 }
390
391 if (parentPid < 0) {
392 getName(st, st.cmdlineFile);
393 if (st.threadStats != null) {
394 mCurThreadPids = collectStats(st.threadsDir, pid, false,
395 mCurThreadPids, st.threadStats);
396 }
397 }
398
399 if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
400 + " utime=" + utime + "-" + st.base_utime
401 + " stime=" + stime + "-" + st.base_stime
402 + " minfaults=" + minfaults + "-" + st.base_minfaults
403 + " majfaults=" + majfaults + "-" + st.base_majfaults);
404
405 st.rel_uptime = uptime - st.base_uptime;
406 st.base_uptime = uptime;
407 st.rel_utime = (int)(utime - st.base_utime);
408 st.rel_stime = (int)(stime - st.base_stime);
409 st.base_utime = utime;
410 st.base_stime = stime;
411 st.rel_minfaults = (int)(minfaults - st.base_minfaults);
412 st.rel_majfaults = (int)(majfaults - st.base_majfaults);
413 st.base_minfaults = minfaults;
414 st.base_majfaults = majfaults;
415 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 continue;
419 }
420
421 if (st == null || st.pid > pid) {
422 // We have a new process!
423 st = new Stats(pid, parentPid, mIncludeThreads);
424 allProcs.add(curStatsIndex, st);
425 curStatsIndex++;
426 NS++;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700427 if (DEBUG) Slog.v(TAG, "New "
428 + (parentPid < 0 ? "process" : "thread")
429 + " pid " + pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430
431 final String[] procStatsString = mProcessFullStatsStringData;
432 final long[] procStats = mProcessFullStatsData;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700433 st.base_uptime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 if (Process.readProcFile(st.statFile.toString(),
435 PROCESS_FULL_STATS_FORMAT, procStatsString,
436 procStats, null)) {
Dianne Hackborn287952c2010-09-22 22:34:31 -0700437 // This is a possible way to filter out processes that
438 // are actually kernel threads... do we want to? Some
439 // of them do use CPU, but there can be a *lot* that are
440 // not doing anything.
441 if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) {
442 st.interesting = true;
443 st.baseName = procStatsString[0];
444 st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
445 st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
446 st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
447 st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
448 } else {
449 Slog.i(TAG, "Skipping kernel process pid " + pid
450 + " name " + procStatsString[0]);
451 st.baseName = procStatsString[0];
452 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 } else {
Dianne Hackborn287952c2010-09-22 22:34:31 -0700454 Slog.w(TAG, "Skipping unknown process pid " + pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 st.baseName = "<unknown>";
456 st.base_utime = st.base_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700457 st.base_minfaults = st.base_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 }
459
460 if (parentPid < 0) {
461 getName(st, st.cmdlineFile);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700462 if (st.threadStats != null) {
463 mCurThreadPids = collectStats(st.threadsDir, pid, true,
464 mCurThreadPids, st.threadStats);
465 }
Dianne Hackborn287952c2010-09-22 22:34:31 -0700466 } else if (st.interesting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 st.name = st.baseName;
468 st.nameWidth = onMeasureProcessName(st.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700470
471 if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
472 + " utime=" + st.base_utime + " stime=" + st.base_stime
473 + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 st.rel_utime = 0;
476 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700477 st.rel_minfaults = 0;
478 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 st.added = true;
Dianne Hackborn287952c2010-09-22 22:34:31 -0700480 if (!first && st.interesting) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700481 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 }
483 continue;
484 }
485
486 // This process has gone away!
487 st.rel_utime = 0;
488 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700489 st.rel_minfaults = 0;
490 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 st.removed = true;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700492 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 allProcs.remove(curStatsIndex);
494 NS--;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700495 if (DEBUG) Slog.v(TAG, "Removed "
496 + (parentPid < 0 ? "process" : "thread")
497 + " pid " + pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 // Decrement the loop counter so that we process the current pid
499 // again the next time through the loop.
500 i--;
501 continue;
502 }
503
504 while (curStatsIndex < NS) {
505 // This process has gone away!
506 final Stats st = allProcs.get(curStatsIndex);
507 st.rel_utime = 0;
508 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700509 st.rel_minfaults = 0;
510 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 st.removed = true;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700512 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 allProcs.remove(curStatsIndex);
514 NS--;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800515 if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
517
518 return pids;
519 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700520
521 public long getCpuTimeForPid(int pid) {
522 final String statFile = "/proc/" + pid + "/stat";
523 final long[] statsData = mSinglePidStatsData;
524 if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
525 null, statsData, null)) {
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700526 long time = statsData[PROCESS_STAT_UTIME]
527 + statsData[PROCESS_STAT_STIME];
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700528 return time;
529 }
530 return 0;
531 }
532
Amith Yamasanie43530a2009-08-21 13:11:37 -0700533 /**
534 * Returns the times spent at each CPU speed, since the last call to this method. If this
535 * is the first time, it will return 1 for each value.
536 * @return relative times spent at different speed steps.
537 */
538 public long[] getLastCpuSpeedTimes() {
539 if (mCpuSpeedTimes == null) {
540 mCpuSpeedTimes = getCpuSpeedTimes(null);
541 mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
542 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
543 mRelCpuSpeedTimes[i] = 1; // Initialize
544 }
545 } else {
546 getCpuSpeedTimes(mRelCpuSpeedTimes);
547 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
548 long temp = mRelCpuSpeedTimes[i];
549 mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
550 mCpuSpeedTimes[i] = temp;
551 }
552 }
553 return mRelCpuSpeedTimes;
554 }
555
556 private long[] getCpuSpeedTimes(long[] out) {
557 long[] tempTimes = out;
558 long[] tempSpeeds = mCpuSpeeds;
Martin Wallgrenca894b32011-09-20 13:45:48 +0200559 final int MAX_SPEEDS = 60;
Amith Yamasanie43530a2009-08-21 13:11:37 -0700560 if (out == null) {
561 tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
562 tempSpeeds = new long[MAX_SPEEDS];
563 }
564 int speed = 0;
565 String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400566 // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
567 if (file != null) {
568 StringTokenizer st = new StringTokenizer(file, "\n ");
569 while (st.hasMoreElements()) {
570 String token = st.nextToken();
571 try {
572 long val = Long.parseLong(token);
573 tempSpeeds[speed] = val;
574 token = st.nextToken();
575 val = Long.parseLong(token);
576 tempTimes[speed] = val;
577 speed++;
578 if (speed == MAX_SPEEDS) break; // No more
579 if (localLOGV && out == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800580 Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400581 + "\t" + tempTimes[speed - 1]);
582 }
583 } catch (NumberFormatException nfe) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800584 Slog.i(TAG, "Unable to parse time_in_state");
Amith Yamasanie43530a2009-08-21 13:11:37 -0700585 }
Amith Yamasanie43530a2009-08-21 13:11:37 -0700586 }
587 }
588 if (out == null) {
589 out = new long[speed];
590 mCpuSpeeds = new long[speed];
591 System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
592 System.arraycopy(tempTimes, 0, out, 0, speed);
593 }
594 return out;
595 }
596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 final public int getLastUserTime() {
598 return mRelUserTime;
599 }
600
601 final public int getLastSystemTime() {
602 return mRelSystemTime;
603 }
604
605 final public int getLastIoWaitTime() {
606 return mRelIoWaitTime;
607 }
608
609 final public int getLastIrqTime() {
610 return mRelIrqTime;
611 }
612
613 final public int getLastSoftIrqTime() {
614 return mRelSoftIrqTime;
615 }
616
617 final public int getLastIdleTime() {
618 return mRelIdleTime;
619 }
620
621 final public float getTotalCpuPercent() {
Dianne Hackborncdadee62012-06-06 11:48:46 -0700622 int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
623 if (denom <= 0) {
624 return 0;
625 }
626 return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 }
628
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700629 final void buildWorkingProcs() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 if (!mWorkingProcsSorted) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700631 mWorkingProcs.clear();
632 final int N = mProcStats.size();
633 for (int i=0; i<N; i++) {
634 Stats stats = mProcStats.get(i);
635 if (stats.working) {
636 mWorkingProcs.add(stats);
637 if (stats.threadStats != null && stats.threadStats.size() > 1) {
638 stats.workingThreads.clear();
639 final int M = stats.threadStats.size();
640 for (int j=0; j<M; j++) {
641 Stats tstats = stats.threadStats.get(j);
642 if (tstats.working) {
643 stats.workingThreads.add(tstats);
644 }
645 }
646 Collections.sort(stats.workingThreads, sLoadComparator);
647 }
648 }
649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 Collections.sort(mWorkingProcs, sLoadComparator);
651 mWorkingProcsSorted = true;
652 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700653 }
654
Dianne Hackborn287952c2010-09-22 22:34:31 -0700655 final public int countStats() {
656 return mProcStats.size();
657 }
658
659 final public Stats getStats(int index) {
660 return mProcStats.get(index);
661 }
662
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700663 final public int countWorkingStats() {
664 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 return mWorkingProcs.size();
666 }
667
668 final public Stats getWorkingStats(int index) {
669 return mWorkingProcs.get(index);
670 }
671
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700672 final public String printCurrentLoad() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 StringWriter sw = new StringWriter();
674 PrintWriter pw = new PrintWriter(sw);
675 pw.print("Load: ");
676 pw.print(mLoad1);
677 pw.print(" / ");
678 pw.print(mLoad5);
679 pw.print(" / ");
680 pw.println(mLoad15);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700681 return sw.toString();
682 }
683
684 final public String printCurrentState(long now) {
685 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700687 StringWriter sw = new StringWriter();
688 PrintWriter pw = new PrintWriter(sw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689
690 pw.print("CPU usage from ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700691 if (now > mLastSampleTime) {
692 pw.print(now-mLastSampleTime);
693 pw.print("ms to ");
694 pw.print(now-mCurrentSampleTime);
695 pw.print("ms ago");
696 } else {
697 pw.print(mLastSampleTime-now);
698 pw.print("ms to ");
699 pw.print(mCurrentSampleTime-now);
700 pw.print("ms later");
701 }
702
703 long sampleTime = mCurrentSampleTime - mLastSampleTime;
704 long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
Dianne Hackborncdadee62012-06-06 11:48:46 -0700705 long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700706 if (percAwake != 100) {
707 pw.print(" with ");
708 pw.print(percAwake);
709 pw.print("% awake");
710 }
711 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700713 final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
714 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700716 if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
717 + (mCurrentSampleTime-mLastSampleTime));
718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 int N = mWorkingProcs.size();
720 for (int i=0; i<N; i++) {
721 Stats st = mWorkingProcs.get(i);
722 printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700723 st.pid, st.name, (int)(st.rel_uptime+5)/10,
724 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 -0800725 if (!st.removed && st.workingThreads != null) {
726 int M = st.workingThreads.size();
727 for (int j=0; j<M; j++) {
728 Stats tst = st.workingThreads.get(j);
729 printProcessCPU(pw,
730 tst.added ? " +" : (tst.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700731 tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
732 tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 }
734 }
735 }
736
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700737 printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700738 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739
740 return sw.toString();
741 }
742
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700743 private void printRatio(PrintWriter pw, long numerator, long denominator) {
744 long thousands = (numerator*1000)/denominator;
745 long hundreds = thousands/10;
746 pw.print(hundreds);
747 if (hundreds < 10) {
748 long remainder = thousands - (hundreds*10);
749 if (remainder != 0) {
750 pw.print('.');
751 pw.print(remainder);
752 }
753 }
754 }
755
756 private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
757 int totalTime, int user, int system, int iowait, int irq, int softIrq,
758 int minFaults, int majFaults) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 pw.print(prefix);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700760 if (totalTime == 0) totalTime = 1;
761 printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
762 pw.print("% ");
763 if (pid >= 0) {
764 pw.print(pid);
765 pw.print("/");
766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 pw.print(label);
768 pw.print(": ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700769 printRatio(pw, user, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 pw.print("% user + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700771 printRatio(pw, system, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 pw.print("% kernel");
773 if (iowait > 0) {
774 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700775 printRatio(pw, iowait, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 pw.print("% iowait");
777 }
778 if (irq > 0) {
779 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700780 printRatio(pw, irq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 pw.print("% irq");
782 }
783 if (softIrq > 0) {
784 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700785 printRatio(pw, softIrq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 pw.print("% softirq");
787 }
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700788 if (minFaults > 0 || majFaults > 0) {
789 pw.print(" / faults:");
790 if (minFaults > 0) {
791 pw.print(" ");
792 pw.print(minFaults);
793 pw.print(" minor");
794 }
795 if (majFaults > 0) {
796 pw.print(" ");
797 pw.print(majFaults);
798 pw.print(" major");
799 }
800 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 pw.println();
802 }
803
804 private String readFile(String file, char endChar) {
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -0700805 // Permit disk reads here, as /proc/meminfo isn't really "on
806 // disk" and should be fast. TODO: make BlockGuard ignore
807 // /proc/ and /sys/ files perhaps?
808 StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800809 FileInputStream is = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 try {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800811 is = new FileInputStream(file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 int len = is.read(mBuffer);
813 is.close();
814
815 if (len > 0) {
816 int i;
817 for (i=0; i<len; i++) {
818 if (mBuffer[i] == endChar) {
819 break;
820 }
821 }
Christian Mehlmauer4136c982010-05-25 20:04:09 +0200822 return new String(mBuffer, 0, i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
824 } catch (java.io.FileNotFoundException e) {
825 } catch (java.io.IOException e) {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800826 } finally {
827 if (is != null) {
828 try {
829 is.close();
830 } catch (java.io.IOException e) {
831 }
832 }
Dianne Hackborn8e8d65f2011-08-11 19:36:18 -0700833 StrictMode.setThreadPolicy(savedPolicy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
835 return null;
836 }
837
838 private void getName(Stats st, String cmdlineFile) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700839 String newName = st.name;
Dianne Hackborn287952c2010-09-22 22:34:31 -0700840 if (st.name == null || st.name.equals("app_process")
841 || st.name.equals("<pre-initialized>")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 String cmdName = readFile(cmdlineFile, '\0');
843 if (cmdName != null && cmdName.length() > 1) {
844 newName = cmdName;
845 int i = newName.lastIndexOf("/");
846 if (i > 0 && i < newName.length()-1) {
847 newName = newName.substring(i+1);
848 }
849 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700850 if (newName == null) {
851 newName = st.baseName;
852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854 if (st.name == null || !newName.equals(st.name)) {
855 st.name = newName;
856 st.nameWidth = onMeasureProcessName(st.name);
857 }
858 }
859}