view src/main/java/org/openjdk/gcbench/tests/MachineCntTest.java @ 47:dada456637b0

Cleanup, and make sure we have error bounds in machine counters tests.
author shade
date Fri, 09 Dec 2016 15:37:18 +0100
parents c65e5eaf3b0d
children 8df264030545
line wrap: on
line source

package org.openjdk.gcbench.tests;

import org.openjdk.jmh.profile.LinuxPerfNormProfiler;
import org.openjdk.jmh.results.Result;
import org.openjdk.jmh.results.RunResult;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.Map;

public class MachineCntTest extends AbstractTest {

    private final Dimension[] dimensions;

    public MachineCntTest(Options baseOpts, Class<?> benchmark, String label, String description,
                           Dimension... dimensions) {
        super(baseOpts, label, benchmark, description);
        this.dimensions = dimensions;
    }

    @Override
    protected void doRun() {
        pw.println("  Test dimensions: ");
        for (Dimension d : dimensions) {
            pw.print("    ");
            pw.println(d.toString());
        }
        pw.println();

        pw.print("  ");

        for (Dimension d : dimensions) {
            pw.printf("%-30s ", d.label());
        }

        pw.printf("%-35s %-25s %-25s %-25s %n",
                "Performance",
                "Instructions",
                "Cycles",
                "Branches"
        );

        Object lastKeyVal = null;

        for (DimensionValues values : DimensionValues.product(dimensions)) {
            ChainedOptionsBuilder builder = new OptionsBuilder()
                    .parent(baseOpts)
                    .threads(1)
                    .forks(3)
                    .addProfiler(LinuxPerfNormProfiler.class);


            Object keyVal = -1;
            for (int i = 0; i < dimensions.length; i++) {
                Dimension d = dimensions[i];
                Object value = values.values[i];
                if (i == dimensions.length - 2) {
                    keyVal = value;
                }

                switch (d.type()) {
                    case JVM_MODE:
                        builder = builder.jvmArgsAppend(String.valueOf(value));
                        break;
                    case JAVA_TYPE:
                        builder = builder.include(benchmark.getName() + ".test_" + value);
                        break;
                    default:
                        throw new IllegalStateException("Unknown dimension: " + d);
                }
            }

            if (lastKeyVal != keyVal) {
                pw.println();
                lastKeyVal = keyVal;
            }

            runWith(values, builder.build());
        }
    }

    private void runWith(DimensionValues values, Options opts) {
        pw.print("  ");

        for (Object v : values.values) {
            pw.printf("%-30s ", v);
        }

        try {
            RunResult result = new Runner(opts).runSingle();

            Result prim = result.getPrimaryResult();
            Map<String, Result> sec = result.getSecondaryResults();

            pw.printf("%-35s %-25s %-25s %-25s%n",
                    shortVal(prim),
                    shortVal(sec.get("instructions")),
                    shortVal(sec.get("cycles")),
                    shortVal(sec.get("branches"))
            );
        } catch (RunnerException e) {
            pw.print("FAILED: ");
            Throwable cause = e.getCause();
            if (cause != null) {
                for (Throwable t : cause.getSuppressed()) {
                    pw.print(t.getMessage() + " ");
                }
            } else {
                pw.println(" unknown error");
                e.printStackTrace(pw);
            }
            pw.println();
        }
    }

    private String shortVal(Result r) {
        if (r != null) {
            if (!Double.isNaN(r.getScoreError())) {
                return String.format("%.2f ± %.2f %s", r.getScore(), r.getScoreError(), r.getScoreUnit());
            } else {
                return String.format("%.2f %s", r.getScore(), r.getScoreUnit());
            }
        } else {
            return "-";
        }
    }

    private String latencyVal(Result r) {
        if (r != null && !Double.isNaN(r.getScore())) {
            return String.format("%.3f %s", r.getScore(), r.getScoreUnit());
        } else {
            return "-";
        }
    }
}