Debug.java revision 9266c558bf1d21ff647525ff99f7dadbca417309
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 android.os; 18 19import java.io.FileOutputStream; 20import java.io.OutputStreamWriter; 21import java.io.PrintWriter; 22 23import org.apache.harmony.dalvik.ddmc.Chunk; 24import org.apache.harmony.dalvik.ddmc.ChunkHandler; 25import org.apache.harmony.dalvik.ddmc.DdmServer; 26 27import dalvik.bytecode.Opcodes; 28import dalvik.system.VMDebug; 29 30 31/** Provides various debugging functions for Android applications, including 32 * tracing and allocation counts. 33 * <p><strong>Logging Trace Files</strong></p> 34 * <p>Debug can create log files that give details about an application, such as 35 * a call stack and start/stop times for any running methods. See <a 36href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for 37 * information about reading trace files. To start logging trace files, call one 38 * of the startMethodTracing() methods. To stop tracing, call 39 * {@link #stopMethodTracing()}. 40 */ 41public final class Debug 42{ 43 /** 44 * Flags for startMethodTracing(). These can be ORed together. 45 * 46 * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the 47 * trace key file. 48 */ 49 public static final int TRACE_COUNT_ALLOCS = VMDebug.TRACE_COUNT_ALLOCS; 50 51 /** 52 * Flags for printLoadedClasses(). Default behavior is to only show 53 * the class name. 54 */ 55 public static final int SHOW_FULL_DETAIL = 1; 56 public static final int SHOW_CLASSLOADER = (1 << 1); 57 public static final int SHOW_INITIALIZED = (1 << 2); 58 59 // set/cleared by waitForDebugger() 60 private static volatile boolean mWaiting = false; 61 62 private Debug() {} 63 64 /* 65 * How long to wait for the debugger to finish sending requests. I've 66 * seen this hit 800msec on the device while waiting for a response 67 * to travel over USB and get processed, so we take that and add 68 * half a second. 69 */ 70 private static final int MIN_DEBUGGER_IDLE = 1300; // msec 71 72 /* how long to sleep when polling for activity */ 73 private static final int SPIN_DELAY = 200; // msec 74 75 /** 76 * Default trace file path and file 77 */ 78 private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/"; 79 private static final String DEFAULT_TRACE_BODY = "dmtrace"; 80 private static final String DEFAULT_TRACE_EXTENSION = ".trace"; 81 private static final String DEFAULT_TRACE_FILE_PATH = 82 DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY 83 + DEFAULT_TRACE_EXTENSION; 84 85 86 /** 87 * This class is used to retrieved various statistics about the memory mappings for this 88 * process. The returns info broken down by dalvik, native, and other. All results are in kB. 89 */ 90 public static class MemoryInfo { 91 /** The proportional set size for dalvik. */ 92 public int dalvikPss; 93 /** The private dirty pages used by dalvik. */ 94 public int dalvikPrivateDirty; 95 /** The shared dirty pages used by dalvik. */ 96 public int dalvikSharedDirty; 97 98 /** The proportional set size for the native heap. */ 99 public int nativePss; 100 /** The private dirty pages used by the native heap. */ 101 public int nativePrivateDirty; 102 /** The shared dirty pages used by the native heap. */ 103 public int nativeSharedDirty; 104 105 /** The proportional set size for everything else. */ 106 public int otherPss; 107 /** The private dirty pages used by everything else. */ 108 public int otherPrivateDirty; 109 /** The shared dirty pages used by everything else. */ 110 public int otherSharedDirty; 111 } 112 113 114 /** 115 * Wait until a debugger attaches. As soon as the debugger attaches, 116 * this returns, so you will need to place a breakpoint after the 117 * waitForDebugger() call if you want to start tracing immediately. 118 */ 119 public static void waitForDebugger() { 120 if (!VMDebug.isDebuggingEnabled()) { 121 //System.out.println("debugging not enabled, not waiting"); 122 return; 123 } 124 if (isDebuggerConnected()) 125 return; 126 127 // if DDMS is listening, inform them of our plight 128 System.out.println("Sending WAIT chunk"); 129 byte[] data = new byte[] { 0 }; // 0 == "waiting for debugger" 130 Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1); 131 DdmServer.sendChunk(waitChunk); 132 133 mWaiting = true; 134 while (!isDebuggerConnected()) { 135 try { Thread.sleep(SPIN_DELAY); } 136 catch (InterruptedException ie) {} 137 } 138 mWaiting = false; 139 140 System.out.println("Debugger has connected"); 141 142 /* 143 * There is no "ready to go" signal from the debugger, and we're 144 * not allowed to suspend ourselves -- the debugger expects us to 145 * be running happily, and gets confused if we aren't. We need to 146 * allow the debugger a chance to set breakpoints before we start 147 * running again. 148 * 149 * Sit and spin until the debugger has been idle for a short while. 150 */ 151 while (true) { 152 long delta = VMDebug.lastDebuggerActivity(); 153 if (delta < 0) { 154 System.out.println("debugger detached?"); 155 break; 156 } 157 158 if (delta < MIN_DEBUGGER_IDLE) { 159 System.out.println("waiting for debugger to settle..."); 160 try { Thread.sleep(SPIN_DELAY); } 161 catch (InterruptedException ie) {} 162 } else { 163 System.out.println("debugger has settled (" + delta + ")"); 164 break; 165 } 166 } 167 } 168 169 /** 170 * Returns "true" if one or more threads is waiting for a debugger 171 * to attach. 172 */ 173 public static boolean waitingForDebugger() { 174 return mWaiting; 175 } 176 177 /** 178 * Determine if a debugger is currently attached. 179 */ 180 public static boolean isDebuggerConnected() { 181 return VMDebug.isDebuggerConnected(); 182 } 183 184 /** 185 * Change the JDWP port. 186 * 187 * @deprecated no longer needed or useful 188 */ 189 @Deprecated 190 public static void changeDebugPort(int port) {} 191 192 /** 193 * This is the pathname to the sysfs file that enables and disables 194 * tracing on the qemu emulator. 195 */ 196 private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state"; 197 198 /** 199 * Enable qemu tracing. For this to work requires running everything inside 200 * the qemu emulator; otherwise, this method will have no effect. The trace 201 * file is specified on the command line when the emulator is started. For 202 * example, the following command line <br /> 203 * <code>emulator -trace foo</code><br /> 204 * will start running the emulator and create a trace file named "foo". This 205 * method simply enables writing the trace records to the trace file. 206 * 207 * <p> 208 * The main differences between this and {@link #startMethodTracing()} are 209 * that tracing in the qemu emulator traces every cpu instruction of every 210 * process, including kernel code, so we have more complete information, 211 * including all context switches. We can also get more detailed information 212 * such as cache misses. The sequence of calls is determined by 213 * post-processing the instruction trace. The qemu tracing is also done 214 * without modifying the application or perturbing the timing of calls 215 * because no instrumentation is added to the application being traced. 216 * </p> 217 * 218 * <p> 219 * One limitation of using this method compared to using 220 * {@link #startMethodTracing()} on the real device is that the emulator 221 * does not model all of the real hardware effects such as memory and 222 * bus contention. The emulator also has a simple cache model and cannot 223 * capture all the complexities of a real cache. 224 * </p> 225 */ 226 public static void startNativeTracing() { 227 // Open the sysfs file for writing and write "1" to it. 228 PrintWriter outStream = null; 229 try { 230 FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE); 231 outStream = new PrintWriter(new OutputStreamWriter(fos)); 232 outStream.println("1"); 233 } catch (Exception e) { 234 } finally { 235 if (outStream != null) 236 outStream.close(); 237 } 238 239 VMDebug.startEmulatorTracing(); 240 } 241 242 /** 243 * Stop qemu tracing. See {@link #startNativeTracing()} to start tracing. 244 * 245 * <p>Tracing can be started and stopped as many times as desired. When 246 * the qemu emulator itself is stopped then the buffered trace records 247 * are flushed and written to the trace file. In fact, it is not necessary 248 * to call this method at all; simply killing qemu is sufficient. But 249 * starting and stopping a trace is useful for examining a specific 250 * region of code.</p> 251 */ 252 public static void stopNativeTracing() { 253 VMDebug.stopEmulatorTracing(); 254 255 // Open the sysfs file for writing and write "0" to it. 256 PrintWriter outStream = null; 257 try { 258 FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE); 259 outStream = new PrintWriter(new OutputStreamWriter(fos)); 260 outStream.println("0"); 261 } catch (Exception e) { 262 // We could print an error message here but we probably want 263 // to quietly ignore errors if we are not running in the emulator. 264 } finally { 265 if (outStream != null) 266 outStream.close(); 267 } 268 } 269 270 /** 271 * Enable "emulator traces", in which information about the current 272 * method is made available to the "emulator -trace" feature. There 273 * is no corresponding "disable" call -- this is intended for use by 274 * the framework when tracing should be turned on and left that way, so 275 * that traces captured with F9/F10 will include the necessary data. 276 * 277 * This puts the VM into "profile" mode, which has performance 278 * consequences. 279 * 280 * To temporarily enable tracing, use {@link #startNativeTracing()}. 281 */ 282 public static void enableEmulatorTraceOutput() { 283 VMDebug.startEmulatorTracing(); 284 } 285 286 /** 287 * Start method tracing with default log name and buffer size. See <a 288href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for 289 * information about reading these files. Call stopMethodTracing() to stop 290 * tracing. 291 */ 292 public static void startMethodTracing() { 293 VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0); 294 } 295 296 /** 297 * Start method tracing, specifying the trace log file name. The trace 298 * file will be put under "/sdcard" unless an absolute path is given. 299 * See <a 300 href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for 301 * information about reading trace files. 302 * 303 * @param traceName Name for the trace log file to create. 304 * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". 305 * If the files already exist, they will be truncated. 306 * If the trace file given does not end in ".trace", it will be appended for you. 307 */ 308 public static void startMethodTracing(String traceName) { 309 startMethodTracing(traceName, 0, 0); 310 } 311 312 /** 313 * Start method tracing, specifying the trace log file name and the 314 * buffer size. The trace files will be put under "/sdcard" unless an 315 * absolute path is given. See <a 316 href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for 317 * information about reading trace files. 318 * @param traceName Name for the trace log file to create. 319 * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". 320 * If the files already exist, they will be truncated. 321 * If the trace file given does not end in ".trace", it will be appended for you. 322 * 323 * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. 324 */ 325 public static void startMethodTracing(String traceName, int bufferSize) { 326 startMethodTracing(traceName, bufferSize, 0); 327 } 328 329 /** 330 * Start method tracing, specifying the trace log file name and the 331 * buffer size. The trace files will be put under "/sdcard" unless an 332 * absolute path is given. See <a 333 href="{@docRoot}reference/traceview.html">Running the Traceview Debugging Program</a> for 334 * information about reading trace files. 335 * 336 * <p> 337 * When method tracing is enabled, the VM will run more slowly than 338 * usual, so the timings from the trace files should only be considered 339 * in relative terms (e.g. was run #1 faster than run #2). The times 340 * for native methods will not change, so don't try to use this to 341 * compare the performance of interpreted and native implementations of the 342 * same method. As an alternative, consider using "native" tracing 343 * in the emulator via {@link #startNativeTracing()}. 344 * </p> 345 * 346 * @param traceName Name for the trace log file to create. 347 * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace". 348 * If the files already exist, they will be truncated. 349 * If the trace file given does not end in ".trace", it will be appended for you. 350 * @param bufferSize The maximum amount of trace data we gather. If not given, it defaults to 8MB. 351 */ 352 public static void startMethodTracing(String traceName, int bufferSize, 353 int flags) { 354 355 String pathName = traceName; 356 if (pathName.charAt(0) != '/') 357 pathName = DEFAULT_TRACE_PATH_PREFIX + pathName; 358 if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION)) 359 pathName = pathName + DEFAULT_TRACE_EXTENSION; 360 361 VMDebug.startMethodTracing(pathName, bufferSize, flags); 362 } 363 364 /** 365 * Stop method tracing. 366 */ 367 public static void stopMethodTracing() { 368 VMDebug.stopMethodTracing(); 369 } 370 371 /** 372 * Get an indication of thread CPU usage. The value returned 373 * indicates the amount of time that the current thread has spent 374 * executing code or waiting for certain types of I/O. 375 * 376 * The time is expressed in nanoseconds, and is only meaningful 377 * when compared to the result from an earlier call. Note that 378 * nanosecond resolution does not imply nanosecond accuracy. 379 * 380 * On system which don't support this operation, the call returns -1. 381 */ 382 public static long threadCpuTimeNanos() { 383 return VMDebug.threadCpuTimeNanos(); 384 } 385 386 /** 387 * Count the number and aggregate size of memory allocations between 388 * two points. 389 * 390 * The "start" function resets the counts and enables counting. The 391 * "stop" function disables the counting so that the analysis code 392 * doesn't cause additional allocations. The "get" function returns 393 * the specified value. 394 * 395 * Counts are kept for the system as a whole and for each thread. 396 * The per-thread counts for threads other than the current thread 397 * are not cleared by the "reset" or "start" calls. 398 */ 399 public static void startAllocCounting() { 400 VMDebug.startAllocCounting(); 401 } 402 public static void stopAllocCounting() { 403 VMDebug.stopAllocCounting(); 404 } 405 406 public static int getGlobalAllocCount() { 407 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); 408 } 409 public static int getGlobalAllocSize() { 410 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); 411 } 412 public static int getGlobalFreedCount() { 413 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); 414 } 415 public static int getGlobalFreedSize() { 416 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); 417 } 418 public static int getGlobalExternalAllocCount() { 419 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS); 420 } 421 public static int getGlobalExternalAllocSize() { 422 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES); 423 } 424 public static int getGlobalExternalFreedCount() { 425 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS); 426 } 427 public static int getGlobalExternalFreedSize() { 428 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES); 429 } 430 public static int getGlobalGcInvocationCount() { 431 return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); 432 } 433 public static int getThreadAllocCount() { 434 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); 435 } 436 public static int getThreadAllocSize() { 437 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); 438 } 439 public static int getThreadExternalAllocCount() { 440 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS); 441 } 442 public static int getThreadExternalAllocSize() { 443 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES); 444 } 445 public static int getThreadGcInvocationCount() { 446 return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); 447 } 448 449 public static void resetGlobalAllocCount() { 450 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); 451 } 452 public static void resetGlobalAllocSize() { 453 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); 454 } 455 public static void resetGlobalFreedCount() { 456 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); 457 } 458 public static void resetGlobalFreedSize() { 459 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); 460 } 461 public static void resetGlobalExternalAllocCount() { 462 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS); 463 } 464 public static void resetGlobalExternalAllocSize() { 465 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES); 466 } 467 public static void resetGlobalExternalFreedCount() { 468 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS); 469 } 470 public static void resetGlobalExternalFreedSize() { 471 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES); 472 } 473 public static void resetGlobalGcInvocationCount() { 474 VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); 475 } 476 public static void resetThreadAllocCount() { 477 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); 478 } 479 public static void resetThreadAllocSize() { 480 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); 481 } 482 public static void resetThreadExternalAllocCount() { 483 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS); 484 } 485 public static void resetThreadExternalAllocSize() { 486 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES); 487 } 488 public static void resetThreadGcInvocationCount() { 489 VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); 490 } 491 public static void resetAllCounts() { 492 VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS); 493 } 494 495 /** 496 * Returns the size of the native heap. 497 * @return The size of the native heap in bytes. 498 */ 499 public static native long getNativeHeapSize(); 500 501 /** 502 * Returns the amount of allocated memory in the native heap. 503 * @return The allocated size in bytes. 504 */ 505 public static native long getNativeHeapAllocatedSize(); 506 507 /** 508 * Returns the amount of free memory in the native heap. 509 * @return The freed size in bytes. 510 */ 511 public static native long getNativeHeapFreeSize(); 512 513 /** 514 * Retrieves information about this processes memory usages. This information is broken down by 515 * how much is in use by dalivk, the native heap, and everything else. 516 */ 517 public static native void getMemoryInfo(MemoryInfo memoryInfo); 518 519 /** 520 * Establish an object allocation limit in the current thread. Useful 521 * for catching regressions in code that is expected to operate 522 * without causing any allocations. 523 * 524 * Pass in the maximum number of allowed allocations. Use -1 to disable 525 * the limit. Returns the previous limit. 526 * 527 * The preferred way to use this is: 528 * 529 * int prevLimit = -1; 530 * try { 531 * prevLimit = Debug.setAllocationLimit(0); 532 * ... do stuff that's not expected to allocate memory ... 533 * } finally { 534 * Debug.setAllocationLimit(prevLimit); 535 * } 536 * 537 * This allows limits to be nested. The try/finally ensures that the 538 * limit is reset if something fails. 539 * 540 * Exceeding the limit causes a dalvik.system.AllocationLimitError to 541 * be thrown from a memory allocation call. The limit is reset to -1 542 * when this happens. 543 * 544 * The feature may be disabled in the VM configuration. If so, this 545 * call has no effect, and always returns -1. 546 */ 547 public static int setAllocationLimit(int limit) { 548 return VMDebug.setAllocationLimit(limit); 549 } 550 551 /** 552 * Establish a global object allocation limit. This is similar to 553 * {@link #setAllocationLimit(int)} but applies to all threads in 554 * the VM. It will coexist peacefully with per-thread limits. 555 * 556 * [ The value of "limit" is currently restricted to 0 (no allocations 557 * allowed) or -1 (no global limit). This may be changed in a future 558 * release. ] 559 */ 560 public static int setGlobalAllocationLimit(int limit) { 561 if (limit != 0 && limit != -1) 562 throw new IllegalArgumentException("limit must be 0 or -1"); 563 return VMDebug.setGlobalAllocationLimit(limit); 564 } 565 566 /** 567 * Dump a list of all currently loaded class to the log file. 568 * 569 * @param flags See constants above. 570 */ 571 public static void printLoadedClasses(int flags) { 572 VMDebug.printLoadedClasses(flags); 573 } 574 575 /** 576 * Get the number of loaded classes. 577 * @return the number of loaded classes. 578 */ 579 public static int getLoadedClassCount() { 580 return VMDebug.getLoadedClassCount(); 581 } 582 583 /** 584 * Returns the number of sent transactions from this process. 585 * @return The number of sent transactions or -1 if it could not read t. 586 */ 587 public static native int getBinderSentTransactions(); 588 589 /** 590 * Returns the number of received transactions from the binder driver. 591 * @return The number of received transactions or -1 if it could not read the stats. 592 */ 593 public static native int getBinderReceivedTransactions(); 594 595 /** 596 * Returns the number of active local Binder objects that exist in the 597 * current process. 598 */ 599 public static final native int getBinderLocalObjectCount(); 600 601 /** 602 * Returns the number of references to remote proxy Binder objects that 603 * exist in the current process. 604 */ 605 public static final native int getBinderProxyObjectCount(); 606 607 /** 608 * Returns the number of death notification links to Binder objects that 609 * exist in the current process. 610 */ 611 public static final native int getBinderDeathObjectCount(); 612 613 /** 614 * API for gathering and querying instruction counts. 615 * 616 * Example usage: 617 * Debug.InstructionCount icount = new Debug.InstructionCount(); 618 * icount.resetAndStart(); 619 * [... do lots of stuff ...] 620 * if (icount.collect()) { 621 * System.out.println("Total instructions executed: " 622 * + icount.globalTotal()); 623 * System.out.println("Method invocations: " 624 * + icount.globalMethodInvocations()); 625 * } 626 */ 627 public static class InstructionCount { 628 private static final int NUM_INSTR = 256; 629 630 private int[] mCounts; 631 632 public InstructionCount() { 633 mCounts = new int[NUM_INSTR]; 634 } 635 636 /** 637 * Reset counters and ensure counts are running. Counts may 638 * have already been running. 639 * 640 * @return true if counting was started 641 */ 642 public boolean resetAndStart() { 643 try { 644 VMDebug.startInstructionCounting(); 645 VMDebug.resetInstructionCount(); 646 } catch (UnsupportedOperationException uoe) { 647 return false; 648 } 649 return true; 650 } 651 652 /** 653 * Collect instruction counts. May or may not stop the 654 * counting process. 655 */ 656 public boolean collect() { 657 try { 658 VMDebug.stopInstructionCounting(); 659 VMDebug.getInstructionCount(mCounts); 660 } catch (UnsupportedOperationException uoe) { 661 return false; 662 } 663 return true; 664 } 665 666 /** 667 * Return the total number of instructions executed globally (i.e. in 668 * all threads). 669 */ 670 public int globalTotal() { 671 int count = 0; 672 for (int i = 0; i < NUM_INSTR; i++) 673 count += mCounts[i]; 674 return count; 675 } 676 677 /** 678 * Return the total number of method-invocation instructions 679 * executed globally. 680 */ 681 public int globalMethodInvocations() { 682 int count = 0; 683 684 //count += mCounts[Opcodes.OP_EXECUTE_INLINE]; 685 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL]; 686 count += mCounts[Opcodes.OP_INVOKE_SUPER]; 687 count += mCounts[Opcodes.OP_INVOKE_DIRECT]; 688 count += mCounts[Opcodes.OP_INVOKE_STATIC]; 689 count += mCounts[Opcodes.OP_INVOKE_INTERFACE]; 690 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE]; 691 count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE]; 692 count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE]; 693 count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE]; 694 count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE]; 695 //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY]; 696 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK]; 697 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE]; 698 count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK]; 699 count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE]; 700 return count; 701 } 702 }; 703} 704