blob: 0c8c2fd40d007e35fbcb27cbbb4be5f04228048c [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
83 PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
84 };
85
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -070086 static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1;
87 static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2;
88 static final int PROCESS_FULL_STAT_UTIME = 3;
89 static final int PROCESS_FULL_STAT_STIME = 4;
90
91 private final String[] mProcessFullStatsStringData = new String[5];
92 private final long[] mProcessFullStatsData = new long[5];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 private static final int[] SYSTEM_CPU_FORMAT = new int[] {
95 PROC_SPACE_TERM|PROC_COMBINE,
96 PROC_SPACE_TERM|PROC_OUT_LONG, // 1: user time
97 PROC_SPACE_TERM|PROC_OUT_LONG, // 2: nice time
98 PROC_SPACE_TERM|PROC_OUT_LONG, // 3: sys time
99 PROC_SPACE_TERM|PROC_OUT_LONG, // 4: idle time
100 PROC_SPACE_TERM|PROC_OUT_LONG, // 5: iowait time
101 PROC_SPACE_TERM|PROC_OUT_LONG, // 6: irq time
102 PROC_SPACE_TERM|PROC_OUT_LONG // 7: softirq time
103 };
104
105 private final long[] mSystemCpuData = new long[7];
106
107 private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
108 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 0: 1 min
109 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 1: 5 mins
110 PROC_SPACE_TERM|PROC_OUT_FLOAT // 2: 15 mins
111 };
112
113 private final float[] mLoadAverageData = new float[3];
114
115 private final boolean mIncludeThreads;
116
117 private float mLoad1 = 0;
118 private float mLoad5 = 0;
119 private float mLoad15 = 0;
120
121 private long mCurrentSampleTime;
122 private long mLastSampleTime;
123
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700124 private long mCurrentSampleRealTime;
125 private long mLastSampleRealTime;
126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 private long mBaseUserTime;
128 private long mBaseSystemTime;
129 private long mBaseIoWaitTime;
130 private long mBaseIrqTime;
131 private long mBaseSoftIrqTime;
132 private long mBaseIdleTime;
133 private int mRelUserTime;
134 private int mRelSystemTime;
135 private int mRelIoWaitTime;
136 private int mRelIrqTime;
137 private int mRelSoftIrqTime;
138 private int mRelIdleTime;
139
140 private int[] mCurPids;
141 private int[] mCurThreadPids;
142
143 private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
144 private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
145 private boolean mWorkingProcsSorted;
146
147 private boolean mFirst = true;
148
149 private byte[] mBuffer = new byte[256];
Amith Yamasanie43530a2009-08-21 13:11:37 -0700150
151 /**
152 * The time in microseconds that the CPU has been running at each speed.
153 */
154 private long[] mCpuSpeedTimes;
155
156 /**
157 * The relative time in microseconds that the CPU has been running at each speed.
158 */
159 private long[] mRelCpuSpeedTimes;
160
161 /**
162 * The different speeds that the CPU can be running at.
163 */
164 private long[] mCpuSpeeds;
165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 public static class Stats {
167 public final int pid;
168 final String statFile;
169 final String cmdlineFile;
170 final String threadsDir;
171 final ArrayList<Stats> threadStats;
172 final ArrayList<Stats> workingThreads;
173
174 public String baseName;
175 public String name;
176 int nameWidth;
177
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700178 public long base_uptime;
179 public long rel_uptime;
180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 public long base_utime;
182 public long base_stime;
183 public int rel_utime;
184 public int rel_stime;
185
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700186 public long base_minfaults;
187 public long base_majfaults;
188 public int rel_minfaults;
189 public int rel_majfaults;
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 public boolean active;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700192 public boolean working;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 public boolean added;
194 public boolean removed;
195
196 Stats(int _pid, int parentPid, boolean includeThreads) {
197 pid = _pid;
198 if (parentPid < 0) {
199 final File procDir = new File("/proc", Integer.toString(pid));
200 statFile = new File(procDir, "stat").toString();
201 cmdlineFile = new File(procDir, "cmdline").toString();
202 threadsDir = (new File(procDir, "task")).toString();
203 if (includeThreads) {
204 threadStats = new ArrayList<Stats>();
205 workingThreads = new ArrayList<Stats>();
206 } else {
207 threadStats = null;
208 workingThreads = null;
209 }
210 } else {
211 final File procDir = new File("/proc", Integer.toString(
212 parentPid));
213 final File taskDir = new File(
214 new File(procDir, "task"), Integer.toString(pid));
215 statFile = new File(taskDir, "stat").toString();
216 cmdlineFile = null;
217 threadsDir = null;
218 threadStats = null;
219 workingThreads = null;
220 }
221 }
222 }
223
224 private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
225 public final int
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700226 compare(Stats sta, Stats stb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 int ta = sta.rel_utime + sta.rel_stime;
228 int tb = stb.rel_utime + stb.rel_stime;
229 if (ta != tb) {
230 return ta > tb ? -1 : 1;
231 }
232 if (sta.added != stb.added) {
233 return sta.added ? -1 : 1;
234 }
235 if (sta.removed != stb.removed) {
236 return sta.added ? -1 : 1;
237 }
238 return 0;
239 }
240 };
241
242
243 public ProcessStats(boolean includeThreads) {
244 mIncludeThreads = includeThreads;
245 }
246
247 public void onLoadChanged(float load1, float load5, float load15) {
248 }
249
250 public int onMeasureProcessName(String name) {
251 return 0;
252 }
253
254 public void init() {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700255 if (DEBUG) Slog.v(TAG, "Init: " + this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 mFirst = true;
257 update();
258 }
259
260 public void update() {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700261 if (DEBUG) Slog.v(TAG, "Update: " + this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 mLastSampleTime = mCurrentSampleTime;
263 mCurrentSampleTime = SystemClock.uptimeMillis();
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700264 mLastSampleRealTime = mCurrentSampleRealTime;
265 mCurrentSampleRealTime = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266
267 final long[] sysCpu = mSystemCpuData;
268 if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
269 null, sysCpu, null)) {
270 // Total user time is user + nice time.
271 final long usertime = sysCpu[0]+sysCpu[1];
272 // Total system time is simply system time.
273 final long systemtime = sysCpu[2];
274 // Total idle time is simply idle time.
275 final long idletime = sysCpu[3];
276 // Total irq time is iowait + irq + softirq time.
277 final long iowaittime = sysCpu[4];
278 final long irqtime = sysCpu[5];
279 final long softirqtime = sysCpu[6];
280
281 mRelUserTime = (int)(usertime - mBaseUserTime);
282 mRelSystemTime = (int)(systemtime - mBaseSystemTime);
283 mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
284 mRelIrqTime = (int)(irqtime - mBaseIrqTime);
285 mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
286 mRelIdleTime = (int)(idletime - mBaseIdleTime);
287
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700288 if (DEBUG) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800289 Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 + " S:" + sysCpu[2] + " I:" + sysCpu[3]
291 + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
292 + " O:" + sysCpu[6]);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800293 Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
295 }
296
297 mBaseUserTime = usertime;
298 mBaseSystemTime = systemtime;
299 mBaseIoWaitTime = iowaittime;
300 mBaseIrqTime = irqtime;
301 mBaseSoftIrqTime = softirqtime;
302 mBaseIdleTime = idletime;
303 }
304
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700305 mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
306
307 final float[] loadAverages = mLoadAverageData;
308 if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
309 null, null, loadAverages)) {
310 float load1 = loadAverages[0];
311 float load5 = loadAverages[1];
312 float load15 = loadAverages[2];
313 if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
314 mLoad1 = load1;
315 mLoad5 = load5;
316 mLoad15 = load15;
317 onLoadChanged(load1, load5, load15);
318 }
319 }
320
321 if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
322 + (SystemClock.uptimeMillis()-mCurrentSampleTime));
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 mWorkingProcsSorted = false;
325 mFirst = false;
326 }
327
328 private int[] collectStats(String statsFile, int parentPid, boolean first,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700329 int[] curPids, ArrayList<Stats> allProcs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 int[] pids = Process.getPids(statsFile, curPids);
332 int NP = (pids == null) ? 0 : pids.length;
333 int NS = allProcs.size();
334 int curStatsIndex = 0;
335 for (int i=0; i<NP; i++) {
336 int pid = pids[i];
337 if (pid < 0) {
338 NP = pid;
339 break;
340 }
341 Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
342
343 if (st != null && st.pid == pid) {
344 // Update an existing process...
345 st.added = false;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700346 st.working = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 curStatsIndex++;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700348 if (DEBUG) Slog.v(TAG, "Existing "
349 + (parentPid < 0 ? "process" : "thread")
350 + " pid " + pid + ": " + st);
351
352 final long uptime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
354 final long[] procStats = mProcessStatsData;
355 if (!Process.readProcFile(st.statFile.toString(),
356 PROCESS_STATS_FORMAT, null, procStats, null)) {
357 continue;
358 }
359
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700360 final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
361 final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
362 final long utime = procStats[PROCESS_STAT_UTIME];
363 final long stime = procStats[PROCESS_STAT_STIME];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364
365 if (utime == st.base_utime && stime == st.base_stime) {
366 st.rel_utime = 0;
367 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700368 st.rel_minfaults = 0;
369 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 if (st.active) {
371 st.active = false;
372 }
373 continue;
374 }
375
376 if (!st.active) {
377 st.active = true;
378 }
379
380 if (parentPid < 0) {
381 getName(st, st.cmdlineFile);
382 if (st.threadStats != null) {
383 mCurThreadPids = collectStats(st.threadsDir, pid, false,
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700384 mCurThreadPids, st.threadStats);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 }
386 }
387
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700388 if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
389 + " utime=" + utime + "-" + st.base_utime
390 + " stime=" + stime + "-" + st.base_stime
391 + " minfaults=" + minfaults + "-" + st.base_minfaults
392 + " majfaults=" + majfaults + "-" + st.base_majfaults);
393
394 st.rel_uptime = uptime - st.base_uptime;
395 st.base_uptime = uptime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 st.rel_utime = (int)(utime - st.base_utime);
397 st.rel_stime = (int)(stime - st.base_stime);
398 st.base_utime = utime;
399 st.base_stime = stime;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700400 st.rel_minfaults = (int)(minfaults - st.base_minfaults);
401 st.rel_majfaults = (int)(majfaults - st.base_majfaults);
402 st.base_minfaults = minfaults;
403 st.base_majfaults = majfaults;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700404 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 continue;
406 }
407
408 if (st == null || st.pid > pid) {
409 // We have a new process!
410 st = new Stats(pid, parentPid, mIncludeThreads);
411 allProcs.add(curStatsIndex, st);
412 curStatsIndex++;
413 NS++;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700414 if (DEBUG) Slog.v(TAG, "New "
415 + (parentPid < 0 ? "process" : "thread")
416 + " pid " + pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417
418 final String[] procStatsString = mProcessFullStatsStringData;
419 final long[] procStats = mProcessFullStatsData;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700420 st.base_uptime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 if (Process.readProcFile(st.statFile.toString(),
422 PROCESS_FULL_STATS_FORMAT, procStatsString,
423 procStats, null)) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700424 st.baseName = procStatsString[0];
425 st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS];
426 st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS];
427 st.base_utime = procStats[PROCESS_FULL_STAT_UTIME];
428 st.base_stime = procStats[PROCESS_FULL_STAT_STIME];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 } else {
430 st.baseName = "<unknown>";
431 st.base_utime = st.base_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700432 st.base_minfaults = st.base_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 }
434
435 if (parentPid < 0) {
436 getName(st, st.cmdlineFile);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700437 if (st.threadStats != null) {
438 mCurThreadPids = collectStats(st.threadsDir, pid, true,
439 mCurThreadPids, st.threadStats);
440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 } else {
442 st.name = st.baseName;
443 st.nameWidth = onMeasureProcessName(st.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700445
446 if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid
447 + " utime=" + st.base_utime + " stime=" + st.base_stime
448 + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 st.rel_utime = 0;
451 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700452 st.rel_minfaults = 0;
453 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 st.added = true;
455 if (!first) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700456 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 }
458 continue;
459 }
460
461 // This process has gone away!
462 st.rel_utime = 0;
463 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700464 st.rel_minfaults = 0;
465 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 st.removed = true;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700467 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 allProcs.remove(curStatsIndex);
469 NS--;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700470 if (DEBUG) Slog.v(TAG, "Removed "
471 + (parentPid < 0 ? "process" : "thread")
472 + " pid " + pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 // Decrement the loop counter so that we process the current pid
474 // again the next time through the loop.
475 i--;
476 continue;
477 }
478
479 while (curStatsIndex < NS) {
480 // This process has gone away!
481 final Stats st = allProcs.get(curStatsIndex);
482 st.rel_utime = 0;
483 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700484 st.rel_minfaults = 0;
485 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 st.removed = true;
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700487 st.working = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488 allProcs.remove(curStatsIndex);
489 NS--;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800490 if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 }
492
493 return pids;
494 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700495
496 public long getCpuTimeForPid(int pid) {
497 final String statFile = "/proc/" + pid + "/stat";
498 final long[] statsData = mSinglePidStatsData;
499 if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
500 null, statsData, null)) {
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700501 long time = statsData[PROCESS_STAT_UTIME]
502 + statsData[PROCESS_STAT_STIME];
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700503 return time;
504 }
505 return 0;
506 }
507
Amith Yamasanie43530a2009-08-21 13:11:37 -0700508 /**
509 * Returns the times spent at each CPU speed, since the last call to this method. If this
510 * is the first time, it will return 1 for each value.
511 * @return relative times spent at different speed steps.
512 */
513 public long[] getLastCpuSpeedTimes() {
514 if (mCpuSpeedTimes == null) {
515 mCpuSpeedTimes = getCpuSpeedTimes(null);
516 mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
517 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
518 mRelCpuSpeedTimes[i] = 1; // Initialize
519 }
520 } else {
521 getCpuSpeedTimes(mRelCpuSpeedTimes);
522 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
523 long temp = mRelCpuSpeedTimes[i];
524 mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
525 mCpuSpeedTimes[i] = temp;
526 }
527 }
528 return mRelCpuSpeedTimes;
529 }
530
531 private long[] getCpuSpeedTimes(long[] out) {
532 long[] tempTimes = out;
533 long[] tempSpeeds = mCpuSpeeds;
534 final int MAX_SPEEDS = 20;
535 if (out == null) {
536 tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
537 tempSpeeds = new long[MAX_SPEEDS];
538 }
539 int speed = 0;
540 String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400541 // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
542 if (file != null) {
543 StringTokenizer st = new StringTokenizer(file, "\n ");
544 while (st.hasMoreElements()) {
545 String token = st.nextToken();
546 try {
547 long val = Long.parseLong(token);
548 tempSpeeds[speed] = val;
549 token = st.nextToken();
550 val = Long.parseLong(token);
551 tempTimes[speed] = val;
552 speed++;
553 if (speed == MAX_SPEEDS) break; // No more
554 if (localLOGV && out == null) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800555 Slog.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400556 + "\t" + tempTimes[speed - 1]);
557 }
558 } catch (NumberFormatException nfe) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800559 Slog.i(TAG, "Unable to parse time_in_state");
Amith Yamasanie43530a2009-08-21 13:11:37 -0700560 }
Amith Yamasanie43530a2009-08-21 13:11:37 -0700561 }
562 }
563 if (out == null) {
564 out = new long[speed];
565 mCpuSpeeds = new long[speed];
566 System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
567 System.arraycopy(tempTimes, 0, out, 0, speed);
568 }
569 return out;
570 }
571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 final public int getLastUserTime() {
573 return mRelUserTime;
574 }
575
576 final public int getLastSystemTime() {
577 return mRelSystemTime;
578 }
579
580 final public int getLastIoWaitTime() {
581 return mRelIoWaitTime;
582 }
583
584 final public int getLastIrqTime() {
585 return mRelIrqTime;
586 }
587
588 final public int getLastSoftIrqTime() {
589 return mRelSoftIrqTime;
590 }
591
592 final public int getLastIdleTime() {
593 return mRelIdleTime;
594 }
595
596 final public float getTotalCpuPercent() {
597 return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100)
598 / (mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime);
599 }
600
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700601 final void buildWorkingProcs() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 if (!mWorkingProcsSorted) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700603 mWorkingProcs.clear();
604 final int N = mProcStats.size();
605 for (int i=0; i<N; i++) {
606 Stats stats = mProcStats.get(i);
607 if (stats.working) {
608 mWorkingProcs.add(stats);
609 if (stats.threadStats != null && stats.threadStats.size() > 1) {
610 stats.workingThreads.clear();
611 final int M = stats.threadStats.size();
612 for (int j=0; j<M; j++) {
613 Stats tstats = stats.threadStats.get(j);
614 if (tstats.working) {
615 stats.workingThreads.add(tstats);
616 }
617 }
618 Collections.sort(stats.workingThreads, sLoadComparator);
619 }
620 }
621 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 Collections.sort(mWorkingProcs, sLoadComparator);
623 mWorkingProcsSorted = true;
624 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700625 }
626
627 final public int countWorkingStats() {
628 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 return mWorkingProcs.size();
630 }
631
632 final public Stats getWorkingStats(int index) {
633 return mWorkingProcs.get(index);
634 }
635
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700636 final public String printCurrentLoad() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 StringWriter sw = new StringWriter();
638 PrintWriter pw = new PrintWriter(sw);
639 pw.print("Load: ");
640 pw.print(mLoad1);
641 pw.print(" / ");
642 pw.print(mLoad5);
643 pw.print(" / ");
644 pw.println(mLoad15);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700645 return sw.toString();
646 }
647
648 final public String printCurrentState(long now) {
649 buildWorkingProcs();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700651 StringWriter sw = new StringWriter();
652 PrintWriter pw = new PrintWriter(sw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653
654 pw.print("CPU usage from ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700655 if (now > mLastSampleTime) {
656 pw.print(now-mLastSampleTime);
657 pw.print("ms to ");
658 pw.print(now-mCurrentSampleTime);
659 pw.print("ms ago");
660 } else {
661 pw.print(mLastSampleTime-now);
662 pw.print("ms to ");
663 pw.print(mCurrentSampleTime-now);
664 pw.print("ms later");
665 }
666
667 long sampleTime = mCurrentSampleTime - mLastSampleTime;
668 long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime;
669 long percAwake = (sampleTime*100) / sampleRealTime;
670 if (percAwake != 100) {
671 pw.print(" with ");
672 pw.print(percAwake);
673 pw.print("% awake");
674 }
675 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700677 final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
678 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700680 if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time "
681 + (mCurrentSampleTime-mLastSampleTime));
682
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 int N = mWorkingProcs.size();
684 for (int i=0; i<N; i++) {
685 Stats st = mWorkingProcs.get(i);
686 printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700687 st.pid, st.name, (int)(st.rel_uptime+5)/10,
688 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 -0800689 if (!st.removed && st.workingThreads != null) {
690 int M = st.workingThreads.size();
691 for (int j=0; j<M; j++) {
692 Stats tst = st.workingThreads.get(j);
693 printProcessCPU(pw,
694 tst.added ? " +" : (tst.removed ? " -": " "),
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700695 tst.pid, tst.name, (int)(st.rel_uptime+5)/10,
696 tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 }
698 }
699 }
700
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700701 printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700702 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703
704 return sw.toString();
705 }
706
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700707 private void printRatio(PrintWriter pw, long numerator, long denominator) {
708 long thousands = (numerator*1000)/denominator;
709 long hundreds = thousands/10;
710 pw.print(hundreds);
711 if (hundreds < 10) {
712 long remainder = thousands - (hundreds*10);
713 if (remainder != 0) {
714 pw.print('.');
715 pw.print(remainder);
716 }
717 }
718 }
719
720 private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label,
721 int totalTime, int user, int system, int iowait, int irq, int softIrq,
722 int minFaults, int majFaults) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 pw.print(prefix);
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700724 if (totalTime == 0) totalTime = 1;
725 printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
726 pw.print("% ");
727 if (pid >= 0) {
728 pw.print(pid);
729 pw.print("/");
730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 pw.print(label);
732 pw.print(": ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700733 printRatio(pw, user, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 pw.print("% user + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700735 printRatio(pw, system, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 pw.print("% kernel");
737 if (iowait > 0) {
738 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700739 printRatio(pw, iowait, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 pw.print("% iowait");
741 }
742 if (irq > 0) {
743 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700744 printRatio(pw, irq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 pw.print("% irq");
746 }
747 if (softIrq > 0) {
748 pw.print(" + ");
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700749 printRatio(pw, softIrq, totalTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 pw.print("% softirq");
751 }
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700752 if (minFaults > 0 || majFaults > 0) {
753 pw.print(" / faults:");
754 if (minFaults > 0) {
755 pw.print(" ");
756 pw.print(minFaults);
757 pw.print(" minor");
758 }
759 if (majFaults > 0) {
760 pw.print(" ");
761 pw.print(majFaults);
762 pw.print(" major");
763 }
764 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 pw.println();
766 }
767
768 private String readFile(String file, char endChar) {
769 try {
770 FileInputStream is = new FileInputStream(file);
771 int len = is.read(mBuffer);
772 is.close();
773
774 if (len > 0) {
775 int i;
776 for (i=0; i<len; i++) {
777 if (mBuffer[i] == endChar) {
778 break;
779 }
780 }
781 return new String(mBuffer, 0, 0, i);
782 }
783 } catch (java.io.FileNotFoundException e) {
784 } catch (java.io.IOException e) {
785 }
786 return null;
787 }
788
789 private void getName(Stats st, String cmdlineFile) {
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700790 String newName = st.name;
791 if (st.name == null || st.name.equals("app_process")) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 String cmdName = readFile(cmdlineFile, '\0');
793 if (cmdName != null && cmdName.length() > 1) {
794 newName = cmdName;
795 int i = newName.lastIndexOf("/");
796 if (i > 0 && i < newName.length()-1) {
797 newName = newName.substring(i+1);
798 }
799 }
Dianne Hackborn6b1afeb2010-08-31 15:40:21 -0700800 if (newName == null) {
801 newName = st.baseName;
802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
804 if (st.name == null || !newName.equals(st.name)) {
805 st.name = newName;
806 st.nameWidth = onMeasureProcessName(st.name);
807 }
808 }
809}
810