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