blob: 1a12a84a0a632f97775bc8836c3a34a4508f8a2e [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
17package com.android.server;
18
19import static android.os.Process.*;
20
21import android.os.Process;
22import android.os.SystemClock;
23import android.util.Config;
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;
38 private static final boolean localLOGV = DEBUG || Config.LOGV;
39
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
157 private byte[] mBuffer = new byte[256];
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;
186 int nameWidth;
187
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;
559 final int MAX_SPEEDS = 20;
560 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() {
622 return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100)
623 / (mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime);
624 }
625
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700626 final void buildWorkingProcs() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 if (!mWorkingProcsSorted) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700628 mWorkingProcs.clear();
629 final int N = mProcStats.size();
630 for (int i=0; i<N; i++) {
631 Stats stats = mProcStats.get(i);
632 if (stats.working) {
633 mWorkingProcs.add(stats);
634 if (stats.threadStats != null && stats.threadStats.size() > 1) {
635 stats.workingThreads.clear();
636 final int M = stats.threadStats.size();
637 for (int j=0; j<M; j++) {
638 Stats tstats = stats.threadStats.get(j);
639 if (tstats.working) {
640 stats.workingThreads.add(tstats);
641 }
642 }
643 Collections.sort(stats.workingThreads, sLoadComparator);
644 }
645 }
646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 Collections.sort(mWorkingProcs, sLoadComparator);
648 mWorkingProcsSorted = true;
649 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700650 }
651
Dianne Hackborn287952c2010-09-22 22:34:31 -0700652 final public int countStats() {
653 return mProcStats.size();
654 }
655
656 final public Stats getStats(int index) {
657 return mProcStats.get(index);
658 }
659
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700660 final public int countWorkingStats() {
661 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 return mWorkingProcs.size();
663 }
664
665 final public Stats getWorkingStats(int index) {
666 return mWorkingProcs.get(index);
667 }
668
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700669 final public String printCurrentLoad() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 StringWriter sw = new StringWriter();
671 PrintWriter pw = new PrintWriter(sw);
672 pw.print("Load: ");
673 pw.print(mLoad1);
674 pw.print(" / ");
675 pw.print(mLoad5);
676 pw.print(" / ");
677 pw.println(mLoad15);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700678 return sw.toString();
679 }
680
681 final public String printCurrentState(long now) {
682 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700684 StringWriter sw = new StringWriter();
685 PrintWriter pw = new PrintWriter(sw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686
687 pw.print("CPU usage from ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700688 if (now > mLastSampleTime) {
689 pw.print(now-mLastSampleTime);
690 pw.print("ms to ");
691 pw.print(now-mCurrentSampleTime);
692 pw.print("ms ago");
693 } else {
694 pw.print(mLastSampleTime-now);
695 pw.print("ms to ");
696 pw.print(mCurrentSampleTime-now);
697 pw.print("ms later");
698 }
699
700 long sampleTime = mCurrentSampleTime - mLastSampleTime;
701 long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
702 long percAwake = (sampleTime*100) / sampleRealTime;
703 if (percAwake != 100) {
704 pw.print(" with ");
705 pw.print(percAwake);
706 pw.print("% awake");
707 }
708 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700710 final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
711 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700713 if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
714 + (mCurrentSampleTime-mLastSampleTime));
715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 int N = mWorkingProcs.size();
717 for (int i=0; i<N; i++) {
718 Stats st = mWorkingProcs.get(i);
719 printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700720 st.pid, st.name, (int)(st.rel_uptime+5)/10,
721 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 -0800722 if (!st.removed && st.workingThreads != null) {
723 int M = st.workingThreads.size();
724 for (int j=0; j<M; j++) {
725 Stats tst = st.workingThreads.get(j);
726 printProcessCPU(pw,
727 tst.added ? " +" : (tst.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700728 tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
729 tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 }
731 }
732 }
733
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700734 printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700735 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736
737 return sw.toString();
738 }
739
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700740 private void printRatio(PrintWriter pw, long numerator, long denominator) {
741 long thousands = (numerator*1000)/denominator;
742 long hundreds = thousands/10;
743 pw.print(hundreds);
744 if (hundreds < 10) {
745 long remainder = thousands - (hundreds*10);
746 if (remainder != 0) {
747 pw.print('.');
748 pw.print(remainder);
749 }
750 }
751 }
752
753 private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
754 int totalTime, int user, int system, int iowait, int irq, int softIrq,
755 int minFaults, int majFaults) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 pw.print(prefix);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700757 if (totalTime == 0) totalTime = 1;
758 printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
759 pw.print("% ");
760 if (pid >= 0) {
761 pw.print(pid);
762 pw.print("/");
763 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 pw.print(label);
765 pw.print(": ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700766 printRatio(pw, user, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 pw.print("% user + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700768 printRatio(pw, system, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 pw.print("% kernel");
770 if (iowait > 0) {
771 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700772 printRatio(pw, iowait, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 pw.print("% iowait");
774 }
775 if (irq > 0) {
776 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700777 printRatio(pw, irq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 pw.print("% irq");
779 }
780 if (softIrq > 0) {
781 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700782 printRatio(pw, softIrq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 pw.print("% softirq");
784 }
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700785 if (minFaults > 0 || majFaults > 0) {
786 pw.print(" / faults:");
787 if (minFaults > 0) {
788 pw.print(" ");
789 pw.print(minFaults);
790 pw.print(" minor");
791 }
792 if (majFaults > 0) {
793 pw.print(" ");
794 pw.print(majFaults);
795 pw.print(" major");
796 }
797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 pw.println();
799 }
800
801 private String readFile(String file, char endChar) {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800802 FileInputStream is = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 try {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800804 is = new FileInputStream(file);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 int len = is.read(mBuffer);
806 is.close();
807
808 if (len > 0) {
809 int i;
810 for (i=0; i<len; i++) {
811 if (mBuffer[i] == endChar) {
812 break;
813 }
814 }
Christian Mehlmauer4136c982010-05-25 20:04:09 +0200815 return new String(mBuffer, 0, i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 }
817 } catch (java.io.FileNotFoundException e) {
818 } catch (java.io.IOException e) {
Brad Fitzpatrick6689ac82010-11-15 16:26:04 -0800819 } finally {
820 if (is != null) {
821 try {
822 is.close();
823 } catch (java.io.IOException e) {
824 }
825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 }
827 return null;
828 }
829
830 private void getName(Stats st, String cmdlineFile) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700831 String newName = st.name;
Dianne Hackborn287952c2010-09-22 22:34:31 -0700832 if (st.name == null || st.name.equals("app_process")
833 || st.name.equals("<pre-initialized>")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 String cmdName = readFile(cmdlineFile, '\0');
835 if (cmdName != null && cmdName.length() > 1) {
836 newName = cmdName;
837 int i = newName.lastIndexOf("/");
838 if (i > 0 && i < newName.length()-1) {
839 newName = newName.substring(i+1);
840 }
841 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700842 if (newName == null) {
843 newName = st.baseName;
844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 }
846 if (st.name == null || !newName.equals(st.name)) {
847 st.name = newName;
848 st.nameWidth = onMeasureProcessName(st.name);
849 }
850 }
851}