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