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