diff --git a/test/functional/JLM_Tests/src/org/openj9/test/java/lang/management/TestThreadMXBean.java b/test/functional/JLM_Tests/src/org/openj9/test/java/lang/management/TestThreadMXBean.java index 21f84009c78..9d2e5d4b0b8 100644 --- a/test/functional/JLM_Tests/src/org/openj9/test/java/lang/management/TestThreadMXBean.java +++ b/test/functional/JLM_Tests/src/org/openj9/test/java/lang/management/TestThreadMXBean.java @@ -36,6 +36,7 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import javax.management.Attribute; import javax.management.AttributeList; @@ -1097,6 +1098,96 @@ public final void testThreadAllocationMetricsOnCurrentThread() { AssertJUnit.assertTrue(bytes5 >= bytes4); } + private final void allocateAndWait(int allocCount, Object sync, AtomicInteger count) { + try { + ArrayList list = new ArrayList<>(); + + for (int i = 0; i < allocCount; i++) { + list.add(new Object[100]); + } + + count.getAndIncrement(); + + synchronized (sync) { + sync.wait(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + AssertJUnit.fail(e.getMessage()); + } + } + + /** + * Allocate differing amounts of objects on each thread and ensure that + * threadMXbean getThreadAllocatedBytes correctly reports the relative + * allocated amounts. + * + * @throws InterruptedException + */ + @Test + public final void testThreadAllocationMetrics() throws InterruptedException { + com.sun.management.ThreadMXBean sunTB = (com.sun.management.ThreadMXBean)tb; + + final Object sync = new Object() {}; + final AtomicInteger count = new AtomicInteger(0); + + Thread t1 = new Thread(()->{ + allocateAndWait(1000, sync, count); + }); + + Thread t2 = new Thread(()->{ + allocateAndWait(2000, sync, count); + }); + + Thread t3 = new Thread(()->{ + allocateAndWait(1, sync, count); + }); + + t1.start(); + t2.start(); + t3.start(); + + Thread.yield(); + Thread.yield(); + Thread.yield(); + + /* Wait for threads to complete allocations or 10 seconds */ + for (int i = 0; (count.get() < 3) || (i < 100); i++) { + Thread.sleep(100); + } + + if (count.get() != 3) { + AssertJUnit.fail("Threads did not complete allocations in allotted time."); + } + + /* Allocation stats are updated after a GC. */ + System.gc(); + + /* Check stats with `long getThreadAllocatedBytes(long tid)`. */ + long t1Stats = sunTB.getThreadAllocatedBytes(t1.getId()); + long t2Stats = sunTB.getThreadAllocatedBytes(t2.getId()); + long t3Stats = sunTB.getThreadAllocatedBytes(t3.getId()); + + AssertJUnit.assertTrue(t2Stats > t1Stats); + AssertJUnit.assertTrue(t1Stats > t3Stats); + + /* Check stats with `long[] getThreadAllocatedBytes(long[] tids)`. */ + long[] threadIDs = new long[] {t1.getId(), t2.getId(), t3.getId()}; + long[] threadStats = sunTB.getThreadAllocatedBytes(threadIDs); + + AssertJUnit.assertTrue(threadStats[1] > threadStats[0]); + AssertJUnit.assertTrue(threadStats[0] > threadStats[2]); + + /* Wake up threads and wait for them to terminate */ + synchronized (sync) { + sync.notifyAll(); + } + + t1.join(); + t2.join(); + t3.join(); + } + @Test public final void testGetAttributes() { AttributeList attributes = null;