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