Mercurial > hg > gc-bench
changeset 33:2302c92fc1d9
fraggers.* even better LDS targeting.
author | shade |
---|---|
date | Fri, 02 Dec 2016 14:03:29 +0100 |
parents | 7b87f91c5db9 |
children | 73d0b304ec43 |
files | src/main/java/org/openjdk/gcbench/GCBench.java src/main/java/org/openjdk/gcbench/fragger/ArrayFragger.java src/main/java/org/openjdk/gcbench/fragger/LinkedListFragger.java src/main/java/org/openjdk/gcbench/fragger/TreeFragger.java src/main/java/org/openjdk/gcbench/util/AllocProfileSupport.java |
diffstat | 5 files changed, 157 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/openjdk/gcbench/GCBench.java Fri Dec 02 12:43:28 2016 +0100 +++ b/src/main/java/org/openjdk/gcbench/GCBench.java Fri Dec 02 14:03:29 2016 +0100 @@ -242,13 +242,12 @@ Dimensions.lds(4) )); -// FIXME: Enable the test back, it runs too slow -// tests.add(new DimensionalTest(baseOpts, org.openjdk.gcbench.fragger.LinkedListFragger.class, -// "fragger.linkedlist", groupDescr + "Retains a LinkedList.", -// true, -// Dimensions.heapSize(4), -// Dimensions.lds(4) -// )); + tests.add(new DimensionalTest(baseOpts, org.openjdk.gcbench.fragger.LinkedListFragger.class, + "fragger.linkedlist", groupDescr + "Retains a LinkedList.", + true, + Dimensions.heapSize(4), + Dimensions.lds(4) + )); } {
--- a/src/main/java/org/openjdk/gcbench/fragger/ArrayFragger.java Fri Dec 02 12:43:28 2016 +0100 +++ b/src/main/java/org/openjdk/gcbench/fragger/ArrayFragger.java Fri Dec 02 14:03:29 2016 +0100 @@ -1,5 +1,6 @@ package org.openjdk.gcbench.fragger; +import org.openjdk.gcbench.util.AllocProfileSupport; import org.openjdk.gcbench.util.ratelimit.MultiTokenBucket; import org.openjdk.jmh.annotations.*; import org.openjdk.jol.info.GraphLayout; @@ -16,6 +17,8 @@ @State(Scope.Benchmark) public class ArrayFragger { + public static final int PAYLOAD_SIZE = 16384; + @Param({"1000"}) long ldsMB; @@ -28,9 +31,29 @@ MultiTokenBucket bucket; + Object[] o0; + Object[] o16; + private int getSizePerCount() { - return 4 + // array element - 16; // object + if (AllocProfileSupport.isAvailable()) { + long a1 = AllocProfileSupport.getAllocatedBytes(); + o0 = new Object[0]; + long a2 = AllocProfileSupport.getAllocatedBytes(); + o16 = new Object[16]; + for (int c = 0; c < 16; c++) { + o16[c] = new byte[PAYLOAD_SIZE]; + } + long a3 = AllocProfileSupport.getAllocatedBytes(); + + long sizeO0 = a2 - a1; + long sizeO16 = a3 - a2; + + return (int) ((sizeO16 - sizeO0) / 16); + } else { + // best guess + return 4 + // array element + 16 + PAYLOAD_SIZE; // object + } } @Setup @@ -39,14 +62,14 @@ count = (int) Math.max(1, ldsMB * 1024 * 1024 / getSizePerCount()); objects = new Object[count]; for (int c = 0; c < count; c++) { - objects[c] = new Object(); + objects[c] = new byte[PAYLOAD_SIZE]; } } @Benchmark public void test() { bucket.limit(); - objects[ThreadLocalRandom.current().nextInt(count)] = new Object(); + objects[ThreadLocalRandom.current().nextInt(count)] = new byte[PAYLOAD_SIZE]; } }
--- a/src/main/java/org/openjdk/gcbench/fragger/LinkedListFragger.java Fri Dec 02 12:43:28 2016 +0100 +++ b/src/main/java/org/openjdk/gcbench/fragger/LinkedListFragger.java Fri Dec 02 14:03:29 2016 +0100 @@ -1,5 +1,6 @@ package org.openjdk.gcbench.fragger; +import org.openjdk.gcbench.util.AllocProfileSupport; import org.openjdk.gcbench.util.ratelimit.MultiTokenBucket; import org.openjdk.jmh.annotations.*; @@ -17,6 +18,8 @@ @State(Scope.Benchmark) public class LinkedListFragger { + public static final int PAYLOAD_SIZE = 16384; + @Param({"1000"}) long ldsMB; @@ -29,9 +32,29 @@ int count; + LinkedList<Object> o0; + LinkedList<Object> o16; + private int getSizePerCount() { - return 24 + // Node - 64; // payload + if (AllocProfileSupport.isAvailable()) { + long a1 = AllocProfileSupport.getAllocatedBytes(); + o0 = new LinkedList<>(); + long a2 = AllocProfileSupport.getAllocatedBytes(); + o16 = new LinkedList<>(); + for (int c = 0; c < 16; c++) { + o16.add(new byte[PAYLOAD_SIZE]); + } + long a3 = AllocProfileSupport.getAllocatedBytes(); + + long sizeO0 = a2 - a1; + long sizeO16 = a3 - a2; + + return (int) ((sizeO16 - sizeO0) / 16); + } else { + // best guess + return 24 + // Node + 16 + PAYLOAD_SIZE; // payload + } } @Setup @@ -40,14 +63,14 @@ count = (int)Math.max(1, ldsMB * 1024 * 1024 / getSizePerCount()); objects = new LinkedList<>(); for (int c = 0; c < count; c++) { - objects.add(new byte[48]); + objects.add(new byte[PAYLOAD_SIZE]); } } @Benchmark public void test() { bucket.limit(); - objects.set(ThreadLocalRandom.current().nextInt(count), new byte[48]); + objects.set(ThreadLocalRandom.current().nextInt(count), new byte[PAYLOAD_SIZE]); } }
--- a/src/main/java/org/openjdk/gcbench/fragger/TreeFragger.java Fri Dec 02 12:43:28 2016 +0100 +++ b/src/main/java/org/openjdk/gcbench/fragger/TreeFragger.java Fri Dec 02 14:03:29 2016 +0100 @@ -1,5 +1,6 @@ package org.openjdk.gcbench.fragger; +import org.openjdk.gcbench.util.AllocProfileSupport; import org.openjdk.gcbench.util.ratelimit.MultiTokenBucket; import org.openjdk.jmh.annotations.*; @@ -15,6 +16,8 @@ @State(Scope.Benchmark) public class TreeFragger { + public static final int PAYLOAD_SIZE = 16384; + @Param({"1000"}) long ldsMB; @@ -27,48 +30,61 @@ MultiTokenBucket bucket; + Object o0, o16; + private int getSizePerCount() { - return 24 + // Node - 16; // payload + if (AllocProfileSupport.isAvailable()) { + long a1 = AllocProfileSupport.getAllocatedBytes(); + o0 = create(0); + long a2 = AllocProfileSupport.getAllocatedBytes(); + o16 = create(16); + long a3 = AllocProfileSupport.getAllocatedBytes(); + + long sizeO0 = a2 - a1; + long sizeO16 = a3 - a2; + + return (int) ((sizeO16 - sizeO0) / 16); + } else { + // best guess + return 24 + // Node + 16 + PAYLOAD_SIZE; // payload + } } @Setup public void setup() { bucket = new MultiTokenBucket(rate); count = (int)Math.max(1, ldsMB * 1024 * 1024 / getSizePerCount()); + root = create(count); + } - root = new Node(new Object()); + private Node create(int count) { + Node root = new Node(new Object()); for (int addr = 0; addr < count; addr++) { Node cur = root; for (int m = 31 - Integer.numberOfLeadingZeros(addr); m >= 0; m--) { if ((addr & (1 << m)) != 0) { if (cur.left == null) { - cur.left = new Node(new Object()); + cur.left = new Node(new byte[PAYLOAD_SIZE]); } cur = cur.left; } else { if (cur.right == null) { - cur.right = new Node(new Object()); + cur.right = new Node(new byte[PAYLOAD_SIZE]); } cur = cur.right; } } } - } - public static int align(int size, int align) { - if ((size % align) == 0) { - return size; - } else { - return ((size / align) + 1) * align; - } + return root; } @Benchmark public void test() { bucket.limit(); - doStore(ThreadLocalRandom.current().nextInt(count), new Object()); + doStore(ThreadLocalRandom.current().nextInt(count), new byte[PAYLOAD_SIZE]); } private void doStore(int addr, Object obj) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/openjdk/gcbench/util/AllocProfileSupport.java Fri Dec 02 14:03:29 2016 +0100 @@ -0,0 +1,68 @@ +package org.openjdk.gcbench.util; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * This class encapsulates any platform-specific functionality. It is supposed + * to gracefully fail if some functionality is not available. This class + * resolves most special classes via Reflection to enable building against a + * standard JDK. + */ +public class AllocProfileSupport { + private static final boolean ALLOC_AVAILABLE; + private static ThreadMXBean ALLOC_MX_BEAN; + private static Method ALLOC_MX_BEAN_GETTER; + + static { + ALLOC_AVAILABLE = tryInitAlloc(); + } + + private static boolean tryInitAlloc() { + try { + Class<?> internalIntf = Class.forName("com.sun.management.ThreadMXBean"); + ThreadMXBean bean = ManagementFactory.getThreadMXBean(); + if (!internalIntf.isAssignableFrom(bean.getClass())) { + Class<?> pmo = Class.forName("java.lang.management.PlatformManagedObject"); + Method m = ManagementFactory.class.getMethod("getPlatformMXBean", Class.class, pmo); + bean = (ThreadMXBean) m.invoke(null, internalIntf); + if (bean == null) { + throw new UnsupportedOperationException("No way to access private ThreadMXBean"); + } + } + + ALLOC_MX_BEAN = bean; + ALLOC_MX_BEAN_GETTER = internalIntf.getMethod("getThreadAllocatedBytes", long[].class); + getAllocatedBytes(bean.getAllThreadIds()); + + return true; + } catch (Throwable e) { + System.out.println("WARNING: Allocation profiling is not available: " + e.getMessage()); + } + return false; + } + + public static long getAllocatedBytes() { + long[] threadIds = {Thread.currentThread().getId()}; + return getAllocatedBytes(threadIds)[0]; + } + + private static long[] getAllocatedBytes(long[] threadIds) { + if (ALLOC_AVAILABLE) { + try { + return (long[]) ALLOC_MX_BEAN_GETTER.invoke(ALLOC_MX_BEAN, (Object) threadIds); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new IllegalStateException(e); + } + } else { + return new long[threadIds.length]; + } + } + + public static boolean isAvailable() { + return ALLOC_AVAILABLE; + } + +}