/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.ignite.ml.math.benchmark; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; /** Refer {@link MathBenchmarkSelfTest} for usage examples. */ class MathBenchmark { /** */ private final boolean outputToConsole; /** */ private final String benchmarkName; /** */ private final int measurementTimes; /** */ private final int warmUpTimes; /** */ private final String tag; /** */ private final String comments; /** Constructor strictly for use within this class. */ private MathBenchmark(String benchmarkName, boolean outputToConsole, int measurementTimes, int warmUpTimes, String tag, String comments) { this.benchmarkName = benchmarkName; this.outputToConsole = outputToConsole; this.measurementTimes = measurementTimes; this.warmUpTimes = warmUpTimes; this.tag = tag; this.comments = comments; validate(); } /** * Benchmark with specified name and default parameters, in particular, default output file. * * @param benchmarkName name */ MathBenchmark(String benchmarkName) { this(benchmarkName, false, 100, 1, "", ""); } /** * Executes the code using config of this benchmark. * * @param code code to execute * @throws Exception if something goes wrong */ void execute(BenchmarkCode code) throws Exception { System.out.println("Started benchmark [" + benchmarkName + "]."); for (int cnt = 0; cnt < warmUpTimes; cnt++) code.call(); final long start = System.currentTimeMillis(); for (int cnt = 0; cnt < measurementTimes; cnt++) code.call(); final long end = System.currentTimeMillis(); writeResults(formatResults(start, end)); System.out.println("Finished benchmark [" + benchmarkName + "]."); } /** * Set optional output mode for using stdout. * * @return configured benchmark */ MathBenchmark outputToConsole() { return new MathBenchmark(benchmarkName, true, measurementTimes, warmUpTimes, tag, comments); } /** * Set optional measurement times. * * @param param times * @return configured benchmark */ MathBenchmark measurementTimes(int param) { return new MathBenchmark(benchmarkName, outputToConsole, param, warmUpTimes, tag, comments); } /** * Set optional warm-up times. * * @param param times * @return configured benchmark */ MathBenchmark warmUpTimes(int param) { return new MathBenchmark(benchmarkName, outputToConsole, measurementTimes, param, tag, comments); } /** * Set optional tag to help filtering specific kind of benchmark results. * * @param param name * @return configured benchmark */ MathBenchmark tag(String param) { return new MathBenchmark(benchmarkName, outputToConsole, measurementTimes, warmUpTimes, param, comments); } /** * Set optional comments. * * @param param name * @return configured benchmark */ MathBenchmark comments(String param) { return new MathBenchmark(benchmarkName, outputToConsole, measurementTimes, warmUpTimes, tag, param); } /** */ private void writeResults(String results) throws Exception { if (outputToConsole) { System.out.println(results); return; } new ResultsWriter().append(results); } /** */ private String formatResults(long start, long end) { final String delim = ","; assert !formatDouble(1000_000_001.1).contains(delim) : "Formatted results contain [" + delim + "]."; final String ts = formatTs(start); assert !ts.contains(delim) : "Formatted timestamp contains [" + delim + "]."; return benchmarkName + delim + ts + // IMPL NOTE timestamp delim + formatDouble((double)(end - start) / measurementTimes) + delim + measurementTimes + delim + warmUpTimes + delim + tag + delim + comments; } /** */ private String formatDouble(double val) { return String.format(Locale.US, "%f", val); } /** */ private String formatTs(long ts) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); return sdf.format(new Date(ts)); } /** */ private void validate() { if (benchmarkName == null || benchmarkName.isEmpty()) throw new IllegalArgumentException("Invalid benchmark name: [" + benchmarkName + "]."); if (measurementTimes < 1) throw new IllegalArgumentException("Invalid measurement times: [" + measurementTimes + "]."); } /** */ interface BenchmarkCode { // todo find out why Callable<Void> failed to work here /** */ void call() throws Exception; } }