de.tynne.benchmarksuite.Main.java Source code

Java tutorial

Introduction

Here is the source code for de.tynne.benchmarksuite.Main.java

Source

/*
 * Copyright 2015 Stephan Fuhrmann.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.tynne.benchmarksuite;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.reflections.Reflections;

/**
 *
 * @author Stephan Fuhrmann
 */
public class Main {

    private static double standardDeviationOf(DoubleStream doubleStream, double average) {
        double sum = doubleStream.map(x -> Math.pow(x - average, 2.)).average().getAsDouble();
        return Math.sqrt(sum);
    }

    private static void listBenchmarks(BenchmarkProducer benchmarkProducer, PrintStream ps) {
        benchmarkProducer.get().stream().forEach((b) -> ps.printf("%s: %s\n", b.getId(), b.getName()));
        ps.flush();
    }

    private static String nameFor(BenchmarkSuite benchmarkSuite, BenchmarkProducer benchmarkProducer) {
        if (benchmarkSuite.name().isEmpty()) {
            return benchmarkProducer.getClass().getSimpleName();
        } else
            return benchmarkSuite.name();
    }

    private static void listSuites(Map<BenchmarkSuite, BenchmarkProducer> suites, PrintStream ps) {
        suites.entrySet().stream().sorted(
                (a, b) -> nameFor(a.getKey(), a.getValue()).compareToIgnoreCase(nameFor(b.getKey(), b.getValue())))
                .forEach((e) -> {
                    ps.printf("%s: %s\n", nameFor(e.getKey(), e.getValue()), e.getKey().enabled());
                });
        ps.flush();
    }

    private static void nanoNullLoop(int times, List<Long> addTo) {
        for (int i = 0; i < times; i++) {
            long start = System.nanoTime();
            long end = System.nanoTime();

            long diff = end - start;
            addTo.add(diff);
        }
    }

    private static void checkNano(PrintStream ps) {
        List<Long> diffs = new ArrayList<>();

        nanoNullLoop(1000000, diffs);
        diffs.clear();
        nanoNullLoop(1000000, diffs);

        LongSummaryStatistics statistics = diffs.stream().mapToLong(l -> l).summaryStatistics();

        ps.printf("min=%d, avg=%g, max=%d\n", statistics.getMin(), statistics.getAverage(), statistics.getMax());
    }

    private static String format(Args args, double number) throws IOException {
        NumberFormat nf = NumberFormat.getNumberInstance(Locale.ENGLISH);
        nf.setGroupingUsed(false);
        String string = nf.format(number);
        return string.replaceAll("\\.", args.getDecimalDot());
    }

    private static void runBenchmarks(Args args, BenchmarkProducer benchmarkProducer) throws IOException {
        BackupHelper.backupIfNeeded(args.getOutput());

        // this looks like NOT comma seperated values, but excel and libreoffice load this automatically
        final CSVFormat format = CSVFormat.EXCEL.withDelimiter(';').withHeader("#", "ID", "Name", "Min [ns]",
                "Avg [ns]", "Max [ns]", "Chart Pos", "Best Increase [%]", "Iterations");
        try (CSVPrinter printer = new CSVPrinter(
                new OutputStreamWriter(new FileOutputStream(args.getOutput()), Charset.forName(args.getCharset())),
                format)) {
            List<Benchmark> benchmarks = benchmarkProducer.get();
            List<Benchmark> matching = benchmarks.stream()
                    .filter(b -> args.getExecute().matcher(b.getId()).matches()).collect(Collectors.toList());
            BenchmarkRunner benchmarkRunner = new BenchmarkRunner(matching,
                    BenchmarkRunner.SEC_IN_NANOS * args.getWarumUpTime(),
                    BenchmarkRunner.SEC_IN_NANOS * args.getRunTime());
            benchmarkRunner.run();
            Chart chart = Chart.of(matching);

            for (Benchmark b : matching) {
                try {
                    StatRecord statRecord = chart.getStats().get(b);
                    printer.print(matching.indexOf(b));
                    printer.print(b.getId());
                    printer.print(b.getName());
                    printer.print(format(args, statRecord.getMin()));
                    printer.print(format(args, statRecord.getAverage()));
                    printer.print(format(args, statRecord.getMax()));
                    printer.print(chart.getChart().get(b).chartPosition);
                    double bestAvg = chart.getStats().get(chart.getPerformanceChart().get(0)).getAverage();
                    double thisAvg = statRecord.getAverage();

                    printer.print(format(args, 100. * (thisAvg - bestAvg) / bestAvg));
                    printer.print(statRecord.getCount());
                    printer.println();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    /** Returns a single suite for benchmarks by name.
     */
    private static Optional<BenchmarkProducer> findByName(String suite,
            Map<BenchmarkSuite, BenchmarkProducer> suites) {
        return suites.entrySet().stream().filter(e -> nameFor(e.getKey(), e.getValue()).equalsIgnoreCase(suite))
                .map(e -> e.getValue()).findFirst();
    }

    /** Returns a producer for all benchmarks in the named suites.
     */
    private static BenchmarkProducer findAllByName(List<String> suiteNames,
            Map<BenchmarkSuite, BenchmarkProducer> suites) {
        List<BenchmarkProducer> benchmarkProducers = suiteNames.stream().map(s -> findByName(s, suites))
                .filter(bp -> bp.isPresent()).map(o -> o.get()).collect(Collectors.toList());

        return () -> {
            List<Benchmark> result = new ArrayList<>();
            benchmarkProducers.forEach(bp -> {
                result.addAll(bp.get());
            });
            return result;
        };
    }

    private static Map<BenchmarkSuite, BenchmarkProducer> getBenchmarkSuites()
            throws InstantiationException, IllegalAccessException {
        Reflections reflections = new Reflections("de.tynne.benchmarksuite");

        Set<Class<?>> benchmarkSuites = reflections.getTypesAnnotatedWith(BenchmarkSuite.class);

        Map<BenchmarkSuite, BenchmarkProducer> result = new HashMap<>();
        for (Class<?> clazz : benchmarkSuites) {
            BenchmarkSuite benchmarkSuite = clazz.getAnnotation(BenchmarkSuite.class);
            BenchmarkProducer benchmarkProducer = clazz.asSubclass(BenchmarkProducer.class).newInstance();
            result.put(benchmarkSuite, benchmarkProducer);
        }
        return result;
    }

    public static void main(String[] cmdLine) throws Exception {
        Args args = Args.parse(cmdLine);
        if (args == null) {
            return;
        }

        Map<BenchmarkSuite, BenchmarkProducer> suites = getBenchmarkSuites();
        if (args.isListSuites()) {
            listSuites(suites, System.out);
            return;
        }

        BenchmarkProducer benchmarkProducer = findAllByName(args.getSuites(), suites);

        if (args.isListBenchmarks()) {
            listBenchmarks(benchmarkProducer, System.out);
            return;
        }

        if (args.isCheckNano()) {
            checkNano(System.out);
            return;
        }

        runBenchmarks(args, benchmarkProducer);
    }
}