blob: 5ea5aaedccaf6424270626b9b05ba01b45a01da2 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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 /**
Andy McFadden07970832009-03-24 18:15:57 -0700367 * Determine whether method tracing is currently active.
368 * @hide
369 */
370 public static boolean isMethodTracingActive() {
371 return VMDebug.isMethodTracingActive();
372 }
373
374 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 * 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 * API for gathering and querying instruction counts.
637 *
638 * Example usage:
639 * Debug.InstructionCount icount = new Debug.InstructionCount();
640 * icount.resetAndStart();
641 * [... do lots of stuff ...]
642 * if (icount.collect()) {
643 * System.out.println("Total instructions executed: "
644 * + icount.globalTotal());
645 * System.out.println("Method invocations: "
646 * + icount.globalMethodInvocations());
647 * }
648 */
649 public static class InstructionCount {
650 private static final int NUM_INSTR = 256;
651
652 private int[] mCounts;
653
654 public InstructionCount() {
655 mCounts = new int[NUM_INSTR];
656 }
657
658 /**
659 * Reset counters and ensure counts are running. Counts may
660 * have already been running.
661 *
662 * @return true if counting was started
663 */
664 public boolean resetAndStart() {
665 try {
666 VMDebug.startInstructionCounting();
667 VMDebug.resetInstructionCount();
668 } catch (UnsupportedOperationException uoe) {
669 return false;
670 }
671 return true;
672 }
673
674 /**
675 * Collect instruction counts. May or may not stop the
676 * counting process.
677 */
678 public boolean collect() {
679 try {
680 VMDebug.stopInstructionCounting();
681 VMDebug.getInstructionCount(mCounts);
682 } catch (UnsupportedOperationException uoe) {
683 return false;
684 }
685 return true;
686 }
687
688 /**
689 * Return the total number of instructions executed globally (i.e. in
690 * all threads).
691 */
692 public int globalTotal() {
693 int count = 0;
694 for (int i = 0; i < NUM_INSTR; i++)
695 count += mCounts[i];
696 return count;
697 }
698
699 /**
700 * Return the total number of method-invocation instructions
701 * executed globally.
702 */
703 public int globalMethodInvocations() {
704 int count = 0;
705
706 //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
707 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
708 count += mCounts[Opcodes.OP_INVOKE_SUPER];
709 count += mCounts[Opcodes.OP_INVOKE_DIRECT];
710 count += mCounts[Opcodes.OP_INVOKE_STATIC];
711 count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
712 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
713 count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
714 count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
715 count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
716 count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
717 //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
718 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
719 count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
720 count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
721 count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
722 return count;
723 }
724 };
725}