blob: 1be5765155b6e3f702dc61c6c2d245a55734dc05 [file] [log] [blame]
Jeff Haod063d912014-09-08 09:38:18 -07001/*
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
17import java.io.File;
18import java.io.IOException;
19import java.lang.reflect.Method;
Mathieu Chartierf1820852015-07-10 13:19:51 -070020import java.util.Arrays;
21import java.util.ArrayList;
Hiroshi Yamauchia1c9f012015-04-02 10:18:12 -070022import java.util.Map;
Jeff Haod063d912014-09-08 09:38:18 -070023
24public class Main {
Sebastien Hertzef3b1772015-06-30 13:57:39 +020025 private static final String TEMP_FILE_NAME_PREFIX = "test";
26 private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
27
Jeff Haod063d912014-09-08 09:38:18 -070028 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();
Mathieu Chartierf1820852015-07-10 13:19:51 -070035 testCountInstances();
Hiroshi Yamauchia1c9f012015-04-02 10:18:12 -070036 testRuntimeStat();
Mathieu Chartierf1820852015-07-10 13:19:51 -070037 testRuntimeStats();
Jeff Haod063d912014-09-08 09:38:18 -070038 }
39
Andreas Gampe74035032015-01-27 16:12:08 -080040 private static File createTempFile() throws Exception {
Jeff Hao8cf89c42014-09-09 13:07:59 -070041 try {
Sebastien Hertzef3b1772015-06-30 13:57:39 +020042 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
Jeff Hao8cf89c42014-09-09 13:07:59 -070043 } catch (IOException e) {
Andreas Gampe74035032015-01-27 16:12:08 -080044 System.setProperty("java.io.tmpdir", "/data/local/tmp");
45 try {
Sebastien Hertzef3b1772015-06-30 13:57:39 +020046 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
Andreas Gampe74035032015-01-27 16:12:08 -080047 } catch (IOException e2) {
48 System.setProperty("java.io.tmpdir", "/sdcard");
Sebastien Hertzef3b1772015-06-30 13:57:39 +020049 return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
Andreas Gampe74035032015-01-27 16:12:08 -080050 }
Jeff Haod063d912014-09-08 09:38:18 -070051 }
Andreas Gampe74035032015-01-27 16:12:08 -080052 }
53
54 private static void testMethodTracing() throws Exception {
Sebastien Hertzef3b1772015-06-30 13:57:39 +020055 File tempFile = null;
56 try {
57 tempFile = createTempFile();
58 testMethodTracingToFile(tempFile);
59 } finally {
60 if (tempFile != null) {
61 tempFile.delete();
62 }
63 }
64 }
65
66 private static void testMethodTracingToFile(File tempFile) throws Exception {
Jeff Hao8cf89c42014-09-09 13:07:59 -070067 String tempFileName = tempFile.getPath();
Jeff Haod063d912014-09-08 09:38:18 -070068
Jeff Haocbe15be2014-09-08 15:32:39 -070069 if (VMDebug.getMethodTracingMode() != 0) {
70 VMDebug.stopMethodTracing();
71 }
72
Jeff Haod063d912014-09-08 09:38:18 -070073 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
Hiroshi Yamauchia1c9f012015-04-02 10:18:12 -0700131 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.valueOf(s);
137 if (n < 0) {
138 System.out.println("Got negative number " + n);
139 }
140 }
141
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.valueOf(kv[0]);
161 long value = Long.valueOf(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
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
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
Mathieu Chartierf1820852015-07-10 13:19:51 -0700227 static class ClassA { }
228 static class ClassB { }
229 static class ClassC extends ClassA { }
230
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
Jeff Haod063d912014-09-08 09:38:18 -0700252 private static class VMDebug {
253 private static final Method startMethodTracingMethod;
254 private static final Method stopMethodTracingMethod;
255 private static final Method getMethodTracingModeMethod;
Hiroshi Yamauchia1c9f012015-04-02 10:18:12 -0700256 private static final Method getRuntimeStatMethod;
257 private static final Method getRuntimeStatsMethod;
Mathieu Chartierf1820852015-07-10 13:19:51 -0700258 private static final Method countInstancesOfClassMethod;
259 private static final Method countInstancesOfClassesMethod;
Jeff Haod063d912014-09-08 09:38:18 -0700260 static {
261 try {
262 Class c = Class.forName("dalvik.system.VMDebug");
263 startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class,
264 Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE);
265 stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing");
266 getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode");
Hiroshi Yamauchia1c9f012015-04-02 10:18:12 -0700267 getRuntimeStatMethod = c.getDeclaredMethod("getRuntimeStat", String.class);
268 getRuntimeStatsMethod = c.getDeclaredMethod("getRuntimeStats");
Mathieu Chartierf1820852015-07-10 13:19:51 -0700269 countInstancesOfClassMethod = c.getDeclaredMethod("countInstancesOfClass",
270 Class.class, Boolean.TYPE);
271 countInstancesOfClassesMethod = c.getDeclaredMethod("countInstancesOfClasses",
272 Class[].class, Boolean.TYPE);
Jeff Haod063d912014-09-08 09:38:18 -0700273 } catch (Exception e) {
274 throw new RuntimeException(e);
275 }
276 }
277
278 public static void startMethodTracing(String filename, int bufferSize, int flags,
279 boolean samplingEnabled, int intervalUs) throws Exception {
280 startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled,
281 intervalUs);
282 }
283 public static void stopMethodTracing() throws Exception {
284 stopMethodTracingMethod.invoke(null);
285 }
286 public static int getMethodTracingMode() throws Exception {
287 return (int) getMethodTracingModeMethod.invoke(null);
288 }
Hiroshi Yamauchia1c9f012015-04-02 10:18:12 -0700289 public static String getRuntimeStat(String statName) throws Exception {
290 return (String) getRuntimeStatMethod.invoke(null, statName);
291 }
292 public static Map<String, String> getRuntimeStats() throws Exception {
293 return (Map<String, String>) getRuntimeStatsMethod.invoke(null);
294 }
Mathieu Chartierf1820852015-07-10 13:19:51 -0700295 public static long countInstancesofClass(Class c, boolean assignable) throws Exception {
296 return (long) countInstancesOfClassMethod.invoke(null, new Object[]{c, assignable});
297 }
298 public static long[] countInstancesofClasses(Class[] classes, boolean assignable)
299 throws Exception {
300 return (long[]) countInstancesOfClassesMethod.invoke(
301 null, new Object[]{classes, assignable});
302 }
Jeff Haod063d912014-09-08 09:38:18 -0700303 }
304}