1306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom/*
2306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * Copyright (C) 2014 The Android Open Source Project
3306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom *
4306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
5306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * you may not use this file except in compliance with the License.
6306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * You may obtain a copy of the License at
7306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom *
8306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
9306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom *
10306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * Unless required by applicable law or agreed to in writing, software
11306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
12306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * See the License for the specific language governing permissions and
14306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom * limitations under the License.
15306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom */
16306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
17306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstromimport java.lang.reflect.Method;
18306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstromimport java.nio.ByteBuffer;
19306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
20306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrompublic class Main {
21306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    public static void main(String[] args) throws Exception {
22306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        String name = System.getProperty("java.vm.name");
23306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        if (!"Dalvik".equals(name)) {
24306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            System.out.println("This test is not supported on " + name);
25306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            return;
26306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
27306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        testRecentAllocationTracking();
28306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    }
29306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
30306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    private static void testRecentAllocationTracking() throws Exception {
31306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Confirm empty");
32306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations empty = new Allocations(DdmVmInternal.getRecentAllocations());
33306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("empty=" + empty);
34306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
35306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Confirm enable");
36306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
37306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(true);
38306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
39306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
40306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Capture some allocations (note just this causes allocations)");
41306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations before = new Allocations(DdmVmInternal.getRecentAllocations());
42306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("before > 0=" + (before.numberOfEntries > 0));
43306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
44306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Confirm when we overflow, we don't roll over to zero. b/17392248");
45306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int overflowAllocations = 64 * 1024;  // Won't fit in unsigned 16-bit value.
46306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        for (int i = 0; i < overflowAllocations; i++) {
471ed11b9ad5512cf464cb1686640df53201fa5297Man Cao            new Object();
48306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
49306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations after = new Allocations(DdmVmInternal.getRecentAllocations());
50306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("before < overflowAllocations=" + (before.numberOfEntries < overflowAllocations));
51306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("after > before=" + (after.numberOfEntries > before.numberOfEntries));
52306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("after.numberOfEntries=" + after.numberOfEntries);
53306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
54306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Disable and confirm back to empty");
55306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(false);
56306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
57306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations reset = new Allocations(DdmVmInternal.getRecentAllocations());
58306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("reset=" + reset);
59306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
60306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Confirm we can disable twice in a row");
61306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(false);
62306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
63306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(false);
64306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
65306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
66306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Confirm we can reenable twice in a row without losing allocations");
67306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(true);
68306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
691ed11b9ad5512cf464cb1686640df53201fa5297Man Cao        for (int i = 0; i < 16 * 1024; i++) {
701ed11b9ad5512cf464cb1686640df53201fa5297Man Cao            new String("fnord");
71306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
72306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations first = new Allocations(DdmVmInternal.getRecentAllocations());
73306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(true);
74306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("status=" + DdmVmInternal.getRecentAllocationStatus());
75306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations second = new Allocations(DdmVmInternal.getRecentAllocations());
76306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("second > first =" + (second.numberOfEntries > first.numberOfEntries));
77306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
78306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("Goodbye");
79306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        DdmVmInternal.enableRecentAllocations(false);
80306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations goodbye = new Allocations(DdmVmInternal.getRecentAllocations());
81306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        System.out.println("goodbye=" + goodbye);
82306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    }
83306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
84306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    private static class Allocations {
85306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int messageHeaderLen;
86306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int entryHeaderLen;
87306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int stackFrameLen;
88306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int numberOfEntries;
89306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int offsetToStringTableFromStartOfMessage;
90306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int numberOfClassNameStrings;
91306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int numberOfMethodNameStrings;
92306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        final int numberOfSourceFileNameStrings;
93306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
94306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        Allocations(byte[] allocations) {
95306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            ByteBuffer b = ByteBuffer.wrap(allocations);
96306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            messageHeaderLen = b.get() & 0xff;
97306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            if (messageHeaderLen != 15) {
98306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                throw new IllegalArgumentException("Unexpected messageHeaderLen " + messageHeaderLen);
99306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            }
100306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            entryHeaderLen = b.get() & 0xff;
101306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            if (entryHeaderLen != 9) {
102306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                throw new IllegalArgumentException("Unexpected entryHeaderLen " + entryHeaderLen);
103306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            }
104306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            stackFrameLen = b.get() & 0xff;
105306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            if (stackFrameLen != 8) {
106306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                throw new IllegalArgumentException("Unexpected messageHeaderLen " + stackFrameLen);
107306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            }
108306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            numberOfEntries = b.getShort() & 0xffff;
109306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            offsetToStringTableFromStartOfMessage = b.getInt();
110306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            numberOfClassNameStrings = b.getShort() & 0xffff;
111306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            numberOfMethodNameStrings = b.getShort() & 0xffff;
112306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            numberOfSourceFileNameStrings = b.getShort() & 0xffff;
113306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
114306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
115306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        public String toString() {
116306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            return ("Allocations[message header len: " + messageHeaderLen +
117306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " entry header len: " + entryHeaderLen +
118306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " stack frame len: " + stackFrameLen +
119306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " number of entries: " + numberOfEntries +
120306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " offset to string table from start of message: " + offsetToStringTableFromStartOfMessage +
121306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " number of class name strings: " + numberOfClassNameStrings +
122306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " number of method name strings: " + numberOfMethodNameStrings +
123306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    " number of source file name strings: " + numberOfSourceFileNameStrings +
124306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                    "]");
125306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
126306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    }
127306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
128306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    private static class DdmVmInternal {
129306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        private static final Method enableRecentAllocationsMethod;
130306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        private static final Method getRecentAllocationStatusMethod;
131306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        private static final Method getRecentAllocationsMethod;
132306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        static {
133306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            try {
134306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                Class c = Class.forName("org.apache.harmony.dalvik.ddmc.DdmVmInternal");
135306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                enableRecentAllocationsMethod = c.getDeclaredMethod("enableRecentAllocations",
136306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                                                                    Boolean.TYPE);
137306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                getRecentAllocationStatusMethod = c.getDeclaredMethod("getRecentAllocationStatus");
138306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                getRecentAllocationsMethod = c.getDeclaredMethod("getRecentAllocations");
139306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            } catch (Exception e) {
140306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom                throw new RuntimeException(e);
141306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            }
142306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
143306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom
144306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        public static void enableRecentAllocations(boolean enable) throws Exception {
145306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            enableRecentAllocationsMethod.invoke(null, enable);
146306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
147306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        public static boolean getRecentAllocationStatus() throws Exception {
148306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            return (boolean) getRecentAllocationStatusMethod.invoke(null);
149306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
150306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        public static byte[] getRecentAllocations() throws Exception {
151306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom            return (byte[]) getRecentAllocationsMethod.invoke(null);
152306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom        }
153306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom    }
154306db81aba41eb244a4e8299cf58ac18ae9999c7Brian Carlstrom}
155