1 /* 2 * Copyright (C) 2015 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.concurrent.ConcurrentSkipListMap; 21 import java.util.HashMap; 22 import java.util.HashSet; 23 import java.util.LinkedHashMap; 24 import java.util.LinkedHashSet; 25 import java.util.Map; 26 import java.util.Set; 27 import java.util.TreeMap; 28 import java.util.TreeSet; 29 30 public class Main { 31 private static final String TEMP_FILE_NAME_PREFIX = "test"; 32 private static final String TEMP_FILE_NAME_SUFFIX = ".trace"; 33 private static File file; 34 main(String[] args)35 public static void main(String[] args) throws Exception { 36 String name = System.getProperty("java.vm.name"); 37 if (!"Dalvik".equals(name)) { 38 System.out.println("This test is not supported on " + name); 39 return; 40 } 41 file = createTempFile(); 42 try { 43 new Main().ensureCaller(true, 0); 44 new Main().ensureCaller(false, 0); 45 } finally { 46 if (file != null) { 47 file.delete(); 48 } 49 } 50 } 51 createTempFile()52 private static File createTempFile() throws Exception { 53 try { 54 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 55 } catch (IOException e) { 56 System.setProperty("java.io.tmpdir", "/data/local/tmp"); 57 try { 58 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 59 } catch (IOException e2) { 60 System.setProperty("java.io.tmpdir", "/sdcard"); 61 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); 62 } 63 } 64 } 65 66 // We make sure 'doLoadsOfStuff' has a caller, because it is this caller that will be 67 // pushed in the side instrumentation frame. ensureCaller(boolean warmup, int invocationCount)68 public void ensureCaller(boolean warmup, int invocationCount) throws Exception { 69 doLoadsOfStuff(warmup, invocationCount); 70 } 71 72 // The number of recursive calls we are going to do in 'doLoadsOfStuff' to ensure 73 // the JIT sees it hot. 74 static final int NUMBER_OF_INVOCATIONS = 5; 75 doLoadsOfStuff(boolean warmup, int invocationCount)76 public void doLoadsOfStuff(boolean warmup, int invocationCount) throws Exception { 77 // Warmup is to make sure the JIT gets a chance to compile 'doLoadsOfStuff'. 78 if (warmup) { 79 if (invocationCount < NUMBER_OF_INVOCATIONS) { 80 doLoadsOfStuff(warmup, ++invocationCount); 81 } else { 82 // Give the JIT a chance to compiler. 83 Thread.sleep(1000); 84 } 85 } else { 86 if (invocationCount == 0) { 87 // When running the trace in trace mode, there is already a trace running. 88 if (VMDebug.getMethodTracingMode() != 0) { 89 VMDebug.stopMethodTracing(); 90 } 91 VMDebug.startMethodTracing(file.getPath(), 0, 0, false, 0); 92 } 93 fillJit(); 94 if (invocationCount < NUMBER_OF_INVOCATIONS) { 95 doLoadsOfStuff(warmup, ++invocationCount); 96 } else { 97 VMDebug.stopMethodTracing(); 98 } 99 } 100 } 101 102 // This method creates enough profiling data to fill the code cache and trigger 103 // a collection in debug mode (at the time of the test 10KB of data space). We 104 // used to crash by not looking at the instrumentation stack and deleting JIT code 105 // that will be later restored by the instrumentation. fillJit()106 public static void fillJit() throws Exception { 107 Map map = new HashMap(); 108 map.put("foo", "bar"); 109 map.clear(); 110 map.containsKey("foo"); 111 map.containsValue("foo"); 112 map.entrySet(); 113 map.equals(map); 114 map.hashCode(); 115 map.isEmpty(); 116 map.keySet(); 117 map.putAll(map); 118 map.remove("foo"); 119 map.size(); 120 map.put("bar", "foo"); 121 map.values(); 122 123 map = new LinkedHashMap(); 124 map.put("foo", "bar"); 125 map.clear(); 126 map.containsKey("foo"); 127 map.containsValue("foo"); 128 map.entrySet(); 129 map.equals(map); 130 map.hashCode(); 131 map.isEmpty(); 132 map.keySet(); 133 map.putAll(map); 134 map.remove("foo"); 135 map.size(); 136 map.put("bar", "foo"); 137 map.values(); 138 139 map = new TreeMap(); 140 map.put("foo", "bar"); 141 map.clear(); 142 map.containsKey("foo"); 143 map.containsValue("foo"); 144 map.entrySet(); 145 map.equals(map); 146 map.hashCode(); 147 map.isEmpty(); 148 map.keySet(); 149 map.putAll(map); 150 map.remove("foo"); 151 map.size(); 152 map.put("bar", "foo"); 153 map.values(); 154 155 map = new ConcurrentSkipListMap(); 156 map.put("foo", "bar"); 157 map.clear(); 158 map.containsKey("foo"); 159 map.containsValue("foo"); 160 map.entrySet(); 161 map.equals(map); 162 map.hashCode(); 163 map.isEmpty(); 164 map.keySet(); 165 map.putAll(map); 166 map.remove("foo"); 167 map.size(); 168 map.put("bar", "foo"); 169 map.values(); 170 171 Set set = new HashSet(); 172 set.add("foo"); 173 set.addAll(set); 174 set.clear(); 175 set.contains("foo"); 176 set.containsAll(set); 177 set.equals(set); 178 set.hashCode(); 179 set.isEmpty(); 180 set.iterator(); 181 set.remove("foo"); 182 set.removeAll(set); 183 set.retainAll(set); 184 set.size(); 185 set.add("foo"); 186 set.toArray(); 187 188 set = new LinkedHashSet(); 189 set.add("foo"); 190 set.addAll(set); 191 set.clear(); 192 set.contains("foo"); 193 set.containsAll(set); 194 set.equals(set); 195 set.hashCode(); 196 set.isEmpty(); 197 set.iterator(); 198 set.remove("foo"); 199 set.removeAll(set); 200 set.retainAll(set); 201 set.size(); 202 set.add("foo"); 203 set.toArray(); 204 205 set = new TreeSet(); 206 set.add("foo"); 207 set.addAll(set); 208 set.clear(); 209 set.contains("foo"); 210 set.containsAll(set); 211 set.equals(set); 212 set.hashCode(); 213 set.isEmpty(); 214 set.iterator(); 215 set.remove("foo"); 216 set.removeAll(set); 217 set.retainAll(set); 218 set.size(); 219 set.add("foo"); 220 set.toArray(); 221 } 222 223 private static class VMDebug { 224 private static final Method startMethodTracingMethod; 225 private static final Method stopMethodTracingMethod; 226 private static final Method getMethodTracingModeMethod; 227 static { 228 try { 229 Class<?> c = Class.forName("dalvik.system.VMDebug"); 230 startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class, 231 Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE); 232 stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing"); 233 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode"); 234 } catch (Exception e) { 235 throw new RuntimeException(e); 236 } 237 } 238 startMethodTracing(String filename, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)239 public static void startMethodTracing(String filename, int bufferSize, int flags, 240 boolean samplingEnabled, int intervalUs) throws Exception { 241 startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled, 242 intervalUs); 243 } stopMethodTracing()244 public static void stopMethodTracing() throws Exception { 245 stopMethodTracingMethod.invoke(null); 246 } getMethodTracingMode()247 public static int getMethodTracingMode() throws Exception { 248 return (int) getMethodTracingModeMethod.invoke(null); 249 } 250 } 251 } 252