1 /* 2 * Copyright (c) 2011, 2019, 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 31 import java.lang.management.*; 32 33 public 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 volatile boolean done = false; 38 private static volatile 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 82 // Test current thread two ways 83 84 85 // First way, getCurrentThreadAllocatedBytes 86 87 long size = mbean.getCurrentThreadAllocatedBytes(); 88 // implementation could have started measurement when 89 // measurement was enabled, in which case size can be 0 90 if (size < 0) { 91 throw new RuntimeException( 92 "Invalid allocated bytes returned = " + size); 93 } 94 95 doit(); 96 97 // Expected to be size1 >= size 98 long size1 = mbean.getThreadAllocatedBytes(id); 99 if (size1 < size) { 100 throw new RuntimeException("Allocated bytes " + size1 + 101 " expected >= " + size); 102 } 103 System.out.println(curThread.getName() + 104 " Previous allocated bytes = " + size + 105 " Current allocated bytes = " + size1); 106 107 108 // Second way, getThreadAllocatedBytes 109 110 size = mbean.getThreadAllocatedBytes(id); 111 // implementation could have started measurement when 112 // measurement was enabled, in which case size can be 0 113 if (size < 0) { 114 throw new RuntimeException( 115 "Invalid allocated bytes returned = " + size); 116 } 117 118 doit(); 119 120 // Expected to be size1 >= size 121 size1 = mbean.getThreadAllocatedBytes(id); 122 if (size1 < size) { 123 throw new RuntimeException("Allocated bytes " + size1 + 124 " expected >= " + size); 125 } 126 System.out.println(curThread.getName() + 127 " Previous allocated bytes = " + size + 128 " Current allocated bytes = " + size1); 129 130 131 // Test a single thread that isn't ourself 132 133 // Start one thread, wait for it to block 134 // after doing some allocation 135 done = false; done1 = false; 136 curThread = new MyThread("MyThread"); 137 curThread.start(); 138 id = curThread.getId(); 139 waitUntilThreadBlocked(curThread); 140 size = mbean.getThreadAllocatedBytes(id); 141 142 // let thread go to do some more allocation 143 synchronized (obj) { 144 done = true; 145 obj.notifyAll(); 146 } 147 148 // wait for thread to get going again and sample it 149 goSleep(400); 150 size1 = mbean.getThreadAllocatedBytes(id); 151 if (size > size1) { 152 throw new RuntimeException( 153 curThread.getName() + 154 " previous allocated bytes = " + size + 155 " > current allocated bytes = " + size1); 156 } 157 System.out.println(curThread.getName() + 158 " Previous allocated bytes = " + size + 159 " Current allocated bytes = " + size1); 160 161 // let thread exit 162 synchronized (obj) { 163 done1 = true; 164 obj.notifyAll(); 165 } 166 167 try { 168 curThread.join(); 169 } catch (InterruptedException e) { 170 System.out.println("Unexpected exception is thrown."); 171 e.printStackTrace(System.out); 172 testFailed = true; 173 } 174 if (testFailed) { 175 throw new RuntimeException("TEST FAILED"); 176 } 177 178 179 // Test many threads 180 181 // start threads, wait for them to block 182 done = false; done1 = false; 183 for (int i = 0; i < NUM_THREADS; i++) { 184 threads[i] = new MyThread("MyThread-" + i); 185 threads[i].start(); 186 } 187 188 // threads block after doing some allocation 189 waitUntilThreadsBlocked(); 190 191 for (int i = 0; i < NUM_THREADS; i++) { 192 sizes[i] = mbean.getThreadAllocatedBytes(threads[i].getId()); 193 } 194 195 // let threads go and do some more allocation 196 synchronized (obj) { 197 done = true; 198 obj.notifyAll(); 199 } 200 201 // wait for threads to get going again. we don't care if we 202 // catch them in mid-execution or if some of them haven't 203 // restarted after we're done sleeping. 204 goSleep(400); 205 206 for (int i = 0; i < NUM_THREADS; i++) { 207 long newSize = mbean.getThreadAllocatedBytes(threads[i].getId()); 208 if (sizes[i] > newSize) { 209 throw new RuntimeException( 210 threads[i].getName() + 211 " previous allocated bytes = " + sizes[i] + 212 " > current allocated bytes = " + newSize); 213 } 214 System.out.println(threads[i].getName() + 215 " Previous allocated bytes = " + sizes[i] + 216 " Current allocated bytes = " + newSize); 217 } 218 219 // let threads exit 220 synchronized (obj) { 221 done1 = true; 222 obj.notifyAll(); 223 } 224 225 for (int i = 0; i < NUM_THREADS; i++) { 226 try { 227 threads[i].join(); 228 } catch (InterruptedException e) { 229 System.out.println("Unexpected exception is thrown."); 230 e.printStackTrace(System.out); 231 testFailed = true; 232 break; 233 } 234 } 235 if (testFailed) { 236 throw new RuntimeException("TEST FAILED"); 237 } 238 239 240 System.out.println("Test passed"); 241 } 242 243 244 private static void goSleep(long ms) throws Exception { 245 try { 246 Thread.sleep(ms); 247 } catch (InterruptedException e) { 248 System.out.println("Unexpected exception is thrown."); 249 throw e; 250 } 251 } 252 253 private static void waitUntilThreadBlocked(Thread thread) 254 throws Exception { 255 while (true) { 256 goSleep(100); 257 ThreadInfo info = mbean.getThreadInfo(thread.getId()); 258 if (info.getThreadState() == Thread.State.WAITING) { 259 break; 260 } 261 } 262 } 263 264 private static void waitUntilThreadsBlocked() 265 throws Exception { 266 int count = 0; 267 while (count != NUM_THREADS) { 268 goSleep(100); 269 count = 0; 270 for (int i = 0; i < NUM_THREADS; i++) { 271 ThreadInfo info = mbean.getThreadInfo(threads[i].getId()); 272 if (info.getThreadState() == Thread.State.WAITING) { 273 count++; 274 } 275 } 276 } 277 } 278 279 public static void doit() { 280 String tmp = ""; 281 long hashCode = 0; 282 for (int counter = 0; counter < 1000; counter++) { 283 tmp += counter; 284 hashCode = tmp.hashCode(); 285 } 286 System.out.println(Thread.currentThread().getName() + 287 " hashcode: " + hashCode); 288 } 289 290 static class MyThread extends Thread { 291 public MyThread(String name) { 292 super(name); 293 } 294 295 public void run() { 296 ThreadAllocatedMemory.doit(); 297 298 synchronized (obj) { 299 while (!done) { 300 try { 301 obj.wait(); 302 } catch (InterruptedException e) { 303 System.out.println("Unexpected exception is thrown."); 304 e.printStackTrace(System.out); 305 testFailed = true; 306 break; 307 } 308 } 309 } 310 311 long size1 = mbean.getThreadAllocatedBytes(getId()); 312 ThreadAllocatedMemory.doit(); 313 long size2 = mbean.getThreadAllocatedBytes(getId()); 314 315 System.out.println(getName() + ": " + 316 "ThreadAllocatedBytes = " + size1 + 317 " ThreadAllocatedBytes = " + size2); 318 319 if (size1 > size2) { 320 throw new RuntimeException(getName() + 321 " ThreadAllocatedBytes = " + size1 + 322 " > ThreadAllocatedBytes = " + size2); 323 } 324 325 synchronized (obj) { 326 while (!done1) { 327 try { 328 obj.wait(); 329 } catch (InterruptedException e) { 330 System.out.println("Unexpected exception is thrown."); 331 e.printStackTrace(System.out); 332 testFailed = true; 333 break; 334 } 335 } 336 } 337 } 338 } 339 }