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