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 } 39 createTempFile()40 private static File createTempFile() throws Exception { 41 try { 42 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 43 } catch (IOException e) { 44 System.setProperty("java.io.tmpdir", "/data/local/tmp"); 45 try { 46 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 47 } catch (IOException e2) { 48 System.setProperty("java.io.tmpdir", "/sdcard"); 49 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 50 } 51 } 52 } 53 testMethodTracing()54 private static void testMethodTracing() throws Exception { 55 File tempFile = null; 56 try { 57 tempFile = createTempFile(); 58 testMethodTracingToFile(tempFile); 59 } finally { 60 if (tempFile != null) { 61 tempFile.delete(); 62 } 63 } 64 } 65 testMethodTracingToFile(File tempFile)66 private static void testMethodTracingToFile(File tempFile) throws Exception { 67 String tempFileName = tempFile.getPath(); 68 69 if (VMDebug.getMethodTracingMode() != 0) { 70 VMDebug.stopMethodTracing(); 71 } 72 73 System.out.println("Confirm enable/disable"); 74 System.out.println("status=" + VMDebug.getMethodTracingMode()); 75 VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0); 76 System.out.println("status=" + VMDebug.getMethodTracingMode()); 77 VMDebug.stopMethodTracing(); 78 System.out.println("status=" + VMDebug.getMethodTracingMode()); 79 if (tempFile.length() == 0) { 80 System.out.println("ERROR: tracing output file is empty"); 81 } 82 83 System.out.println("Confirm sampling"); 84 VMDebug.startMethodTracing(tempFileName, 0, 0, true, 1000); 85 System.out.println("status=" + VMDebug.getMethodTracingMode()); 86 VMDebug.stopMethodTracing(); 87 System.out.println("status=" + VMDebug.getMethodTracingMode()); 88 if (tempFile.length() == 0) { 89 System.out.println("ERROR: sample tracing output file is empty"); 90 } 91 92 System.out.println("Test starting when already started"); 93 VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0); 94 System.out.println("status=" + VMDebug.getMethodTracingMode()); 95 VMDebug.startMethodTracing(tempFileName, 0, 0, false, 0); 96 System.out.println("status=" + VMDebug.getMethodTracingMode()); 97 98 System.out.println("Test stopping when already stopped"); 99 VMDebug.stopMethodTracing(); 100 System.out.println("status=" + VMDebug.getMethodTracingMode()); 101 VMDebug.stopMethodTracing(); 102 System.out.println("status=" + VMDebug.getMethodTracingMode()); 103 104 System.out.println("Test tracing with empty filename"); 105 try { 106 VMDebug.startMethodTracing("", 0, 0, false, 0); 107 System.out.println("Should have thrown an exception"); 108 } catch (Exception e) { 109 System.out.println("Got expected exception"); 110 } 111 112 System.out.println("Test tracing with bogus (< 1024 && != 0) filesize"); 113 try { 114 VMDebug.startMethodTracing(tempFileName, 1000, 0, false, 0); 115 System.out.println("Should have thrown an exception"); 116 } catch (Exception e) { 117 System.out.println("Got expected exception"); 118 } 119 120 System.out.println("Test sampling with bogus (<= 0) interval"); 121 try { 122 VMDebug.startMethodTracing(tempFileName, 0, 0, true, 0); 123 System.out.println("Should have thrown an exception"); 124 } catch (Exception e) { 125 System.out.println("Got expected exception"); 126 } 127 128 tempFile.delete(); 129 } 130 checkNumber(String s)131 private static void checkNumber(String s) throws Exception { 132 if (s == null) { 133 System.out.println("Got null string"); 134 return; 135 } 136 long n = Long.parseLong(s); 137 if (n < 0) { 138 System.out.println("Got negative number " + n); 139 } 140 } 141 checkHistogram(String s)142 private static void checkHistogram(String s) throws Exception { 143 if (s == null || s.length() == 0) { 144 System.out.println("Got null or empty string"); 145 return; 146 } 147 String[] buckets = s.split(","); 148 long last_key = 0; 149 for (int i = 0; i < buckets.length; ++i) { 150 String bucket = buckets[i]; 151 if (bucket.length() == 0) { 152 System.out.println("Got empty bucket"); 153 continue; 154 } 155 String[] kv = bucket.split(":"); 156 if (kv.length != 2 || kv[0].length() == 0 || kv[1].length() == 0) { 157 System.out.println("Got bad bucket " + bucket); 158 continue; 159 } 160 long key = Long.parseLong(kv[0]); 161 long value = Long.parseLong(kv[1]); 162 if (key < 0 || value < 0) { 163 System.out.println("Got negative key or value " + bucket); 164 continue; 165 } 166 if (key < last_key) { 167 System.out.println("Got decreasing key " + bucket); 168 continue; 169 } 170 last_key = key; 171 } 172 } 173 testRuntimeStat()174 private static void testRuntimeStat() throws Exception { 175 // Invoke at least one GC and wait for 20 seconds or so so we get at 176 // least one bucket in the histograms. 177 for (int i = 0; i < 20; ++i) { 178 Runtime.getRuntime().gc(); 179 Thread.sleep(1000L); 180 } 181 String gc_count = VMDebug.getRuntimeStat("art.gc.gc-count"); 182 String gc_time = VMDebug.getRuntimeStat("art.gc.gc-time"); 183 String bytes_allocated = VMDebug.getRuntimeStat("art.gc.bytes-allocated"); 184 String bytes_freed = VMDebug.getRuntimeStat("art.gc.bytes-freed"); 185 String blocking_gc_count = VMDebug.getRuntimeStat("art.gc.blocking-gc-count"); 186 String blocking_gc_time = VMDebug.getRuntimeStat("art.gc.blocking-gc-time"); 187 String gc_count_rate_histogram = VMDebug.getRuntimeStat("art.gc.gc-count-rate-histogram"); 188 String blocking_gc_count_rate_histogram = 189 VMDebug.getRuntimeStat("art.gc.blocking-gc-count-rate-histogram"); 190 checkNumber(gc_count); 191 checkNumber(gc_time); 192 checkNumber(bytes_allocated); 193 checkNumber(bytes_freed); 194 checkNumber(blocking_gc_count); 195 checkNumber(blocking_gc_time); 196 checkHistogram(gc_count_rate_histogram); 197 checkHistogram(blocking_gc_count_rate_histogram); 198 } 199 testRuntimeStats()200 private static void testRuntimeStats() throws Exception { 201 // Invoke at least one GC and wait for 20 seconds or so so we get at 202 // least one bucket in the histograms. 203 for (int i = 0; i < 20; ++i) { 204 Runtime.getRuntime().gc(); 205 Thread.sleep(1000L); 206 } 207 Map<String, String> map = VMDebug.getRuntimeStats(); 208 String gc_count = map.get("art.gc.gc-count"); 209 String gc_time = map.get("art.gc.gc-time"); 210 String bytes_allocated = map.get("art.gc.bytes-allocated"); 211 String bytes_freed = map.get("art.gc.bytes-freed"); 212 String blocking_gc_count = map.get("art.gc.blocking-gc-count"); 213 String blocking_gc_time = map.get("art.gc.blocking-gc-time"); 214 String gc_count_rate_histogram = map.get("art.gc.gc-count-rate-histogram"); 215 String blocking_gc_count_rate_histogram = 216 map.get("art.gc.blocking-gc-count-rate-histogram"); 217 checkNumber(gc_count); 218 checkNumber(gc_time); 219 checkNumber(bytes_allocated); 220 checkNumber(bytes_freed); 221 checkNumber(blocking_gc_count); 222 checkNumber(blocking_gc_time); 223 checkHistogram(gc_count_rate_histogram); 224 checkHistogram(blocking_gc_count_rate_histogram); 225 } 226 227 static class ClassA { } 228 static class ClassB { } 229 static class ClassC extends ClassA { } 230 testCountInstances()231 private static void testCountInstances() throws Exception { 232 ArrayList<Object> l = new ArrayList<Object>(); 233 l.add(new ClassA()); 234 l.add(new ClassB()); 235 l.add(new ClassA()); 236 l.add(new ClassC()); 237 Runtime.getRuntime().gc(); 238 System.out.println("Instances of ClassA " + 239 VMDebug.countInstancesofClass(ClassA.class, false)); 240 System.out.println("Instances of ClassB " + 241 VMDebug.countInstancesofClass(ClassB.class, false)); 242 System.out.println("Instances of null " + VMDebug.countInstancesofClass(null, false)); 243 System.out.println("Instances of ClassA assignable " + 244 VMDebug.countInstancesofClass(ClassA.class, true)); 245 Class<?>[] classes = new Class<?>[] {ClassA.class, ClassB.class, null}; 246 long[] counts = VMDebug.countInstancesofClasses(classes, false); 247 System.out.println("Array counts " + Arrays.toString(counts)); 248 counts = VMDebug.countInstancesofClasses(classes, true); 249 System.out.println("Array counts assignable " + Arrays.toString(counts)); 250 } 251 252 static class ClassD { 253 public int mask; 254 ClassD(int mask)255 public ClassD(int mask) { 256 this.mask = mask; 257 } 258 } 259 260 static class ClassE extends ClassD { ClassE(int mask)261 public ClassE(int mask) { 262 super(mask); 263 } 264 } 265 266 private static class VMDebug { 267 private static final Method startMethodTracingMethod; 268 private static final Method stopMethodTracingMethod; 269 private static final Method getMethodTracingModeMethod; 270 private static final Method getRuntimeStatMethod; 271 private static final Method getRuntimeStatsMethod; 272 private static final Method countInstancesOfClassMethod; 273 private static final Method countInstancesOfClassesMethod; 274 static { 275 try { 276 Class<?> c = Class.forName("dalvik.system.VMDebug"); 277 startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, 278 Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE); 279 stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); 280 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); 281 getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class); 282 getRuntimeStatsMethod = c.getDeclaredMethod("getRuntimeStats"); 283 countInstancesOfClassMethod = c.getDeclaredMethod("countInstancesOfClass", 284 Class.class, Boolean.TYPE); 285 countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses", 286 Class[].class, Boolean.TYPE); 287 } catch (Exception e) { 288 throw new RuntimeException(e); 289 } 290 } 291 startMethodTracing(String filename, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)292 public static void startMethodTracing(String filename, int bufferSize, int flags, 293 boolean samplingEnabled, int intervalUs) throws Exception { 294 startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled, 295 intervalUs); 296 } stopMethodTracing()297 public static void stopMethodTracing() throws Exception { 298 stopMethodTracingMethod.invoke(null); 299 } getMethodTracingMode()300 public static int getMethodTracingMode() throws Exception { 301 return (int) getMethodTracingModeMethod.invoke(null); 302 } getRuntimeStat(String statName)303 public static String getRuntimeStat(String statName) throws Exception { 304 return (String) getRuntimeStatMethod.invoke(null, statName); 305 } getRuntimeStats()306 public static Map<String, String> getRuntimeStats() throws Exception { 307 return (Map<String, String>) getRuntimeStatsMethod.invoke(null); 308 } countInstancesofClass(Class<?> c, boolean assignable)309 public static long countInstancesofClass(Class<?> c, boolean assignable) throws Exception { 310 return (long) countInstancesOfClassMethod.invoke(null, new Object[]{c, assignable}); 311 } countInstancesofClasses(Class<?>[] classes, boolean assignable)312 public static long[] countInstancesofClasses(Class<?>[] classes, boolean assignable) 313 throws Exception { 314 return (long[]) countInstancesOfClassesMethod.invoke( 315 null, new Object[]{classes, assignable}); 316 } 317 } 318 } 319