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