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