1 /* 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 17 package com.android.internal.os; 18 19 import static android.os.Process.*; 20 21 import android.os.FileUtils; 22 import android.os.Process; 23 import android.os.StrictMode; 24 import android.os.SystemClock; 25 import android.system.OsConstants; 26 import android.util.Slog; 27 28 import com.android.internal.util.FastPrintWriter; 29 30 import libcore.io.IoUtils; 31 import libcore.io.Libcore; 32 33 import java.io.File; 34 import java.io.FileInputStream; 35 import java.io.PrintWriter; 36 import java.io.StringWriter; 37 import java.util.ArrayList; 38 import java.util.Collections; 39 import java.util.Comparator; 40 import java.util.StringTokenizer; 41 42 public class ProcessCpuTracker { 43 private static final String TAG = "ProcessCpuTracker"; 44 private static final boolean DEBUG = false; 45 private static final boolean localLOGV = DEBUG || false; 46 47 private static final int[] PROCESS_STATS_FORMAT = new int[] { 48 PROC_SPACE_TERM, 49 PROC_SPACE_TERM|PROC_PARENS, 50 PROC_SPACE_TERM, 51 PROC_SPACE_TERM, 52 PROC_SPACE_TERM, 53 PROC_SPACE_TERM, 54 PROC_SPACE_TERM, 55 PROC_SPACE_TERM, 56 PROC_SPACE_TERM, 57 PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults 58 PROC_SPACE_TERM, 59 PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults 60 PROC_SPACE_TERM, 61 PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime 62 PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime 63 }; 64 65 static final int PROCESS_STAT_MINOR_FAULTS = 0; 66 static final int PROCESS_STAT_MAJOR_FAULTS = 1; 67 static final int PROCESS_STAT_UTIME = 2; 68 static final int PROCESS_STAT_STIME = 3; 69 70 /** Stores user time and system time in 100ths of a second. */ 71 private final long[] mProcessStatsData = new long[4]; 72 73 /** Stores user time and system time in 100ths of a second. Used for 74 * public API to retrieve CPU use for a process. Must lock while in use. */ 75 private final long[] mSinglePidStatsData = new long[4]; 76 77 private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] { 78 PROC_SPACE_TERM, 79 PROC_SPACE_TERM|PROC_PARENS|PROC_OUT_STRING, // 2: name 80 PROC_SPACE_TERM, 81 PROC_SPACE_TERM, 82 PROC_SPACE_TERM, 83 PROC_SPACE_TERM, 84 PROC_SPACE_TERM, 85 PROC_SPACE_TERM, 86 PROC_SPACE_TERM, 87 PROC_SPACE_TERM|PROC_OUT_LONG, // 10: minor faults 88 PROC_SPACE_TERM, 89 PROC_SPACE_TERM|PROC_OUT_LONG, // 12: major faults 90 PROC_SPACE_TERM, 91 PROC_SPACE_TERM|PROC_OUT_LONG, // 14: utime 92 PROC_SPACE_TERM|PROC_OUT_LONG, // 15: stime 93 PROC_SPACE_TERM, 94 PROC_SPACE_TERM, 95 PROC_SPACE_TERM, 96 PROC_SPACE_TERM, 97 PROC_SPACE_TERM, 98 PROC_SPACE_TERM, 99 PROC_SPACE_TERM, 100 PROC_SPACE_TERM|PROC_OUT_LONG, // 23: vsize 101 }; 102 103 static final int PROCESS_FULL_STAT_MINOR_FAULTS = 1; 104 static final int PROCESS_FULL_STAT_MAJOR_FAULTS = 2; 105 static final int PROCESS_FULL_STAT_UTIME = 3; 106 static final int PROCESS_FULL_STAT_STIME = 4; 107 static final int PROCESS_FULL_STAT_VSIZE = 5; 108 109 private final String[] mProcessFullStatsStringData = new String[6]; 110 private final long[] mProcessFullStatsData = new long[6]; 111 112 private static final int[] SYSTEM_CPU_FORMAT = new int[] { 113 PROC_SPACE_TERM|PROC_COMBINE, 114 PROC_SPACE_TERM|PROC_OUT_LONG, // 1: user time 115 PROC_SPACE_TERM|PROC_OUT_LONG, // 2: nice time 116 PROC_SPACE_TERM|PROC_OUT_LONG, // 3: sys time 117 PROC_SPACE_TERM|PROC_OUT_LONG, // 4: idle time 118 PROC_SPACE_TERM|PROC_OUT_LONG, // 5: iowait time 119 PROC_SPACE_TERM|PROC_OUT_LONG, // 6: irq time 120 PROC_SPACE_TERM|PROC_OUT_LONG // 7: softirq time 121 }; 122 123 private final long[] mSystemCpuData = new long[7]; 124 125 private static final int[] LOAD_AVERAGE_FORMAT = new int[] { 126 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 0: 1 min 127 PROC_SPACE_TERM|PROC_OUT_FLOAT, // 1: 5 mins 128 PROC_SPACE_TERM|PROC_OUT_FLOAT // 2: 15 mins 129 }; 130 131 private final float[] mLoadAverageData = new float[3]; 132 133 private final boolean mIncludeThreads; 134 135 // How long a CPU jiffy is in milliseconds. 136 private final long mJiffyMillis; 137 138 private float mLoad1 = 0; 139 private float mLoad5 = 0; 140 private float mLoad15 = 0; 141 142 // All times are in milliseconds. They are converted from jiffies to milliseconds 143 // when extracted from the kernel. 144 private long mCurrentSampleTime; 145 private long mLastSampleTime; 146 147 private long mCurrentSampleRealTime; 148 private long mLastSampleRealTime; 149 150 private long mBaseUserTime; 151 private long mBaseSystemTime; 152 private long mBaseIoWaitTime; 153 private long mBaseIrqTime; 154 private long mBaseSoftIrqTime; 155 private long mBaseIdleTime; 156 private int mRelUserTime; 157 private int mRelSystemTime; 158 private int mRelIoWaitTime; 159 private int mRelIrqTime; 160 private int mRelSoftIrqTime; 161 private int mRelIdleTime; 162 private boolean mRelStatsAreGood; 163 164 private int[] mCurPids; 165 private int[] mCurThreadPids; 166 167 private final ArrayList<Stats> mProcStats = new ArrayList<Stats>(); 168 private final ArrayList<Stats> mWorkingProcs = new ArrayList<Stats>(); 169 private boolean mWorkingProcsSorted; 170 171 private boolean mFirst = true; 172 173 private byte[] mBuffer = new byte[4096]; 174 175 public static class Stats { 176 public final int pid; 177 public final int uid; 178 final String statFile; 179 final String cmdlineFile; 180 final String threadsDir; 181 final ArrayList<Stats> threadStats; 182 final ArrayList<Stats> workingThreads; 183 184 public BatteryStatsImpl.Uid.Proc batteryStats; 185 186 public boolean interesting; 187 188 public String baseName; 189 public String name; 190 public int nameWidth; 191 192 // vsize capture when process first detected; can be used to 193 // filter out kernel processes. 194 public long vsize; 195 196 /** 197 * Time in milliseconds. 198 */ 199 public long base_uptime; 200 201 /** 202 * Time in milliseconds. 203 */ 204 public long rel_uptime; 205 206 /** 207 * Time in milliseconds. 208 */ 209 public long base_utime; 210 211 /** 212 * Time in milliseconds. 213 */ 214 public long base_stime; 215 216 /** 217 * Time in milliseconds. 218 */ 219 public int rel_utime; 220 221 /** 222 * Time in milliseconds. 223 */ 224 public int rel_stime; 225 226 public long base_minfaults; 227 public long base_majfaults; 228 public int rel_minfaults; 229 public int rel_majfaults; 230 231 public boolean active; 232 public boolean working; 233 public boolean added; 234 public boolean removed; 235 Stats(int _pid, int parentPid, boolean includeThreads)236 Stats(int _pid, int parentPid, boolean includeThreads) { 237 pid = _pid; 238 if (parentPid < 0) { 239 final File procDir = new File("/proc", Integer.toString(pid)); 240 statFile = new File(procDir, "stat").toString(); 241 cmdlineFile = new File(procDir, "cmdline").toString(); 242 threadsDir = (new File(procDir, "task")).toString(); 243 if (includeThreads) { 244 threadStats = new ArrayList<Stats>(); 245 workingThreads = new ArrayList<Stats>(); 246 } else { 247 threadStats = null; 248 workingThreads = null; 249 } 250 } else { 251 final File procDir = new File("/proc", Integer.toString( 252 parentPid)); 253 final File taskDir = new File( 254 new File(procDir, "task"), Integer.toString(pid)); 255 statFile = new File(taskDir, "stat").toString(); 256 cmdlineFile = null; 257 threadsDir = null; 258 threadStats = null; 259 workingThreads = null; 260 } 261 uid = FileUtils.getUid(statFile.toString()); 262 } 263 } 264 265 private final static Comparator<Stats> sLoadComparator = new Comparator<Stats>() { 266 public final int 267 compare(Stats sta, Stats stb) { 268 int ta = sta.rel_utime + sta.rel_stime; 269 int tb = stb.rel_utime + stb.rel_stime; 270 if (ta != tb) { 271 return ta > tb ? -1 : 1; 272 } 273 if (sta.added != stb.added) { 274 return sta.added ? -1 : 1; 275 } 276 if (sta.removed != stb.removed) { 277 return sta.added ? -1 : 1; 278 } 279 return 0; 280 } 281 }; 282 283 ProcessCpuTracker(boolean includeThreads)284 public ProcessCpuTracker(boolean includeThreads) { 285 mIncludeThreads = includeThreads; 286 long jiffyHz = Libcore.os.sysconf(OsConstants._SC_CLK_TCK); 287 mJiffyMillis = 1000/jiffyHz; 288 } 289 onLoadChanged(float load1, float load5, float load15)290 public void onLoadChanged(float load1, float load5, float load15) { 291 } 292 onMeasureProcessName(String name)293 public int onMeasureProcessName(String name) { 294 return 0; 295 } 296 init()297 public void init() { 298 if (DEBUG) Slog.v(TAG, "Init: " + this); 299 mFirst = true; 300 update(); 301 } 302 update()303 public void update() { 304 if (DEBUG) Slog.v(TAG, "Update: " + this); 305 306 final long nowUptime = SystemClock.uptimeMillis(); 307 final long nowRealtime = SystemClock.elapsedRealtime(); 308 309 final long[] sysCpu = mSystemCpuData; 310 if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT, 311 null, sysCpu, null)) { 312 // Total user time is user + nice time. 313 final long usertime = (sysCpu[0]+sysCpu[1]) * mJiffyMillis; 314 // Total system time is simply system time. 315 final long systemtime = sysCpu[2] * mJiffyMillis; 316 // Total idle time is simply idle time. 317 final long idletime = sysCpu[3] * mJiffyMillis; 318 // Total irq time is iowait + irq + softirq time. 319 final long iowaittime = sysCpu[4] * mJiffyMillis; 320 final long irqtime = sysCpu[5] * mJiffyMillis; 321 final long softirqtime = sysCpu[6] * mJiffyMillis; 322 323 // This code is trying to avoid issues with idle time going backwards, 324 // but currently it gets into situations where it triggers most of the time. :( 325 if (true || (usertime >= mBaseUserTime && systemtime >= mBaseSystemTime 326 && iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime 327 && softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) { 328 mRelUserTime = (int)(usertime - mBaseUserTime); 329 mRelSystemTime = (int)(systemtime - mBaseSystemTime); 330 mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime); 331 mRelIrqTime = (int)(irqtime - mBaseIrqTime); 332 mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime); 333 mRelIdleTime = (int)(idletime - mBaseIdleTime); 334 mRelStatsAreGood = true; 335 336 if (DEBUG) { 337 Slog.i("Load", "Total U:" + (sysCpu[0]*mJiffyMillis) 338 + " N:" + (sysCpu[1]*mJiffyMillis) 339 + " S:" + (sysCpu[2]*mJiffyMillis) + " I:" + (sysCpu[3]*mJiffyMillis) 340 + " W:" + (sysCpu[4]*mJiffyMillis) + " Q:" + (sysCpu[5]*mJiffyMillis) 341 + " O:" + (sysCpu[6]*mJiffyMillis)); 342 Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime 343 + " I:" + mRelIdleTime + " Q:" + mRelIrqTime); 344 } 345 346 mBaseUserTime = usertime; 347 mBaseSystemTime = systemtime; 348 mBaseIoWaitTime = iowaittime; 349 mBaseIrqTime = irqtime; 350 mBaseSoftIrqTime = softirqtime; 351 mBaseIdleTime = idletime; 352 353 } else { 354 mRelUserTime = 0; 355 mRelSystemTime = 0; 356 mRelIoWaitTime = 0; 357 mRelIrqTime = 0; 358 mRelSoftIrqTime = 0; 359 mRelIdleTime = 0; 360 mRelStatsAreGood = false; 361 Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update"); 362 return; 363 } 364 } 365 366 mLastSampleTime = mCurrentSampleTime; 367 mCurrentSampleTime = nowUptime; 368 mLastSampleRealTime = mCurrentSampleRealTime; 369 mCurrentSampleRealTime = nowRealtime; 370 371 final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); 372 try { 373 mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats); 374 } finally { 375 StrictMode.setThreadPolicy(savedPolicy); 376 } 377 378 final float[] loadAverages = mLoadAverageData; 379 if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT, 380 null, null, loadAverages)) { 381 float load1 = loadAverages[0]; 382 float load5 = loadAverages[1]; 383 float load15 = loadAverages[2]; 384 if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) { 385 mLoad1 = load1; 386 mLoad5 = load5; 387 mLoad15 = load15; 388 onLoadChanged(load1, load5, load15); 389 } 390 } 391 392 if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: " 393 + (SystemClock.uptimeMillis()-mCurrentSampleTime)); 394 395 mWorkingProcsSorted = false; 396 mFirst = false; 397 } 398 collectStats(String statsFile, int parentPid, boolean first, int[] curPids, ArrayList<Stats> allProcs)399 private int[] collectStats(String statsFile, int parentPid, boolean first, 400 int[] curPids, ArrayList<Stats> allProcs) { 401 402 int[] pids = Process.getPids(statsFile, curPids); 403 int NP = (pids == null) ? 0 : pids.length; 404 int NS = allProcs.size(); 405 int curStatsIndex = 0; 406 for (int i=0; i<NP; i++) { 407 int pid = pids[i]; 408 if (pid < 0) { 409 NP = pid; 410 break; 411 } 412 Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null; 413 414 if (st != null && st.pid == pid) { 415 // Update an existing process... 416 st.added = false; 417 st.working = false; 418 curStatsIndex++; 419 if (DEBUG) Slog.v(TAG, "Existing " 420 + (parentPid < 0 ? "process" : "thread") 421 + " pid " + pid + ": " + st); 422 423 if (st.interesting) { 424 final long uptime = SystemClock.uptimeMillis(); 425 426 final long[] procStats = mProcessStatsData; 427 if (!Process.readProcFile(st.statFile.toString(), 428 PROCESS_STATS_FORMAT, null, procStats, null)) { 429 continue; 430 } 431 432 final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS]; 433 final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS]; 434 final long utime = procStats[PROCESS_STAT_UTIME] * mJiffyMillis; 435 final long stime = procStats[PROCESS_STAT_STIME] * mJiffyMillis; 436 437 if (utime == st.base_utime && stime == st.base_stime) { 438 st.rel_utime = 0; 439 st.rel_stime = 0; 440 st.rel_minfaults = 0; 441 st.rel_majfaults = 0; 442 if (st.active) { 443 st.active = false; 444 } 445 continue; 446 } 447 448 if (!st.active) { 449 st.active = true; 450 } 451 452 if (parentPid < 0) { 453 getName(st, st.cmdlineFile); 454 if (st.threadStats != null) { 455 mCurThreadPids = collectStats(st.threadsDir, pid, false, 456 mCurThreadPids, st.threadStats); 457 } 458 } 459 460 if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid 461 + " utime=" + utime + "-" + st.base_utime 462 + " stime=" + stime + "-" + st.base_stime 463 + " minfaults=" + minfaults + "-" + st.base_minfaults 464 + " majfaults=" + majfaults + "-" + st.base_majfaults); 465 466 st.rel_uptime = uptime - st.base_uptime; 467 st.base_uptime = uptime; 468 st.rel_utime = (int)(utime - st.base_utime); 469 st.rel_stime = (int)(stime - st.base_stime); 470 st.base_utime = utime; 471 st.base_stime = stime; 472 st.rel_minfaults = (int)(minfaults - st.base_minfaults); 473 st.rel_majfaults = (int)(majfaults - st.base_majfaults); 474 st.base_minfaults = minfaults; 475 st.base_majfaults = majfaults; 476 st.working = true; 477 } 478 479 continue; 480 } 481 482 if (st == null || st.pid > pid) { 483 // We have a new process! 484 st = new Stats(pid, parentPid, mIncludeThreads); 485 allProcs.add(curStatsIndex, st); 486 curStatsIndex++; 487 NS++; 488 if (DEBUG) Slog.v(TAG, "New " 489 + (parentPid < 0 ? "process" : "thread") 490 + " pid " + pid + ": " + st); 491 492 final String[] procStatsString = mProcessFullStatsStringData; 493 final long[] procStats = mProcessFullStatsData; 494 st.base_uptime = SystemClock.uptimeMillis(); 495 String path = st.statFile.toString(); 496 //Slog.d(TAG, "Reading proc file: " + path); 497 if (Process.readProcFile(path, PROCESS_FULL_STATS_FORMAT, procStatsString, 498 procStats, null)) { 499 // This is a possible way to filter out processes that 500 // are actually kernel threads... do we want to? Some 501 // of them do use CPU, but there can be a *lot* that are 502 // not doing anything. 503 st.vsize = procStats[PROCESS_FULL_STAT_VSIZE]; 504 if (true || procStats[PROCESS_FULL_STAT_VSIZE] != 0) { 505 st.interesting = true; 506 st.baseName = procStatsString[0]; 507 st.base_minfaults = procStats[PROCESS_FULL_STAT_MINOR_FAULTS]; 508 st.base_majfaults = procStats[PROCESS_FULL_STAT_MAJOR_FAULTS]; 509 st.base_utime = procStats[PROCESS_FULL_STAT_UTIME] * mJiffyMillis; 510 st.base_stime = procStats[PROCESS_FULL_STAT_STIME] * mJiffyMillis; 511 } else { 512 Slog.i(TAG, "Skipping kernel process pid " + pid 513 + " name " + procStatsString[0]); 514 st.baseName = procStatsString[0]; 515 } 516 } else { 517 Slog.w(TAG, "Skipping unknown process pid " + pid); 518 st.baseName = "<unknown>"; 519 st.base_utime = st.base_stime = 0; 520 st.base_minfaults = st.base_majfaults = 0; 521 } 522 523 if (parentPid < 0) { 524 getName(st, st.cmdlineFile); 525 if (st.threadStats != null) { 526 mCurThreadPids = collectStats(st.threadsDir, pid, true, 527 mCurThreadPids, st.threadStats); 528 } 529 } else if (st.interesting) { 530 st.name = st.baseName; 531 st.nameWidth = onMeasureProcessName(st.name); 532 } 533 534 if (DEBUG) Slog.v("Load", "Stats added " + st.name + " pid=" + st.pid 535 + " utime=" + st.base_utime + " stime=" + st.base_stime 536 + " minfaults=" + st.base_minfaults + " majfaults=" + st.base_majfaults); 537 538 st.rel_utime = 0; 539 st.rel_stime = 0; 540 st.rel_minfaults = 0; 541 st.rel_majfaults = 0; 542 st.added = true; 543 if (!first && st.interesting) { 544 st.working = true; 545 } 546 continue; 547 } 548 549 // This process has gone away! 550 st.rel_utime = 0; 551 st.rel_stime = 0; 552 st.rel_minfaults = 0; 553 st.rel_majfaults = 0; 554 st.removed = true; 555 st.working = true; 556 allProcs.remove(curStatsIndex); 557 NS--; 558 if (DEBUG) Slog.v(TAG, "Removed " 559 + (parentPid < 0 ? "process" : "thread") 560 + " pid " + pid + ": " + st); 561 // Decrement the loop counter so that we process the current pid 562 // again the next time through the loop. 563 i--; 564 continue; 565 } 566 567 while (curStatsIndex < NS) { 568 // This process has gone away! 569 final Stats st = allProcs.get(curStatsIndex); 570 st.rel_utime = 0; 571 st.rel_stime = 0; 572 st.rel_minfaults = 0; 573 st.rel_majfaults = 0; 574 st.removed = true; 575 st.working = true; 576 allProcs.remove(curStatsIndex); 577 NS--; 578 if (localLOGV) Slog.v(TAG, "Removed pid " + st.pid + ": " + st); 579 } 580 581 return pids; 582 } 583 584 /** 585 * Returns the total time (in milliseconds) spent executing in 586 * both user and system code. Safe to call without lock held. 587 */ 588 public long getCpuTimeForPid(int pid) { 589 synchronized (mSinglePidStatsData) { 590 final String statFile = "/proc/" + pid + "/stat"; 591 final long[] statsData = mSinglePidStatsData; 592 if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT, 593 null, statsData, null)) { 594 long time = statsData[PROCESS_STAT_UTIME] 595 + statsData[PROCESS_STAT_STIME]; 596 return time * mJiffyMillis; 597 } 598 return 0; 599 } 600 } 601 602 /** 603 * @return time in milliseconds. 604 */ 605 final public int getLastUserTime() { 606 return mRelUserTime; 607 } 608 609 /** 610 * @return time in milliseconds. 611 */ 612 final public int getLastSystemTime() { 613 return mRelSystemTime; 614 } 615 616 /** 617 * @return time in milliseconds. 618 */ 619 final public int getLastIoWaitTime() { 620 return mRelIoWaitTime; 621 } 622 623 /** 624 * @return time in milliseconds. 625 */ 626 final public int getLastIrqTime() { 627 return mRelIrqTime; 628 } 629 630 /** 631 * @return time in milliseconds. 632 */ 633 final public int getLastSoftIrqTime() { 634 return mRelSoftIrqTime; 635 } 636 637 /** 638 * @return time in milliseconds. 639 */ 640 final public int getLastIdleTime() { 641 return mRelIdleTime; 642 } 643 644 final public boolean hasGoodLastStats() { 645 return mRelStatsAreGood; 646 } 647 648 final public float getTotalCpuPercent() { 649 int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime; 650 if (denom <= 0) { 651 return 0; 652 } 653 return ((float)(mRelUserTime+mRelSystemTime+mRelIrqTime)*100) / denom; 654 } 655 656 final void buildWorkingProcs() { 657 if (!mWorkingProcsSorted) { 658 mWorkingProcs.clear(); 659 final int N = mProcStats.size(); 660 for (int i=0; i<N; i++) { 661 Stats stats = mProcStats.get(i); 662 if (stats.working) { 663 mWorkingProcs.add(stats); 664 if (stats.threadStats != null && stats.threadStats.size() > 1) { 665 stats.workingThreads.clear(); 666 final int M = stats.threadStats.size(); 667 for (int j=0; j<M; j++) { 668 Stats tstats = stats.threadStats.get(j); 669 if (tstats.working) { 670 stats.workingThreads.add(tstats); 671 } 672 } 673 Collections.sort(stats.workingThreads, sLoadComparator); 674 } 675 } 676 } 677 Collections.sort(mWorkingProcs, sLoadComparator); 678 mWorkingProcsSorted = true; 679 } 680 } 681 682 final public int countStats() { 683 return mProcStats.size(); 684 } 685 686 final public Stats getStats(int index) { 687 return mProcStats.get(index); 688 } 689 690 final public int countWorkingStats() { 691 buildWorkingProcs(); 692 return mWorkingProcs.size(); 693 } 694 695 final public Stats getWorkingStats(int index) { 696 return mWorkingProcs.get(index); 697 } 698 699 final public String printCurrentLoad() { 700 StringWriter sw = new StringWriter(); 701 PrintWriter pw = new FastPrintWriter(sw, false, 128); 702 pw.print("Load: "); 703 pw.print(mLoad1); 704 pw.print(" / "); 705 pw.print(mLoad5); 706 pw.print(" / "); 707 pw.println(mLoad15); 708 pw.flush(); 709 return sw.toString(); 710 } 711 712 final public String printCurrentState(long now) { 713 buildWorkingProcs(); 714 715 StringWriter sw = new StringWriter(); 716 PrintWriter pw = new FastPrintWriter(sw, false, 1024); 717 718 pw.print("CPU usage from "); 719 if (now > mLastSampleTime) { 720 pw.print(now-mLastSampleTime); 721 pw.print("ms to "); 722 pw.print(now-mCurrentSampleTime); 723 pw.print("ms ago"); 724 } else { 725 pw.print(mLastSampleTime-now); 726 pw.print("ms to "); 727 pw.print(mCurrentSampleTime-now); 728 pw.print("ms later"); 729 } 730 731 long sampleTime = mCurrentSampleTime - mLastSampleTime; 732 long sampleRealTime = mCurrentSampleRealTime - mLastSampleRealTime; 733 long percAwake = sampleRealTime > 0 ? ((sampleTime*100) / sampleRealTime) : 0; 734 if (percAwake != 100) { 735 pw.print(" with "); 736 pw.print(percAwake); 737 pw.print("% awake"); 738 } 739 pw.println(":"); 740 741 final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime 742 + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime; 743 744 if (DEBUG) Slog.i(TAG, "totalTime " + totalTime + " over sample time " 745 + (mCurrentSampleTime-mLastSampleTime)); 746 747 int N = mWorkingProcs.size(); 748 for (int i=0; i<N; i++) { 749 Stats st = mWorkingProcs.get(i); 750 printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": " "), 751 st.pid, st.name, (int)st.rel_uptime, 752 st.rel_utime, st.rel_stime, 0, 0, 0, st.rel_minfaults, st.rel_majfaults); 753 if (!st.removed && st.workingThreads != null) { 754 int M = st.workingThreads.size(); 755 for (int j=0; j<M; j++) { 756 Stats tst = st.workingThreads.get(j); 757 printProcessCPU(pw, 758 tst.added ? " +" : (tst.removed ? " -": " "), 759 tst.pid, tst.name, (int)st.rel_uptime, 760 tst.rel_utime, tst.rel_stime, 0, 0, 0, 0, 0); 761 } 762 } 763 } 764 765 printProcessCPU(pw, "", -1, "TOTAL", totalTime, mRelUserTime, mRelSystemTime, 766 mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0); 767 768 pw.flush(); 769 return sw.toString(); 770 } 771 772 private void printRatio(PrintWriter pw, long numerator, long denominator) { 773 long thousands = (numerator*1000)/denominator; 774 long hundreds = thousands/10; 775 pw.print(hundreds); 776 if (hundreds < 10) { 777 long remainder = thousands - (hundreds*10); 778 if (remainder != 0) { 779 pw.print('.'); 780 pw.print(remainder); 781 } 782 } 783 } 784 785 private void printProcessCPU(PrintWriter pw, String prefix, int pid, String label, 786 int totalTime, int user, int system, int iowait, int irq, int softIrq, 787 int minFaults, int majFaults) { 788 pw.print(prefix); 789 if (totalTime == 0) totalTime = 1; 790 printRatio(pw, user+system+iowait+irq+softIrq, totalTime); 791 pw.print("% "); 792 if (pid >= 0) { 793 pw.print(pid); 794 pw.print("/"); 795 } 796 pw.print(label); 797 pw.print(": "); 798 printRatio(pw, user, totalTime); 799 pw.print("% user + "); 800 printRatio(pw, system, totalTime); 801 pw.print("% kernel"); 802 if (iowait > 0) { 803 pw.print(" + "); 804 printRatio(pw, iowait, totalTime); 805 pw.print("% iowait"); 806 } 807 if (irq > 0) { 808 pw.print(" + "); 809 printRatio(pw, irq, totalTime); 810 pw.print("% irq"); 811 } 812 if (softIrq > 0) { 813 pw.print(" + "); 814 printRatio(pw, softIrq, totalTime); 815 pw.print("% softirq"); 816 } 817 if (minFaults > 0 || majFaults > 0) { 818 pw.print(" / faults:"); 819 if (minFaults > 0) { 820 pw.print(" "); 821 pw.print(minFaults); 822 pw.print(" minor"); 823 } 824 if (majFaults > 0) { 825 pw.print(" "); 826 pw.print(majFaults); 827 pw.print(" major"); 828 } 829 } 830 pw.println(); 831 } 832 833 private String readFile(String file, char endChar) { 834 // Permit disk reads here, as /proc/meminfo isn't really "on 835 // disk" and should be fast. TODO: make BlockGuard ignore 836 // /proc/ and /sys/ files perhaps? 837 StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); 838 FileInputStream is = null; 839 try { 840 is = new FileInputStream(file); 841 int len = is.read(mBuffer); 842 is.close(); 843 844 if (len > 0) { 845 int i; 846 for (i=0; i<len; i++) { 847 if (mBuffer[i] == endChar) { 848 break; 849 } 850 } 851 return new String(mBuffer, 0, i); 852 } 853 } catch (java.io.FileNotFoundException e) { 854 } catch (java.io.IOException e) { 855 } finally { 856 IoUtils.closeQuietly(is); 857 StrictMode.setThreadPolicy(savedPolicy); 858 } 859 return null; 860 } 861 getName(Stats st, String cmdlineFile)862 private void getName(Stats st, String cmdlineFile) { 863 String newName = st.name; 864 if (st.name == null || st.name.equals("app_process") 865 || st.name.equals("<pre-initialized>")) { 866 String cmdName = readFile(cmdlineFile, '\0'); 867 if (cmdName != null && cmdName.length() > 1) { 868 newName = cmdName; 869 int i = newName.lastIndexOf("/"); 870 if (i > 0 && i < newName.length()-1) { 871 newName = newName.substring(i+1); 872 } 873 } 874 if (newName == null) { 875 newName = st.baseName; 876 } 877 } 878 if (st.name == null || !newName.equals(st.name)) { 879 st.name = newName; 880 st.nameWidth = onMeasureProcessName(st.name); 881 } 882 } 883 } 884