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