xref: /aosp_15_r20/art/test/130-hprof/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2009 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker import java.io.File;
18*795d594fSAndroid Build Coastguard Worker import java.lang.ref.WeakReference;
19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Constructor;
20*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method;
21*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.InvocationTargetException;
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker public class Main {
24*795d594fSAndroid Build Coastguard Worker     private static final int TEST_LENGTH = 100;
25*795d594fSAndroid Build Coastguard Worker 
makeArray(int i)26*795d594fSAndroid Build Coastguard Worker     private static boolean makeArray(int i) {
27*795d594fSAndroid Build Coastguard Worker         return i % 10 == 0;
28*795d594fSAndroid Build Coastguard Worker     }
29*795d594fSAndroid Build Coastguard Worker 
fillArray(Object global[], Object local[], int i)30*795d594fSAndroid Build Coastguard Worker     private static void fillArray(Object global[], Object local[], int i) {
31*795d594fSAndroid Build Coastguard Worker         // Very stupid linking.
32*795d594fSAndroid Build Coastguard Worker         local[0] = global;
33*795d594fSAndroid Build Coastguard Worker         for (int j = 1; j < local.length; j++) {
34*795d594fSAndroid Build Coastguard Worker             local[j] = global[j];
35*795d594fSAndroid Build Coastguard Worker         }
36*795d594fSAndroid Build Coastguard Worker     }
37*795d594fSAndroid Build Coastguard Worker 
allocInDifferentLoader()38*795d594fSAndroid Build Coastguard Worker     private static Object allocInDifferentLoader() throws Exception {
39*795d594fSAndroid Build Coastguard Worker         final String DEX_FILE = System.getenv("DEX_LOCATION") + "/130-hprof-ex.jar";
40*795d594fSAndroid Build Coastguard Worker         Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
41*795d594fSAndroid Build Coastguard Worker         if (pathClassLoader == null) {
42*795d594fSAndroid Build Coastguard Worker             throw new AssertionError("Couldn't find path class loader class");
43*795d594fSAndroid Build Coastguard Worker         }
44*795d594fSAndroid Build Coastguard Worker         Constructor<?> constructor =
45*795d594fSAndroid Build Coastguard Worker             pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class);
46*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader)constructor.newInstance(
47*795d594fSAndroid Build Coastguard Worker                 DEX_FILE, ClassLoader.getSystemClassLoader());
48*795d594fSAndroid Build Coastguard Worker         Class<?> allocator = loader.loadClass("Allocator");
49*795d594fSAndroid Build Coastguard Worker         return allocator.getDeclaredMethod("allocObject", null).invoke(null);
50*795d594fSAndroid Build Coastguard Worker     }
51*795d594fSAndroid Build Coastguard Worker 
createDumpAndConv()52*795d594fSAndroid Build Coastguard Worker     private static void createDumpAndConv() throws RuntimeException {
53*795d594fSAndroid Build Coastguard Worker         File dumpFile = null;
54*795d594fSAndroid Build Coastguard Worker         File convFile = null;
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker         try {
57*795d594fSAndroid Build Coastguard Worker             // Now dump the heap.
58*795d594fSAndroid Build Coastguard Worker             dumpFile = createDump();
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker             // Run hprof-conv on it.
61*795d594fSAndroid Build Coastguard Worker             convFile = getConvFile();
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker             File hprof_conv = getHprofConf();
64*795d594fSAndroid Build Coastguard Worker             try {
65*795d594fSAndroid Build Coastguard Worker                 ProcessBuilder pb = new ProcessBuilder(
66*795d594fSAndroid Build Coastguard Worker                         hprof_conv.getAbsoluteFile().toString(),
67*795d594fSAndroid Build Coastguard Worker                         dumpFile.getAbsoluteFile().toString(),
68*795d594fSAndroid Build Coastguard Worker                         convFile.getAbsoluteFile().toString());
69*795d594fSAndroid Build Coastguard Worker                 pb.redirectErrorStream(true);
70*795d594fSAndroid Build Coastguard Worker                 Process process = pb.start();
71*795d594fSAndroid Build Coastguard Worker                 int ret = process.waitFor();
72*795d594fSAndroid Build Coastguard Worker                 if (ret != 0) {
73*795d594fSAndroid Build Coastguard Worker                     throw new RuntimeException("Exited abnormally with " + ret);
74*795d594fSAndroid Build Coastguard Worker                 }
75*795d594fSAndroid Build Coastguard Worker             } catch (Exception exc) {
76*795d594fSAndroid Build Coastguard Worker                 throw new RuntimeException(exc);
77*795d594fSAndroid Build Coastguard Worker             }
78*795d594fSAndroid Build Coastguard Worker         } finally {
79*795d594fSAndroid Build Coastguard Worker             // Delete the files.
80*795d594fSAndroid Build Coastguard Worker             if (dumpFile != null) {
81*795d594fSAndroid Build Coastguard Worker                 dumpFile.delete();
82*795d594fSAndroid Build Coastguard Worker             }
83*795d594fSAndroid Build Coastguard Worker             if (convFile != null) {
84*795d594fSAndroid Build Coastguard Worker                 convFile.delete();
85*795d594fSAndroid Build Coastguard Worker             }
86*795d594fSAndroid Build Coastguard Worker         }
87*795d594fSAndroid Build Coastguard Worker     }
88*795d594fSAndroid Build Coastguard Worker 
main(String[] args)89*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
90*795d594fSAndroid Build Coastguard Worker         testBasicDump();
91*795d594fSAndroid Build Coastguard Worker         testAllocationTrackingAndClassUnloading();
92*795d594fSAndroid Build Coastguard Worker         testGcAndDump();
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker 
testBasicDump()95*795d594fSAndroid Build Coastguard Worker     private static void testBasicDump() throws Exception {
96*795d594fSAndroid Build Coastguard Worker         // Create some data.
97*795d594fSAndroid Build Coastguard Worker         Object data[] = new Object[TEST_LENGTH];
98*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < data.length; i++) {
99*795d594fSAndroid Build Coastguard Worker             if (makeArray(i)) {
100*795d594fSAndroid Build Coastguard Worker                 data[i] = new Object[TEST_LENGTH];
101*795d594fSAndroid Build Coastguard Worker             } else {
102*795d594fSAndroid Build Coastguard Worker                 data[i] = String.valueOf(i);
103*795d594fSAndroid Build Coastguard Worker             }
104*795d594fSAndroid Build Coastguard Worker         }
105*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < data.length; i++) {
106*795d594fSAndroid Build Coastguard Worker             if (makeArray(i)) {
107*795d594fSAndroid Build Coastguard Worker                 Object data2[] = (Object[]) data[i];
108*795d594fSAndroid Build Coastguard Worker                 fillArray(data, data2, i);
109*795d594fSAndroid Build Coastguard Worker             }
110*795d594fSAndroid Build Coastguard Worker         }
111*795d594fSAndroid Build Coastguard Worker         System.out.println("Generated data.");
112*795d594fSAndroid Build Coastguard Worker         createDumpAndConv();
113*795d594fSAndroid Build Coastguard Worker     }
114*795d594fSAndroid Build Coastguard Worker 
testAllocationTrackingAndClassUnloading()115*795d594fSAndroid Build Coastguard Worker     private static void testAllocationTrackingAndClassUnloading() throws Exception {
116*795d594fSAndroid Build Coastguard Worker         Class<?> klass = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
117*795d594fSAndroid Build Coastguard Worker         if (klass == null) {
118*795d594fSAndroid Build Coastguard Worker             throw new AssertionError("Couldn't find path class loader class");
119*795d594fSAndroid Build Coastguard Worker         }
120*795d594fSAndroid Build Coastguard Worker         Method enableMethod = klass.getDeclaredMethod("setRecentAllocationsTrackingEnabled",
121*795d594fSAndroid Build Coastguard Worker             boolean.class);
122*795d594fSAndroid Build Coastguard Worker         if (enableMethod == null) {
123*795d594fSAndroid Build Coastguard Worker             throw new AssertionError("Couldn't find setRecentAllocationsTrackingEnabled method");
124*795d594fSAndroid Build Coastguard Worker         }
125*795d594fSAndroid Build Coastguard Worker         enableMethod.invoke(null, true);
126*795d594fSAndroid Build Coastguard Worker         Object o = allocInDifferentLoader();
127*795d594fSAndroid Build Coastguard Worker         // Run GC to cause class unloading.
128*795d594fSAndroid Build Coastguard Worker         Runtime.getRuntime().gc();
129*795d594fSAndroid Build Coastguard Worker         createDumpAndConv();
130*795d594fSAndroid Build Coastguard Worker         // TODO: Somehow check contents of hprof file.
131*795d594fSAndroid Build Coastguard Worker         enableMethod.invoke(null, false);
132*795d594fSAndroid Build Coastguard Worker     }
133*795d594fSAndroid Build Coastguard Worker 
testGcAndDump()134*795d594fSAndroid Build Coastguard Worker     private static void testGcAndDump() throws Exception {
135*795d594fSAndroid Build Coastguard Worker         Allocator allocator = new Allocator();
136*795d594fSAndroid Build Coastguard Worker         Dumper dumper = new Dumper(allocator);
137*795d594fSAndroid Build Coastguard Worker         allocator.start();
138*795d594fSAndroid Build Coastguard Worker         dumper.start();
139*795d594fSAndroid Build Coastguard Worker         try {
140*795d594fSAndroid Build Coastguard Worker             allocator.join();
141*795d594fSAndroid Build Coastguard Worker             dumper.join();
142*795d594fSAndroid Build Coastguard Worker         } catch (InterruptedException e) {
143*795d594fSAndroid Build Coastguard Worker             System.out.println("join interrupted");
144*795d594fSAndroid Build Coastguard Worker         }
145*795d594fSAndroid Build Coastguard Worker     }
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker     private static class Allocator extends Thread {
148*795d594fSAndroid Build Coastguard Worker         private static int ARRAY_SIZE = 1024;
149*795d594fSAndroid Build Coastguard Worker         public volatile boolean running = true;
run()150*795d594fSAndroid Build Coastguard Worker         public void run() {
151*795d594fSAndroid Build Coastguard Worker             Object[] array = new Object[ARRAY_SIZE];
152*795d594fSAndroid Build Coastguard Worker             int i = 0;
153*795d594fSAndroid Build Coastguard Worker             while (running) {
154*795d594fSAndroid Build Coastguard Worker                 array[i] = new byte[1024];
155*795d594fSAndroid Build Coastguard Worker                 if (i % ARRAY_SIZE == 0) {
156*795d594fSAndroid Build Coastguard Worker                     Main.sleep(100L);
157*795d594fSAndroid Build Coastguard Worker                 }
158*795d594fSAndroid Build Coastguard Worker                 i = (i + 1) % ARRAY_SIZE;
159*795d594fSAndroid Build Coastguard Worker             }
160*795d594fSAndroid Build Coastguard Worker         }
161*795d594fSAndroid Build Coastguard Worker     }
162*795d594fSAndroid Build Coastguard Worker 
163*795d594fSAndroid Build Coastguard Worker     private static class Dumper extends Thread {
Dumper(Allocator allocator)164*795d594fSAndroid Build Coastguard Worker         Dumper(Allocator allocator) {
165*795d594fSAndroid Build Coastguard Worker             this.allocator = allocator;
166*795d594fSAndroid Build Coastguard Worker         }
167*795d594fSAndroid Build Coastguard Worker         Allocator allocator;
run()168*795d594fSAndroid Build Coastguard Worker         public void run() {
169*795d594fSAndroid Build Coastguard Worker             for (int i = 0; i < 5; ++i) {
170*795d594fSAndroid Build Coastguard Worker                 Main.sleep(1000L);
171*795d594fSAndroid Build Coastguard Worker                 createDumpAndConv();
172*795d594fSAndroid Build Coastguard Worker             }
173*795d594fSAndroid Build Coastguard Worker             allocator.running = false;
174*795d594fSAndroid Build Coastguard Worker         }
175*795d594fSAndroid Build Coastguard Worker     }
176*795d594fSAndroid Build Coastguard Worker 
sleep(long ms)177*795d594fSAndroid Build Coastguard Worker     public static void sleep(long ms) {
178*795d594fSAndroid Build Coastguard Worker         try {
179*795d594fSAndroid Build Coastguard Worker             Thread.sleep(ms);
180*795d594fSAndroid Build Coastguard Worker         } catch (InterruptedException e) {
181*795d594fSAndroid Build Coastguard Worker             System.out.println("sleep interrupted");
182*795d594fSAndroid Build Coastguard Worker         }
183*795d594fSAndroid Build Coastguard Worker     }
184*795d594fSAndroid Build Coastguard Worker 
getHprofConf()185*795d594fSAndroid Build Coastguard Worker     private static File getHprofConf() {
186*795d594fSAndroid Build Coastguard Worker         // Use the java.library.path. It points to the lib directory.
187*795d594fSAndroid Build Coastguard Worker         File libDir = new File(System.getProperty("java.library.path").split(":")[0]);
188*795d594fSAndroid Build Coastguard Worker         return new File(new File(libDir.getParentFile(), "bin"), "hprof-conv");
189*795d594fSAndroid Build Coastguard Worker     }
190*795d594fSAndroid Build Coastguard Worker 
createDump()191*795d594fSAndroid Build Coastguard Worker     private static File createDump() {
192*795d594fSAndroid Build Coastguard Worker         java.lang.reflect.Method dumpHprofDataMethod = getDumpHprofDataMethod();
193*795d594fSAndroid Build Coastguard Worker         if (dumpHprofDataMethod != null) {
194*795d594fSAndroid Build Coastguard Worker             File f = getDumpFile();
195*795d594fSAndroid Build Coastguard Worker             try {
196*795d594fSAndroid Build Coastguard Worker                 dumpHprofDataMethod.invoke(null, f.getAbsoluteFile().toString());
197*795d594fSAndroid Build Coastguard Worker                 return f;
198*795d594fSAndroid Build Coastguard Worker             } catch (Exception exc) {
199*795d594fSAndroid Build Coastguard Worker                 exc.printStackTrace(System.out);
200*795d594fSAndroid Build Coastguard Worker             }
201*795d594fSAndroid Build Coastguard Worker         } else {
202*795d594fSAndroid Build Coastguard Worker             System.out.println("Could not find dump method!");
203*795d594fSAndroid Build Coastguard Worker         }
204*795d594fSAndroid Build Coastguard Worker         return null;
205*795d594fSAndroid Build Coastguard Worker     }
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker     /**
208*795d594fSAndroid Build Coastguard Worker      * Finds VMDebug.dumpHprofData() through reflection.  In the reference
209*795d594fSAndroid Build Coastguard Worker      * implementation this will not be available.
210*795d594fSAndroid Build Coastguard Worker      *
211*795d594fSAndroid Build Coastguard Worker      * @return the reflection object, or null if the method can't be found
212*795d594fSAndroid Build Coastguard Worker      */
getDumpHprofDataMethod()213*795d594fSAndroid Build Coastguard Worker     private static Method getDumpHprofDataMethod() {
214*795d594fSAndroid Build Coastguard Worker         ClassLoader myLoader = Main.class.getClassLoader();
215*795d594fSAndroid Build Coastguard Worker         Class<?> vmdClass;
216*795d594fSAndroid Build Coastguard Worker         try {
217*795d594fSAndroid Build Coastguard Worker             vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
218*795d594fSAndroid Build Coastguard Worker         } catch (ClassNotFoundException cnfe) {
219*795d594fSAndroid Build Coastguard Worker             return null;
220*795d594fSAndroid Build Coastguard Worker         }
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker         Method meth;
223*795d594fSAndroid Build Coastguard Worker         try {
224*795d594fSAndroid Build Coastguard Worker             meth = vmdClass.getMethod("dumpHprofData", String.class);
225*795d594fSAndroid Build Coastguard Worker         } catch (NoSuchMethodException nsme) {
226*795d594fSAndroid Build Coastguard Worker             System.out.println("Found VMDebug but not dumpHprofData method");
227*795d594fSAndroid Build Coastguard Worker             return null;
228*795d594fSAndroid Build Coastguard Worker         }
229*795d594fSAndroid Build Coastguard Worker 
230*795d594fSAndroid Build Coastguard Worker         return meth;
231*795d594fSAndroid Build Coastguard Worker     }
232*795d594fSAndroid Build Coastguard Worker 
getDumpFile()233*795d594fSAndroid Build Coastguard Worker     private static File getDumpFile() {
234*795d594fSAndroid Build Coastguard Worker         try {
235*795d594fSAndroid Build Coastguard Worker             return File.createTempFile("test-130-hprof", "dump");
236*795d594fSAndroid Build Coastguard Worker         } catch (Exception exc) {
237*795d594fSAndroid Build Coastguard Worker             return null;
238*795d594fSAndroid Build Coastguard Worker         }
239*795d594fSAndroid Build Coastguard Worker     }
240*795d594fSAndroid Build Coastguard Worker 
getConvFile()241*795d594fSAndroid Build Coastguard Worker     private static File getConvFile() {
242*795d594fSAndroid Build Coastguard Worker         try {
243*795d594fSAndroid Build Coastguard Worker             return File.createTempFile("test-130-hprof", "conv");
244*795d594fSAndroid Build Coastguard Worker         } catch (Exception exc) {
245*795d594fSAndroid Build Coastguard Worker             return null;
246*795d594fSAndroid Build Coastguard Worker         }
247*795d594fSAndroid Build Coastguard Worker     }
248*795d594fSAndroid Build Coastguard Worker }
249