• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 import java.io.File;
18 import java.io.IOException;
19 import java.lang.reflect.Method;
20 import java.util.Arrays;
21 import java.util.ArrayList;
22 import java.util.Map;
23 
24 public class Main {
25     private static final String TEMP_FILE_NAME_PREFIX = "test";
26     private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
27 
main(String[] args)28     public static void main(String[] args) throws Exception {
29         String name = System.getProperty("java.vm.name");
30         if (!"Dalvik".equals(name)) {
31             System.out.println("This test is not supported on " + name);
32             return;
33         }
34         testMethodTracing();
35         testCountInstances();
36         testRuntimeStat();
37         testRuntimeStats();
38         testGetAllocCount();
39         testGetVmFeatureList();
40         testDebuggerDetails();
41     }
42 
createTempFile()43     private static File createTempFile() throws Exception {
44         try {
45             return  File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
46         } catch (IOException e) {
47             System.setProperty("java.io.tmpdir", "/data/local/tmp");
48             try {
49                 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
50             } catch (IOException e2) {
51                 System.setProperty("java.io.tmpdir", "/sdcard");
52                 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
53             }
54         }
55     }
56 
testMethodTracing()57     private static void testMethodTracing() throws Exception {
58         File tempFile = null;
59         try {
60             tempFile = createTempFile();
61             testMethodTracingToFile(tempFile);
62         } finally {
63             if (tempFile != null) {
64                 tempFile.delete();
65             }
66         }
67     }
68 
testMethodTracingToFile(File tempFile)69     private static void testMethodTracingToFile(File tempFile) throws Exception {
70         String tempFileName = tempFile.getPath();
71 
72         if (VMDebug.getMethodTracingMode() != 0) {
73             VMDebug.stopMethodTracing();
74         }
75 
76         System.out.println("Confirm enable/disable");
77         System.out.println("status=" + VMDebug.getMethodTracingMode());
78         VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0);
79         System.out.println("status=" + VMDebug.getMethodTracingMode());
80         VMDebug.stopMethodTracing();
81         System.out.println("status=" + VMDebug.getMethodTracingMode());
82         if (tempFile.length() == 0) {
83             System.out.println("ERROR: tracing output file is empty");
84         }
85 
86         System.out.println("Confirm sampling");
87         VMDebug.startMethodTracing(tempFileName, 0, 0, true, 1000);
88         System.out.println("status=" + VMDebug.getMethodTracingMode());
89         VMDebug.stopMethodTracing();
90         System.out.println("status=" + VMDebug.getMethodTracingMode());
91         if (tempFile.length() == 0) {
92             System.out.println("ERROR: sample tracing output file is empty");
93         }
94 
95         System.out.println("Test starting when already started");
96         VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0);
97         System.out.println("status=" + VMDebug.getMethodTracingMode());
98         VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0);
99         System.out.println("status=" + VMDebug.getMethodTracingMode());
100 
101         System.out.println("Test stopping when already stopped");
102         VMDebug.stopMethodTracing();
103         System.out.println("status=" + VMDebug.getMethodTracingMode());
104         VMDebug.stopMethodTracing();
105         System.out.println("status=" + VMDebug.getMethodTracingMode());
106 
107         System.out.println("Test tracing with empty filename");
108         try {
109             VMDebug.startMethodTracing("", 0, 0, false, 0);
110             System.out.println("Should have thrown an exception");
111         } catch (Exception e) {
112             System.out.println("Got expected exception");
113         }
114 
115         System.out.println("Test tracing with bogus (< 1024 && != 0) filesize");
116         try {
117             VMDebug.startMethodTracing(tempFileName, 1000, 0, false, 0);
118             System.out.println("Should have thrown an exception");
119         } catch (Exception e) {
120             System.out.println("Got expected exception");
121         }
122 
123         try {
124             VMDebug.startMethodTracingDdms(1000, 0, false, 0);
125             System.out.println("Should have thrown an exception");
126         } catch (Exception e) {
127             System.out.println("Got expected exception");
128         }
129 
130         System.out.println("Test sampling with bogus (<= 0) interval");
131         try {
132             VMDebug.startMethodTracing(tempFileName, 0, 0, true, 0);
133             System.out.println("Should have thrown an exception");
134         } catch (Exception e) {
135             System.out.println("Got expected exception");
136         }
137         try {
138             VMDebug.startMethodTracingDdms(0, 0, true, 0);
139             System.out.println("Should have thrown an exception");
140         } catch (Exception e) {
141             System.out.println("Got expected exception");
142         }
143 
144         tempFile.delete();
145     }
146 
checkNumber(String s)147     private static void checkNumber(String s) throws Exception {
148         if (s == null) {
149             System.out.println("Got null string");
150             return;
151         }
152         long n = Long.parseLong(s);
153         if (n < 0) {
154             System.out.println("Got negative number " + n);
155         }
156     }
157 
checkBiggerThanZero(int i)158     private static void checkBiggerThanZero(int i) throws Exception {
159         if (i <= 0) {
160             System.out.println("Got zero or smaller  " + i);
161         }
162     }
163 
checkZero(int i)164     private static void checkZero(int i) throws Exception {
165         if (i != 0) {
166             System.out.println("Got non-zero result after reset " + i);
167         }
168     }
169 
checkHistogram(String s)170     private static void checkHistogram(String s) throws Exception {
171         if (s == null || s.length() == 0) {
172             System.out.println("Got null or empty string");
173             return;
174         }
175         String[] buckets = s.split(",");
176         long last_key = 0;
177         for (int i = 0; i < buckets.length; ++i) {
178             String bucket = buckets[i];
179             if (bucket.length() == 0) {
180                 System.out.println("Got empty bucket");
181                 continue;
182             }
183             String[] kv = bucket.split(":");
184             if (kv.length != 2 || kv[0].length() == 0 || kv[1].length() == 0) {
185                 System.out.println("Got bad bucket " + bucket);
186                 continue;
187             }
188             long key = Long.parseLong(kv[0]);
189             long value = Long.parseLong(kv[1]);
190             if (key < 0 || value < 0) {
191                 System.out.println("Got negative key or value " + bucket);
192                 continue;
193             }
194             if (key < last_key) {
195                 System.out.println("Got decreasing key " + bucket);
196                 continue;
197             }
198             last_key = key;
199         }
200     }
201 
testRuntimeStat()202     private static void testRuntimeStat() throws Exception {
203         // Invoke at least one GC and wait for 20 seconds or so so we get at
204         // least one bucket in the histograms.
205         for (int i = 0; i < 20; ++i) {
206           Runtime.getRuntime().gc();
207           Thread.sleep(1000L);
208         }
209         String gc_count = VMDebug.getRuntimeStat("art.gc.gc-count");
210         String gc_time = VMDebug.getRuntimeStat("art.gc.gc-time");
211         String bytes_allocated = VMDebug.getRuntimeStat("art.gc.bytes-allocated");
212         String bytes_freed = VMDebug.getRuntimeStat("art.gc.bytes-freed");
213         String blocking_gc_count = VMDebug.getRuntimeStat("art.gc.blocking-gc-count");
214         String blocking_gc_time = VMDebug.getRuntimeStat("art.gc.blocking-gc-time");
215         String gc_count_rate_histogram = VMDebug.getRuntimeStat("art.gc.gc-count-rate-histogram");
216         String blocking_gc_count_rate_histogram =
217             VMDebug.getRuntimeStat("art.gc.blocking-gc-count-rate-histogram");
218         checkNumber(gc_count);
219         checkNumber(gc_time);
220         checkNumber(bytes_allocated);
221         checkNumber(bytes_freed);
222         checkNumber(blocking_gc_count);
223         checkNumber(blocking_gc_time);
224         checkHistogram(gc_count_rate_histogram);
225         checkHistogram(blocking_gc_count_rate_histogram);
226     }
227 
testRuntimeStats()228     private static void testRuntimeStats() throws Exception {
229         // Invoke at least one GC and wait for 20 seconds or so so we get at
230         // least one bucket in the histograms.
231         for (int i = 0; i < 20; ++i) {
232           Runtime.getRuntime().gc();
233           Thread.sleep(1000L);
234         }
235         Map<String, String> map = VMDebug.getRuntimeStats();
236         String gc_count = map.get("art.gc.gc-count");
237         String gc_time = map.get("art.gc.gc-time");
238         String bytes_allocated = map.get("art.gc.bytes-allocated");
239         String bytes_freed = map.get("art.gc.bytes-freed");
240         String blocking_gc_count = map.get("art.gc.blocking-gc-count");
241         String blocking_gc_time = map.get("art.gc.blocking-gc-time");
242         String gc_count_rate_histogram = map.get("art.gc.gc-count-rate-histogram");
243         String blocking_gc_count_rate_histogram =
244             map.get("art.gc.blocking-gc-count-rate-histogram");
245         checkNumber(gc_count);
246         checkNumber(gc_time);
247         checkNumber(bytes_allocated);
248         checkNumber(bytes_freed);
249         checkNumber(blocking_gc_count);
250         checkNumber(blocking_gc_time);
251         checkHistogram(gc_count_rate_histogram);
252         checkHistogram(blocking_gc_count_rate_histogram);
253     }
254 
255     /* constants for getAllocCount */
256     private static final int KIND_ALLOCATED_OBJECTS     = 1<<0;
257     private static final int KIND_ALLOCATED_BYTES       = 1<<1;
258     private static final int KIND_FREED_OBJECTS         = 1<<2;
259     private static final int KIND_FREED_BYTES           = 1<<3;
260     private static final int RESET_ALL       = 0xffffffff;
261 
testGetAllocCount()262     private static void testGetAllocCount() throws Exception {
263         VMDebug.startAllocCounting();
264 
265         ClassA a1 = new ClassA();
266         Object obj1 = new Object();
267         Runtime.getRuntime().gc();
268 
269         int alloc_objects = VMDebug.getAllocCount(KIND_ALLOCATED_OBJECTS);
270         int alloc_bytes = VMDebug.getAllocCount(KIND_ALLOCATED_BYTES);
271         int freed_objects = VMDebug.getAllocCount(KIND_FREED_OBJECTS);
272         int freed_bytes = VMDebug.getAllocCount(KIND_FREED_BYTES);
273         checkBiggerThanZero(alloc_objects);
274         checkBiggerThanZero(alloc_bytes);
275         checkBiggerThanZero(freed_objects);
276         checkBiggerThanZero(freed_bytes);
277 
278         VMDebug.stopAllocCounting();
279         VMDebug.resetAllocCount(RESET_ALL);
280         checkZero(VMDebug.getAllocCount(KIND_ALLOCATED_OBJECTS));
281         checkZero(VMDebug.getAllocCount(KIND_ALLOCATED_BYTES));
282         checkZero(VMDebug.getAllocCount(KIND_FREED_OBJECTS));
283         checkZero(VMDebug.getAllocCount(KIND_FREED_BYTES));
284 
285         // Even if we create new classes the count should remain 0.
286         ClassA a2 = new ClassA();
287         Object obj2 = new Object();
288 
289         checkZero(VMDebug.getAllocCount(KIND_ALLOCATED_OBJECTS));
290     }
291 
testGetVmFeatureList()292     private static void testGetVmFeatureList() throws Exception {
293         String[] feature_list = VMDebug.getVmFeatureList();
294         if (feature_list.length == 0) {
295             System.out.println("Got empty feature list");
296         }
297     }
298 
testDebuggerDetails()299     private static void testDebuggerDetails() throws Exception {
300         boolean debugger_connected = VMDebug.isDebuggerConnected();
301         boolean debugging_enabled = VMDebug.isDebuggingEnabled();
302         long last_activity = VMDebug.lastDebuggerActivity();
303         if (debugger_connected && last_activity < 0) {
304             System.out.println("Last debugging activity expected but not found");
305         }
306         if (!debugger_connected && last_activity != -1) {
307             System.out.println("Found unexpected last activity");
308         }
309         if (VMDebug.threadCpuTimeNanos() <= 0) {
310             System.out.println("Could not get CPU thread time");
311         }
312         VMDebug.dumpHprofDataDdms();
313         VMDebug.dumpReferenceTables();
314     }
315 
316     static class ClassA { }
317     static class ClassB { }
318     static class ClassC extends ClassA { }
319 
testCountInstances()320     private static void testCountInstances() throws Exception {
321         ArrayList<Object> l = new ArrayList<Object>();
322         l.add(new ClassA());
323         l.add(new ClassB());
324         l.add(new ClassA());
325         l.add(new ClassC());
326         Runtime.getRuntime().gc();
327         System.out.println("Instances of ClassA " +
328                 VMDebug.countInstancesofClass(ClassA.class, false));
329         System.out.println("Instances of ClassB " +
330                 VMDebug.countInstancesofClass(ClassB.class, false));
331         System.out.println("Instances of null " + VMDebug.countInstancesofClass(null, false));
332         System.out.println("Instances of ClassA assignable " +
333                 VMDebug.countInstancesofClass(ClassA.class, true));
334         Class<?>[] classes = new Class<?>[] {ClassA.class, ClassB.class, null};
335         long[] counts = VMDebug.countInstancesofClasses(classes, false);
336         System.out.println("Array counts " + Arrays.toString(counts));
337         counts = VMDebug.countInstancesofClasses(classes, true);
338         System.out.println("Array counts assignable " + Arrays.toString(counts));
339         int class_count = VMDebug.getLoadedClassCount();
340         checkBiggerThanZero(class_count);
341     }
342 
343     static class ClassD {
344         public int mask;
345 
ClassD(int mask)346         public ClassD(int mask) {
347             this.mask = mask;
348         }
349     }
350 
351     static class ClassE extends ClassD {
ClassE(int mask)352         public ClassE(int mask) {
353             super(mask);
354         }
355     }
356 
357     private static class VMDebug {
358         private static final Method startMethodTracingMethod;
359         private static final Method startMethodTracingDdmsMethod;
360         private static final Method stopMethodTracingMethod;
361         private static final Method getMethodTracingModeMethod;
362         private static final Method getRuntimeStatMethod;
363         private static final Method getRuntimeStatsMethod;
364         private static final Method countInstancesOfClassMethod;
365         private static final Method countInstancesOfClassesMethod;
366         private static final Method getAllocCountMethod;
367         private static final Method startAllocCountingMethod;
368         private static final Method stopAllocCountingMethod;
369         private static final Method setAllocTrackerStackDepthMethod;
370         private static final Method resetAllocCountMethod;
371         private static final Method getLoadedClassCountMethod;
372         private static final Method getVmFeatureListMethod;
373         private static final Method isDebuggerConnectedMethod;
374         private static final Method isDebuggingEnabledMethod;
375         private static final Method lastDebuggerActivityMethod;
376         private static final Method threadCpuTimeNanosMethod;
377         private static final Method dumpHprofDataDdmsMethod;
378         private static final Method dumpReferenceTablesMethod;
379         static {
380             try {
381                 Class<?> c = Class.forName("dalvik.system.VMDebug");
382                 startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class,
383                         Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE);
384                 startMethodTracingDdmsMethod = c.getDeclaredMethod("startMethodTracingDdms",
385                         Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE);
386                 stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing");
387                 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode");
388                 getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class);
389                 getRuntimeStatsMethod = c.getDeclaredMethod("getRuntimeStats");
390                 countInstancesOfClassMethod = c.getDeclaredMethod("countInstancesOfClass",
391                         Class.class, Boolean.TYPE);
392                 countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses",
393                         Class[].class, Boolean.TYPE);
394                 getAllocCountMethod = c.getDeclaredMethod("getAllocCount",
395                         Integer.TYPE);
396                 startAllocCountingMethod = c.getDeclaredMethod("startAllocCounting");
397                 stopAllocCountingMethod = c.getDeclaredMethod("stopAllocCounting");
398                 setAllocTrackerStackDepthMethod = c.getDeclaredMethod("setAllocTrackerStackDepth",
399                         Integer.TYPE);
400                 resetAllocCountMethod = c.getDeclaredMethod("resetAllocCount",
401                         Integer.TYPE);
402                 getLoadedClassCountMethod = c.getDeclaredMethod("getLoadedClassCount");
403                 getVmFeatureListMethod = c.getDeclaredMethod("getVmFeatureList");
404                 isDebuggerConnectedMethod = c.getDeclaredMethod("isDebuggerConnected");
405                 isDebuggingEnabledMethod = c.getDeclaredMethod("isDebuggingEnabled");
406                 lastDebuggerActivityMethod = c.getDeclaredMethod("lastDebuggerActivity");
407                 threadCpuTimeNanosMethod = c.getDeclaredMethod("threadCpuTimeNanos");
408                 dumpHprofDataDdmsMethod = c.getDeclaredMethod("dumpHprofDataDdms");
409                 dumpReferenceTablesMethod = c.getDeclaredMethod("dumpReferenceTables");
410             } catch (Exception e) {
411                 throw new RuntimeException(e);
412             }
413         }
414 
startMethodTracing(String filename, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)415         public static void startMethodTracing(String filename, int bufferSize, int flags,
416                 boolean samplingEnabled, int intervalUs) throws Exception {
417             startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled,
418                     intervalUs);
419         }
startMethodTracingDdms(int bufferSize, int flags, boolean samplingEnabled, int intervalUs)420         public static void startMethodTracingDdms(int bufferSize, int flags,
421                 boolean samplingEnabled, int intervalUs) throws Exception {
422             startMethodTracingDdmsMethod.invoke(null, bufferSize, flags, samplingEnabled,
423                     intervalUs);
424         }
stopMethodTracing()425         public static void stopMethodTracing() throws Exception {
426             stopMethodTracingMethod.invoke(null);
427         }
getMethodTracingMode()428         public static int getMethodTracingMode() throws Exception {
429             return (int) getMethodTracingModeMethod.invoke(null);
430         }
getRuntimeStat(String statName)431         public static String getRuntimeStat(String statName) throws Exception {
432             return (String) getRuntimeStatMethod.invoke(null, statName);
433         }
getRuntimeStats()434         public static Map<String, String> getRuntimeStats() throws Exception {
435             return (Map<String, String>) getRuntimeStatsMethod.invoke(null);
436         }
countInstancesofClass(Class<?> c, boolean assignable)437         public static long countInstancesofClass(Class<?> c, boolean assignable) throws Exception {
438             return (long) countInstancesOfClassMethod.invoke(null, new Object[]{c, assignable});
439         }
countInstancesofClasses(Class<?>[] classes, boolean assignable)440         public static long[] countInstancesofClasses(Class<?>[] classes, boolean assignable)
441                 throws Exception {
442             return (long[]) countInstancesOfClassesMethod.invoke(
443                     null, new Object[]{classes, assignable});
444         }
getAllocCount(Integer kind)445         public static int getAllocCount(Integer kind) throws Exception {
446             return (int) getAllocCountMethod.invoke(null, kind);
447         }
startAllocCounting()448         public static void startAllocCounting() throws Exception {
449             startAllocCountingMethod.invoke(null);
450         }
stopAllocCounting()451         public static void stopAllocCounting() throws Exception {
452             stopAllocCountingMethod.invoke(null);
453         }
setAllocTrackerStackDepth(Integer stackDepth)454         public static void setAllocTrackerStackDepth(Integer stackDepth) throws Exception {
455             setAllocTrackerStackDepthMethod.invoke(null, stackDepth);
456         }
resetAllocCount(Integer kind)457         public static void resetAllocCount(Integer kind) throws Exception {
458             resetAllocCountMethod.invoke(null, kind);
459         }
getLoadedClassCount()460         public static int getLoadedClassCount() throws Exception {
461             return (int) getLoadedClassCountMethod.invoke(null);
462         }
getVmFeatureList()463         public static String[] getVmFeatureList() throws Exception {
464             return (String[]) getVmFeatureListMethod.invoke(null);
465         }
isDebuggerConnected()466         public static boolean isDebuggerConnected() throws Exception {
467             return (boolean) isDebuggerConnectedMethod.invoke(null);
468         }
isDebuggingEnabled()469         public static boolean isDebuggingEnabled() throws Exception {
470             return (boolean) isDebuggingEnabledMethod.invoke(null);
471         }
lastDebuggerActivity()472         public static long lastDebuggerActivity() throws Exception {
473             return (long) lastDebuggerActivityMethod.invoke(null);
474         }
threadCpuTimeNanos()475         public static long threadCpuTimeNanos() throws Exception {
476             return (long) threadCpuTimeNanosMethod.invoke(null);
477         }
dumpHprofDataDdms()478         public static void dumpHprofDataDdms() throws Exception {
479             dumpHprofDataDdmsMethod.invoke(null);
480         }
dumpReferenceTables()481         public static void dumpReferenceTables() throws Exception {
482             dumpReferenceTablesMethod.invoke(null);
483         }
484     }
485 }
486