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