Collecting additional metrics with JMH

Doug Simon doug.simon at oracle.com
Thu Apr 3 11:47:54 UTC 2014


For Graal[1], I want to use JMH to micro benchmark core parts of the compiler such as how long a certain compiler transformation takes to run. To do so, I want to use a fixture that builds or clones a compiler graph prior to invoking the benchmarking method. The goal is for the benchmarking method to only contain the application of the compiler transformation and not include the cost of building/cloning the input graph.

@State(Scope.Thread)
public class GraphState {
    private StructuredGraph originalGraph;
    public StructuredGraph graph;
    public GraphState(StructuredGraph graph) {
        this.originalGraph = graph;
    }

    @Setup(Level.Invocation)
    public void beforeInvocation() {
        graph = originalGraph.copy();
    }
}

This works.

However, I would also like to profile the allocation done *only* in the @GMB method. This will allow us to easily see one possible cause for a regression in performance. I wanted to do this using com.sun.management.ThreadMXBean.getThreadAllocatedBytes(long) by modifying GraphState as follows:

    public static final AtomicLong totalAlloc = new AtomicLong();
    public static final AtomicInteger totalOps = new AtomicInteger();
    static {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.out.println("TOTAL_ALLOCATED_BYTES: " + NumberFormat.getInstance().format(totalAlloc.get()));
                System.out.println("AVERAGE_ALLOCATED_BYTES_PER_OP: " + NumberFormat.getInstance().format(totalAlloc.get() / totalOps.get()));
            }
        });
    }

    public StructuredGraph originalGraph;
    public StructuredGraph graph;
    public long allocBefore;

    @Setup(Level.Invocation)
    public void beforeInvocation() {
        graph = originalGraph.copy();
        allocBefore = GraalUtil.getCurrentThreadAllocatedBytes();
    }

    @TearDown(Level.Invocation)
    public void afterInvocation() {
        long delta = GraalUtil.getCurrentThreadAllocatedBytes() - allocBefore;
        totalAlloc.addAndGet(delta);
        totalOps.addAndGet(1);
    }

The use of statics and shutdown hooks for collecting and printing the allocation profiles feels very hacky to me. However, I can’t see any other way to do it. Is there a more elegant way to do this or am I simply trying to squeeze a square peg through a round hole?

-Doug

[1] https://wiki.openjdk.java.net/display/Graal/Main


More information about the jmh-dev mailing list