blob: ac3b723544763f43ced1d2211bf9e6aace6e7eb5 [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;
24import android.util.Log;
25
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,
42 PROC_SPACE_TERM,
43 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,
78 PROC_SPACE_TERM,
79 PROC_SPACE_TERM,
80 PROC_SPACE_TERM,
81 PROC_SPACE_TERM,
82 PROC_SPACE_TERM|PROC_OUT_LONG, // 13: utime
83 PROC_SPACE_TERM|PROC_OUT_LONG // 14: stime
84 };
85
86 private final String[] mProcessFullStatsStringData = new String[3];
87 private final long[] mProcessFullStatsData = new long[3];
88
89 private static final int[] SYSTEM_CPU_FORMAT = new int[] {
90 PROC_SPACE_TERM|PROC_COMBINE,
91 PROC_SPACE_TERM|PROC_OUT_LONG, // 1: user time
92 PROC_SPACE_TERM|PROC_OUT_LONG, // 2: nice time
93 PROC_SPACE_TERM|PROC_OUT_LONG, // 3: sys time
94 PROC_SPACE_TERM|PROC_OUT_LONG, // 4: idle time
95 PROC_SPACE_TERM|PROC_OUT_LONG, // 5: iowait time
96 PROC_SPACE_TERM|PROC_OUT_LONG, // 6: irq time
97 PROC_SPACE_TERM|PROC_OUT_LONG // 7: softirq time
98 };
99
100 private final long[] mSystemCpuData = new long[7];
101
102 private static final int[] LOAD_AVERAGE_FORMAT = new int[] {
103 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 0: 1 min
104 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 1: 5 mins
105 PROC_SPACE_TERM|PROC_OUT_FLOAT // 2: 15 mins
106 };
107
108 private final float[] mLoadAverageData = new float[3];
109
110 private final boolean mIncludeThreads;
111
112 private float mLoad1 = 0;
113 private float mLoad5 = 0;
114 private float mLoad15 = 0;
115
116 private long mCurrentSampleTime;
117 private long mLastSampleTime;
118
119 private long mBaseUserTime;
120 private long mBaseSystemTime;
121 private long mBaseIoWaitTime;
122 private long mBaseIrqTime;
123 private long mBaseSoftIrqTime;
124 private long mBaseIdleTime;
125 private int mRelUserTime;
126 private int mRelSystemTime;
127 private int mRelIoWaitTime;
128 private int mRelIrqTime;
129 private int mRelSoftIrqTime;
130 private int mRelIdleTime;
131
132 private int[] mCurPids;
133 private int[] mCurThreadPids;
134
135 private final ArrayList<Stats> mProcStats = new ArrayList<Stats>();
136 private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>();
137 private boolean mWorkingProcsSorted;
138
139 private boolean mFirst = true;
140
141 private byte[] mBuffer = new byte[256];
Amith Yamasanie43530a2009-08-21 13:11:37 -0700142
143 /**
144 * The time in microseconds that the CPU has been running at each speed.
145 */
146 private long[] mCpuSpeedTimes;
147
148 /**
149 * The relative time in microseconds that the CPU has been running at each speed.
150 */
151 private long[] mRelCpuSpeedTimes;
152
153 /**
154 * The different speeds that the CPU can be running at.
155 */
156 private long[] mCpuSpeeds;
157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 public static class Stats {
159 public final int pid;
160 final String statFile;
161 final String cmdlineFile;
162 final String threadsDir;
163 final ArrayList<Stats> threadStats;
164 final ArrayList<Stats> workingThreads;
165
166 public String baseName;
167 public String name;
168 int nameWidth;
169
170 public long base_utime;
171 public long base_stime;
172 public int rel_utime;
173 public int rel_stime;
174
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700175 public long base_minfaults;
176 public long base_majfaults;
177 public int rel_minfaults;
178 public int rel_majfaults;
179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 public boolean active;
181 public boolean added;
182 public boolean removed;
183
184 Stats(int _pid, int parentPid, boolean includeThreads) {
185 pid = _pid;
186 if (parentPid < 0) {
187 final File procDir = new File("/proc", Integer.toString(pid));
188 statFile = new File(procDir, "stat").toString();
189 cmdlineFile = new File(procDir, "cmdline").toString();
190 threadsDir = (new File(procDir, "task")).toString();
191 if (includeThreads) {
192 threadStats = new ArrayList<Stats>();
193 workingThreads = new ArrayList<Stats>();
194 } else {
195 threadStats = null;
196 workingThreads = null;
197 }
198 } else {
199 final File procDir = new File("/proc", Integer.toString(
200 parentPid));
201 final File taskDir = new File(
202 new File(procDir, "task"), Integer.toString(pid));
203 statFile = new File(taskDir, "stat").toString();
204 cmdlineFile = null;
205 threadsDir = null;
206 threadStats = null;
207 workingThreads = null;
208 }
209 }
210 }
211
212 private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() {
213 public final int
214 compare(Stats sta, Stats stb)
215 {
216 int ta = sta.rel_utime + sta.rel_stime;
217 int tb = stb.rel_utime + stb.rel_stime;
218 if (ta != tb) {
219 return ta > tb ? -1 : 1;
220 }
221 if (sta.added != stb.added) {
222 return sta.added ? -1 : 1;
223 }
224 if (sta.removed != stb.removed) {
225 return sta.added ? -1 : 1;
226 }
227 return 0;
228 }
229 };
230
231
232 public ProcessStats(boolean includeThreads) {
233 mIncludeThreads = includeThreads;
234 }
235
236 public void onLoadChanged(float load1, float load5, float load15) {
237 }
238
239 public int onMeasureProcessName(String name) {
240 return 0;
241 }
242
243 public void init() {
244 mFirst = true;
245 update();
246 }
247
248 public void update() {
249 mLastSampleTime = mCurrentSampleTime;
250 mCurrentSampleTime = SystemClock.uptimeMillis();
251
252 final float[] loadAverages = mLoadAverageData;
253 if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
254 null, null, loadAverages)) {
255 float load1 = loadAverages[0];
256 float load5 = loadAverages[1];
257 float load15 = loadAverages[2];
258 if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
259 mLoad1 = load1;
260 mLoad5 = load5;
261 mLoad15 = load15;
262 onLoadChanged(load1, load5, load15);
263 }
264 }
265
266 mCurPids = collectStats("/proc", -1, mFirst, mCurPids,
267 mProcStats, mWorkingProcs);
268 mFirst = false;
269
270 final long[] sysCpu = mSystemCpuData;
271 if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
272 null, sysCpu, null)) {
273 // Total user time is user + nice time.
274 final long usertime = sysCpu[0]+sysCpu[1];
275 // Total system time is simply system time.
276 final long systemtime = sysCpu[2];
277 // Total idle time is simply idle time.
278 final long idletime = sysCpu[3];
279 // Total irq time is iowait + irq + softirq time.
280 final long iowaittime = sysCpu[4];
281 final long irqtime = sysCpu[5];
282 final long softirqtime = sysCpu[6];
283
284 mRelUserTime = (int)(usertime - mBaseUserTime);
285 mRelSystemTime = (int)(systemtime - mBaseSystemTime);
286 mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
287 mRelIrqTime = (int)(irqtime - mBaseIrqTime);
288 mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
289 mRelIdleTime = (int)(idletime - mBaseIdleTime);
290
291 if (false) {
292 Log.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
293 + " S:" + sysCpu[2] + " I:" + sysCpu[3]
294 + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
295 + " O:" + sysCpu[6]);
296 Log.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
297 + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
298 }
299
300 mBaseUserTime = usertime;
301 mBaseSystemTime = systemtime;
302 mBaseIoWaitTime = iowaittime;
303 mBaseIrqTime = irqtime;
304 mBaseSoftIrqTime = softirqtime;
305 mBaseIdleTime = idletime;
306 }
307
308 mWorkingProcsSorted = false;
309 mFirst = false;
310 }
311
312 private int[] collectStats(String statsFile, int parentPid, boolean first,
313 int[] curPids, ArrayList<Stats> allProcs,
314 ArrayList<Stats> workingProcs) {
315
316 workingProcs.clear();
317
318 int[] pids = Process.getPids(statsFile, curPids);
319 int NP = (pids == null) ? 0 : pids.length;
320 int NS = allProcs.size();
321 int curStatsIndex = 0;
322 for (int i=0; i<NP; i++) {
323 int pid = pids[i];
324 if (pid < 0) {
325 NP = pid;
326 break;
327 }
328 Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
329
330 if (st != null && st.pid == pid) {
331 // Update an existing process...
332 st.added = false;
333 curStatsIndex++;
334 if (localLOGV) Log.v(TAG, "Existing pid " + pid + ": " + st);
335
336 final long[] procStats = mProcessStatsData;
337 if (!Process.readProcFile(st.statFile.toString(),
338 PROCESS_STATS_FORMAT, null, procStats, null)) {
339 continue;
340 }
341
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700342 final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
343 final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
344 final long utime = procStats[PROCESS_STAT_UTIME];
345 final long stime = procStats[PROCESS_STAT_STIME];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346
347 if (utime == st.base_utime && stime == st.base_stime) {
348 st.rel_utime = 0;
349 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700350 st.rel_minfaults = 0;
351 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 if (st.active) {
353 st.active = false;
354 }
355 continue;
356 }
357
358 if (!st.active) {
359 st.active = true;
360 }
361
362 if (parentPid < 0) {
363 getName(st, st.cmdlineFile);
364 if (st.threadStats != null) {
365 mCurThreadPids = collectStats(st.threadsDir, pid, false,
366 mCurThreadPids, st.threadStats,
367 st.workingThreads);
368 }
369 }
370
371 st.rel_utime = (int)(utime - st.base_utime);
372 st.rel_stime = (int)(stime - st.base_stime);
373 st.base_utime = utime;
374 st.base_stime = stime;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700375 st.rel_minfaults = (int)(minfaults - st.base_minfaults);
376 st.rel_majfaults = (int)(majfaults - st.base_majfaults);
377 st.base_minfaults = minfaults;
378 st.base_majfaults = majfaults;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 //Log.i("Load", "Stats changed " + name + " pid=" + st.pid
380 // + " name=" + st.name + " utime=" + utime
381 // + " stime=" + stime);
382 workingProcs.add(st);
383 continue;
384 }
385
386 if (st == null || st.pid > pid) {
387 // We have a new process!
388 st = new Stats(pid, parentPid, mIncludeThreads);
389 allProcs.add(curStatsIndex, st);
390 curStatsIndex++;
391 NS++;
392 if (localLOGV) Log.v(TAG, "New pid " + pid + ": " + st);
393
394 final String[] procStatsString = mProcessFullStatsStringData;
395 final long[] procStats = mProcessFullStatsData;
396 if (Process.readProcFile(st.statFile.toString(),
397 PROCESS_FULL_STATS_FORMAT, procStatsString,
398 procStats, null)) {
399 st.baseName = parentPid < 0
400 ? procStatsString[0] : Integer.toString(pid);
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700401 st.base_utime = 0; //procStats[1];
402 st.base_stime = 0; //procStats[2];
403 st.base_minfaults = st.base_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 } else {
405 st.baseName = "<unknown>";
406 st.base_utime = st.base_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700407 st.base_minfaults = st.base_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 }
409
410 if (parentPid < 0) {
411 getName(st, st.cmdlineFile);
412 } else {
413 st.name = st.baseName;
414 st.nameWidth = onMeasureProcessName(st.name);
415 if (st.threadStats != null) {
416 mCurThreadPids = collectStats(st.threadsDir, pid, true,
417 mCurThreadPids, st.threadStats,
418 st.workingThreads);
419 }
420 }
421
422 //Log.i("Load", "New process: " + st.pid + " " + st.name);
423 st.rel_utime = 0;
424 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700425 st.rel_minfaults = 0;
426 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 st.added = true;
428 if (!first) {
429 workingProcs.add(st);
430 }
431 continue;
432 }
433
434 // This process has gone away!
435 st.rel_utime = 0;
436 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700437 st.rel_minfaults = 0;
438 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 st.removed = true;
440 workingProcs.add(st);
441 allProcs.remove(curStatsIndex);
442 NS--;
443 if (localLOGV) Log.v(TAG, "Removed pid " + st.pid + ": " + st);
444 // Decrement the loop counter so that we process the current pid
445 // again the next time through the loop.
446 i--;
447 continue;
448 }
449
450 while (curStatsIndex < NS) {
451 // This process has gone away!
452 final Stats st = allProcs.get(curStatsIndex);
453 st.rel_utime = 0;
454 st.rel_stime = 0;
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700455 st.rel_minfaults = 0;
456 st.rel_majfaults = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 st.removed = true;
458 workingProcs.add(st);
459 allProcs.remove(curStatsIndex);
460 NS--;
461 if (localLOGV) Log.v(TAG, "Removed pid " + st.pid + ": " + st);
462 }
463
464 return pids;
465 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700466
467 public long getCpuTimeForPid(int pid) {
468 final String statFile = "/proc/" + pid + "/stat";
469 final long[] statsData = mSinglePidStatsData;
470 if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
471 null, statsData, null)) {
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700472 long time = statsData[PROCESS_STAT_UTIME]
473 + statsData[PROCESS_STAT_STIME];
Amith Yamasanieaeb6632009-06-03 15:16:10 -0700474 return time;
475 }
476 return 0;
477 }
478
Amith Yamasanie43530a2009-08-21 13:11:37 -0700479 /**
480 * Returns the times spent at each CPU speed, since the last call to this method. If this
481 * is the first time, it will return 1 for each value.
482 * @return relative times spent at different speed steps.
483 */
484 public long[] getLastCpuSpeedTimes() {
485 if (mCpuSpeedTimes == null) {
486 mCpuSpeedTimes = getCpuSpeedTimes(null);
487 mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
488 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
489 mRelCpuSpeedTimes[i] = 1; // Initialize
490 }
491 } else {
492 getCpuSpeedTimes(mRelCpuSpeedTimes);
493 for (int i = 0; i < mCpuSpeedTimes.length; i++) {
494 long temp = mRelCpuSpeedTimes[i];
495 mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
496 mCpuSpeedTimes[i] = temp;
497 }
498 }
499 return mRelCpuSpeedTimes;
500 }
501
502 private long[] getCpuSpeedTimes(long[] out) {
503 long[] tempTimes = out;
504 long[] tempSpeeds = mCpuSpeeds;
505 final int MAX_SPEEDS = 20;
506 if (out == null) {
507 tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
508 tempSpeeds = new long[MAX_SPEEDS];
509 }
510 int speed = 0;
511 String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
Brad Fitzpatrick2eb239f2009-09-21 15:30:21 +0400512 // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
513 if (file != null) {
514 StringTokenizer st = new StringTokenizer(file, "\n ");
515 while (st.hasMoreElements()) {
516 String token = st.nextToken();
517 try {
518 long val = Long.parseLong(token);
519 tempSpeeds[speed] = val;
520 token = st.nextToken();
521 val = Long.parseLong(token);
522 tempTimes[speed] = val;
523 speed++;
524 if (speed == MAX_SPEEDS) break; // No more
525 if (localLOGV && out == null) {
526 Log.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
527 + "\t" + tempTimes[speed - 1]);
528 }
529 } catch (NumberFormatException nfe) {
530 Log.i(TAG, "Unable to parse time_in_state");
Amith Yamasanie43530a2009-08-21 13:11:37 -0700531 }
Amith Yamasanie43530a2009-08-21 13:11:37 -0700532 }
533 }
534 if (out == null) {
535 out = new long[speed];
536 mCpuSpeeds = new long[speed];
537 System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
538 System.arraycopy(tempTimes, 0, out, 0, speed);
539 }
540 return out;
541 }
542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 final public int getLastUserTime() {
544 return mRelUserTime;
545 }
546
547 final public int getLastSystemTime() {
548 return mRelSystemTime;
549 }
550
551 final public int getLastIoWaitTime() {
552 return mRelIoWaitTime;
553 }
554
555 final public int getLastIrqTime() {
556 return mRelIrqTime;
557 }
558
559 final public int getLastSoftIrqTime() {
560 return mRelSoftIrqTime;
561 }
562
563 final public int getLastIdleTime() {
564 return mRelIdleTime;
565 }
566
567 final public float getTotalCpuPercent() {
568 return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100)
569 / (mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime);
570 }
571
572 final public int countWorkingStats() {
573 if (!mWorkingProcsSorted) {
574 Collections.sort(mWorkingProcs, sLoadComparator);
575 mWorkingProcsSorted = true;
576 }
577 return mWorkingProcs.size();
578 }
579
580 final public Stats getWorkingStats(int index) {
581 return mWorkingProcs.get(index);
582 }
583
584 final public String printCurrentState() {
585 if (!mWorkingProcsSorted) {
586 Collections.sort(mWorkingProcs, sLoadComparator);
587 mWorkingProcsSorted = true;
588 }
589
590 StringWriter sw = new StringWriter();
591 PrintWriter pw = new PrintWriter(sw);
592 pw.print("Load: ");
593 pw.print(mLoad1);
594 pw.print(" / ");
595 pw.print(mLoad5);
596 pw.print(" / ");
597 pw.println(mLoad15);
598
599 long now = SystemClock.uptimeMillis();
600
601 pw.print("CPU usage from ");
602 pw.print(now-mLastSampleTime);
603 pw.print("ms to ");
604 pw.print(now-mCurrentSampleTime);
605 pw.println("ms ago:");
606
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700607 final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
608 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609
610 int N = mWorkingProcs.size();
611 for (int i=0; i<N; i++) {
612 Stats st = mWorkingProcs.get(i);
613 printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "),
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700614 st.name, totalTime, st.rel_utime, st.rel_stime, 0, 0, 0,
615 st.rel_minfaults, st.rel_majfaults);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 if (!st.removed && st.workingThreads != null) {
617 int M = st.workingThreads.size();
618 for (int j=0; j<M; j++) {
619 Stats tst = st.workingThreads.get(j);
620 printProcessCPU(pw,
621 tst.added ? " +" : (tst.removed ? " -": " "),
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700622 tst.name, totalTime, tst.rel_utime, tst.rel_stime,
623 0, 0, 0, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 }
625 }
626 }
627
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700628 printProcessCPU(pw, "", "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
629 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630
631 return sw.toString();
632 }
633
634 private void printProcessCPU(PrintWriter pw, String prefix, String label, int totalTime,
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700635 int user, int system, int iowait, int irq, int softIrq, int minFaults, int majFaults) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 pw.print(prefix);
637 pw.print(label);
638 pw.print(": ");
639 if (totalTime == 0) totalTime = 1;
640 pw.print(((user+system+iowait+irq+softIrq)*100)/totalTime);
641 pw.print("% = ");
642 pw.print((user*100)/totalTime);
643 pw.print("% user + ");
644 pw.print((system*100)/totalTime);
645 pw.print("% kernel");
646 if (iowait > 0) {
647 pw.print(" + ");
648 pw.print((iowait*100)/totalTime);
649 pw.print("% iowait");
650 }
651 if (irq > 0) {
652 pw.print(" + ");
653 pw.print((irq*100)/totalTime);
654 pw.print("% irq");
655 }
656 if (softIrq > 0) {
657 pw.print(" + ");
658 pw.print((softIrq*100)/totalTime);
659 pw.print("% softirq");
660 }
Dianne Hackborn151ceb92009-08-06 12:40:56 -0700661 if (minFaults > 0 || majFaults > 0) {
662 pw.print(" / faults:");
663 if (minFaults > 0) {
664 pw.print(" ");
665 pw.print(minFaults);
666 pw.print(" minor");
667 }
668 if (majFaults > 0) {
669 pw.print(" ");
670 pw.print(majFaults);
671 pw.print(" major");
672 }
673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 pw.println();
675 }
676
677 private String readFile(String file, char endChar) {
678 try {
679 FileInputStream is = new FileInputStream(file);
680 int len = is.read(mBuffer);
681 is.close();
682
683 if (len > 0) {
684 int i;
685 for (i=0; i<len; i++) {
686 if (mBuffer[i] == endChar) {
687 break;
688 }
689 }
690 return new String(mBuffer, 0, 0, i);
691 }
692 } catch (java.io.FileNotFoundException e) {
693 } catch (java.io.IOException e) {
694 }
695 return null;
696 }
697
698 private void getName(Stats st, String cmdlineFile) {
699 String newName = st.baseName;
700 if (st.baseName == null || st.baseName.equals("app_process")) {
701 String cmdName = readFile(cmdlineFile, '\0');
702 if (cmdName != null && cmdName.length() > 1) {
703 newName = cmdName;
704 int i = newName.lastIndexOf("/");
705 if (i > 0 && i < newName.length()-1) {
706 newName = newName.substring(i+1);
707 }
708 }
709 }
710 if (st.name == null || !newName.equals(st.name)) {
711 st.name = newName;
712 st.nameWidth = onMeasureProcessName(st.name);
713 }
714 }
715}
716