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