1/*
2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug     6173675
27 * @summary Basic test of ThreadMXBean.getThreadAllocatedBytes
28 * @author  Paul Hohensee
29 */
30
31import java.lang.management.*;
32
33public class ThreadAllocatedMemory {
34    private static com.sun.management.ThreadMXBean mbean =
35        (com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean();
36    private static boolean testFailed = false;
37    private static boolean done = false;
38    private static boolean done1 = false;
39    private static Object obj = new Object();
40    private static final int NUM_THREADS = 10;
41    private static Thread[] threads = new Thread[NUM_THREADS];
42    private static long[] sizes = new long[NUM_THREADS];
43
44    public static void main(String[] argv)
45        throws Exception {
46
47        if (!mbean.isThreadAllocatedMemorySupported()) {
48            return;
49        }
50
51        // disable allocated memory measurement
52        if (mbean.isThreadAllocatedMemoryEnabled()) {
53            mbean.setThreadAllocatedMemoryEnabled(false);
54        }
55
56        if (mbean.isThreadAllocatedMemoryEnabled()) {
57            throw new RuntimeException(
58                "ThreadAllocatedMemory is expected to be disabled");
59        }
60
61        Thread curThread = Thread.currentThread();
62        long id = curThread.getId();
63
64        long s = mbean.getThreadAllocatedBytes(id);
65        if (s != -1) {
66            throw new RuntimeException(
67                "Invalid ThreadAllocatedBytes returned = " +
68                s + " expected = -1");
69        }
70
71        // enable allocated memory measurement
72        if (!mbean.isThreadAllocatedMemoryEnabled()) {
73            mbean.setThreadAllocatedMemoryEnabled(true);
74        }
75
76        if (!mbean.isThreadAllocatedMemoryEnabled()) {
77            throw new RuntimeException(
78                "ThreadAllocatedMemory is expected to be enabled");
79        }
80
81        long size = mbean.getThreadAllocatedBytes(id);
82        // implementation could have started measurement when
83        // measurement was enabled, in which case size can be 0
84        if (size < 0) {
85            throw new RuntimeException(
86                "Invalid allocated bytes returned = " + size);
87        }
88
89        doit();
90
91        // Expected to be size1 >= size
92        long size1 = mbean.getThreadAllocatedBytes(id);
93        if (size1 < size) {
94            throw new RuntimeException("Allocated bytes " + size1 +
95                " expected >= " + size);
96        }
97        System.out.println(curThread.getName() +
98            " Current thread allocated bytes = " + size +
99            " allocated bytes = " + size1);
100
101
102        // start threads, wait for them to block
103        for (int i = 0; i < NUM_THREADS; i++) {
104            threads[i] = new MyThread("MyThread-" + i);
105            threads[i].start();
106        }
107
108        // threads block after doing some allocation
109        waitUntilThreadBlocked();
110
111        for (int i = 0; i < NUM_THREADS; i++) {
112            sizes[i] = mbean.getThreadAllocatedBytes(threads[i].getId());
113        }
114
115        // let threads go and do some more allocation
116        synchronized (obj) {
117            done = true;
118            obj.notifyAll();
119        }
120
121        // wait for threads to get going again.  we don't care if we
122        // catch them in mid-execution or if some of them haven't
123        // restarted after we're done sleeping.
124        goSleep(400);
125
126        for (int i = 0; i < NUM_THREADS; i++) {
127            long newSize = mbean.getThreadAllocatedBytes(threads[i].getId());
128            if (sizes[i] > newSize) {
129                throw new RuntimeException("TEST FAILED: " +
130                    threads[i].getName() +
131                    " previous allocated bytes = " + sizes[i] +
132                    " > current allocated bytes = " + newSize);
133            }
134            System.out.println(threads[i].getName() +
135                " Previous allocated bytes = " + sizes[i] +
136                " Current allocated bytes = " + newSize);
137        }
138
139        // let threads exit
140        synchronized (obj) {
141            done1 = true;
142            obj.notifyAll();
143        }
144
145        for (int i = 0; i < NUM_THREADS; i++) {
146            try {
147                threads[i].join();
148            } catch (InterruptedException e) {
149                System.out.println("Unexpected exception is thrown.");
150                e.printStackTrace(System.out);
151                testFailed = true;
152                break;
153            }
154        }
155        if (testFailed) {
156            throw new RuntimeException("TEST FAILED");
157        }
158
159        System.out.println("Test passed");
160    }
161
162
163    private static void goSleep(long ms) throws Exception {
164        try {
165            Thread.sleep(ms);
166        } catch (InterruptedException e) {
167            System.out.println("Unexpected exception is thrown.");
168            throw e;
169        }
170    }
171
172    private static void waitUntilThreadBlocked()
173        throws Exception {
174        int count = 0;
175        while (count != NUM_THREADS) {
176            goSleep(100);
177            count = 0;
178            for (int i = 0; i < NUM_THREADS; i++) {
179                ThreadInfo info = mbean.getThreadInfo(threads[i].getId());
180                if (info.getThreadState() == Thread.State.WAITING) {
181                    count++;
182                }
183            }
184        }
185    }
186
187    public static void doit() {
188        String tmp = "";
189        long hashCode = 0;
190        for (int counter = 0; counter < 1000; counter++) {
191            tmp += counter;
192            hashCode = tmp.hashCode();
193        }
194        System.out.println(Thread.currentThread().getName() +
195                           " hashcode: " + hashCode);
196    }
197
198    static class MyThread extends Thread {
199        public MyThread(String name) {
200            super(name);
201        }
202
203        public void run() {
204            ThreadAllocatedMemory.doit();
205
206            synchronized (obj) {
207                while (!done) {
208                    try {
209                        obj.wait();
210                    } catch (InterruptedException e) {
211                        System.out.println("Unexpected exception is thrown.");
212                        e.printStackTrace(System.out);
213                        testFailed = true;
214                        break;
215                    }
216                }
217            }
218
219            long size1 = mbean.getThreadAllocatedBytes(getId());
220            ThreadAllocatedMemory.doit();
221            long size2 = mbean.getThreadAllocatedBytes(getId());
222
223            System.out.println(getName() + ": " +
224                "ThreadAllocatedBytes  = " + size1 +
225                " ThreadAllocatedBytes  = " + size2);
226
227            if (size1 > size2) {
228                throw new RuntimeException("TEST FAILED: " + getName() +
229                    " ThreadAllocatedBytes = " + size1 +
230                    " > ThreadAllocatedBytes = " + size2);
231            }
232
233            synchronized (obj) {
234                while (!done1) {
235                    try {
236                        obj.wait();
237                    } catch (InterruptedException e) {
238                        System.out.println("Unexpected exception is thrown.");
239                        e.printStackTrace(System.out);
240                        testFailed = true;
241                        break;
242                    }
243                }
244            }
245        }
246    }
247}
248