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