diff --git a/benchmark/pom.xml b/benchmark/pom.xml
index 00f55cd..18e95bf 100644
--- a/benchmark/pom.xml
+++ b/benchmark/pom.xml
@@ -45,6 +45,12 @@
${project.version}
+
+ com.github.mp911de.microbenchmark-runner
+ microbenchmark-runner-junit4
+ 0.1.0.RELEASE
+
+
@@ -119,6 +125,10 @@
spring-libs-snapshot
https://repo.spring.io/libs-snapshot
+
+ jitpack.io
+ https://jitpack.io
+
diff --git a/benchmark/support/pom.xml b/benchmark/support/pom.xml
index 5227f64..b6252d2 100644
--- a/benchmark/support/pom.xml
+++ b/benchmark/support/pom.xml
@@ -21,6 +21,11 @@
spring-data-mongodb
+
+ com.github.mp911de.microbenchmark-runner
+ microbenchmark-runner-junit4
+
+
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/AbstractMicrobenchmark.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/AbstractMicrobenchmark.java
index 1173690..70ae2a5 100644
--- a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/AbstractMicrobenchmark.java
+++ b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/AbstractMicrobenchmark.java
@@ -15,6 +15,8 @@
*/
package org.springframework.data.microbenchmark.common;
+import jmh.mbr.junit4.Microbenchmark;
+
import org.junit.runner.RunWith;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
@@ -29,9 +31,10 @@ import org.openjdk.jmh.annotations.Warmup;
* @author Mark Paluch
* @see Microbenchmark
*/
-@Warmup(iterations = JmhSupport.WARMUP_ITERATIONS)
-@Measurement(iterations = JmhSupport.MEASUREMENT_ITERATIONS)
-@Fork(JmhSupport.FORKS)
+@Warmup(iterations = 5)
+@Measurement(iterations = 10)
+@Fork(value = 1, jvmArgs = { "-server", "-XX:+HeapDumpOnOutOfMemoryError", "-Xms1024m", "-Xmx1024m",
+ "-XX:MaxDirectMemorySize=1024m" })
@State(Scope.Thread)
@RunWith(Microbenchmark.class)
public abstract class AbstractMicrobenchmark {
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/HttpResultsWriter.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/HttpResultsWriter.java
index 8ac0718..ba5834b 100644
--- a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/HttpResultsWriter.java
+++ b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/HttpResultsWriter.java
@@ -15,8 +15,10 @@
*/
package org.springframework.data.microbenchmark.common;
-import lombok.SneakyThrows;
+import jmh.mbr.core.ResultsWriter;
+import lombok.RequiredArgsConstructor;
+import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -26,30 +28,37 @@ import java.time.Duration;
import java.util.Collection;
import org.openjdk.jmh.results.RunResult;
+import org.openjdk.jmh.runner.format.OutputFormat;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.CollectionUtils;
/**
- * {@link ResultsWriter} implementation of {@link URLConnection}.
- *
- * @since 2.0
+ * {@link ResultsWriterOld} implementation of {@link URLConnection}.
+ *
+ * @author Christoph Strobl
+ * @author Mark Paluch
*/
+@RequiredArgsConstructor
class HttpResultsWriter implements ResultsWriter {
private final String url;
- HttpResultsWriter(String url) {
- this.url = url;
- }
-
@Override
- @SneakyThrows
- public void write(Collection results) {
+ public void write(OutputFormat output, Collection results) {
if (CollectionUtils.isEmpty(results)) {
return;
}
+ try {
+ doWrite(results);
+ } catch (IOException e) {
+ output.println("Failed to write results: " + e.toString());
+ }
+ }
+
+ private void doWrite(Collection results) throws IOException {
+
StandardEnvironment env = new StandardEnvironment();
String projectVersion = env.getProperty("project.version", "unknown");
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/JmhSupport.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/JmhSupport.java
deleted file mode 100644
index 96cb77d..0000000
--- a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/JmhSupport.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- *
- * 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
- *
- * https://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.springframework.data.microbenchmark.common;
-
-import java.io.File;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-import org.junit.runners.model.FrameworkMethod;
-import org.openjdk.jmh.results.RunResult;
-import org.openjdk.jmh.results.format.ResultFormatType;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-import org.openjdk.jmh.runner.options.TimeValue;
-import org.springframework.core.env.StandardEnvironment;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.ResourceUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * @author Christoph Strobl
- * @author Mark Paluch
- */
-class JmhSupport {
-
- static final int WARMUP_ITERATIONS = 5;
- static final int MEASUREMENT_ITERATIONS = 10;
- static final int FORKS = 1;
- static final String[] JVM_ARGS = { "-server", "-XX:+HeapDumpOnOutOfMemoryError", "-Xms1024m", "-Xmx1024m",
- "-XX:MaxDirectMemorySize=1024m" };
-
- private final StandardEnvironment environment = new StandardEnvironment();
-
- /**
- * Get the regex for all benchmarks to be included in the run. By default every benchmark within classes matching the
- * fqcn.
- * The {@literal benchmark} command line argument allows overriding the defaults using {@code #} as class / method
- * name separator.
- *
- * @return never {@literal null}.
- * @param name
- * @param methods
- */
- protected List includes(Class> testClass, Collection methods) {
-
- String tests = environment.getProperty("benchmark", String.class);
-
- if (!StringUtils.hasText(tests)) {
-
- return methods.stream()
- .map(it -> Pattern.quote(it.getDeclaringClass().getName()) + "\\." + Pattern.quote(it.getName()) + "$")
- .collect(Collectors.toList());
- }
-
- if (tests.contains(testClass.getName()) || tests.contains(testClass.getSimpleName())) {
- if (!tests.contains("#")) {
- return Collections.singletonList(".*" + tests + ".*");
- }
-
- String[] args = tests.split("#");
- return Collections.singletonList(".*" + args[0] + "." + args[1]);
- }
-
- return Collections.emptyList();
- }
-
- /**
- * Collect all options for the {@link Runner}.
- *
- * @return never {@literal null}.
- * @throws Exception
- */
- protected ChainedOptionsBuilder options(Class> jmhTestClass) throws Exception {
-
- ChainedOptionsBuilder optionsBuilder = new OptionsBuilder().jvmArgs(jvmArgs());
-
- optionsBuilder = warmup(optionsBuilder);
- optionsBuilder = measure(optionsBuilder);
- optionsBuilder = forks(optionsBuilder);
- optionsBuilder = report(optionsBuilder, jmhTestClass);
-
- return optionsBuilder;
- }
-
- /**
- * JVM args to apply to {@link Runner} via its {@link org.openjdk.jmh.runner.options.Options}.
- *
- * @return {@link #JVM_ARGS} by default.
- */
- protected String[] jvmArgs() {
-
- String[] args = new String[JVM_ARGS.length];
- System.arraycopy(JVM_ARGS, 0, args, 0, JVM_ARGS.length);
- return args;
- }
-
- /**
- * Read {@code warmupIterations} property from {@link org.springframework.core.env.Environment}.
- *
- * @return -1 if not set.
- */
- protected int getWarmupIterations() {
- return environment.getProperty("warmupIterations", Integer.class, -1);
- }
-
- /**
- * Read {@code measurementIterations} property from {@link org.springframework.core.env.Environment}.
- *
- * @return -1 if not set.
- */
- protected int getMeasurementIterations() {
- return environment.getProperty("measurementIterations", Integer.class, -1);
-
- }
-
- /**
- * Read {@code forks} property from {@link org.springframework.core.env.Environment}.
- *
- * @return -1 if not set.
- */
- protected int getForksCount() {
- return environment.getProperty("forks", Integer.class, -1);
- }
-
- /**
- * Read {@code benchmarkReportDir} property from {@link org.springframework.core.env.Environment}.
- *
- * @return {@literal null} if not set.
- */
- protected String getReportDirectory() {
- return environment.getProperty("benchmarkReportDir");
- }
-
- /**
- * Read {@code measurementTime} property from {@link org.springframework.core.env.Environment}.
- *
- * @return -1 if not set.
- */
- protected long getMeasurementTime() {
- return environment.getProperty("measurementTime", Long.class, -1L);
- }
-
- /**
- * Read {@code warmupTime} property from {@link org.springframework.core.env.Environment}.
- *
- * @return -1 if not set.
- */
- protected long getWarmupTime() {
- return environment.getProperty("warmupTime", Long.class, -1L);
- }
-
- /**
- * {@code project.version_yyyy-MM-dd_ClassName.json} eg.
- * {@literal 1.11.0.BUILD-SNAPSHOT_2017-03-07_MappingMongoConverterBenchmark.json}
- *
- * @return
- */
- protected String reportFilename(Class> jmhTestClass) {
-
- StringBuilder sb = new StringBuilder();
-
- if (environment.containsProperty("project.version")) {
-
- sb.append(environment.getProperty("project.version"));
- sb.append("_");
- }
-
- sb.append(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
- sb.append("_");
- sb.append(org.springframework.util.ClassUtils.getShortName(jmhTestClass));
- sb.append(".json");
- return sb.toString();
- }
-
- /**
- * Apply measurement options to {@link ChainedOptionsBuilder}.
- *
- * @param optionsBuilder must not be {@literal null}.
- * @return {@link ChainedOptionsBuilder} with options applied.
- * @see #getMeasurementIterations()
- * @see #getMeasurementTime()
- */
- private ChainedOptionsBuilder measure(ChainedOptionsBuilder optionsBuilder) {
-
- int measurementIterations = getMeasurementIterations();
- long measurementTime = getMeasurementTime();
-
- if (measurementIterations > 0) {
- optionsBuilder = optionsBuilder.measurementIterations(measurementIterations);
- }
-
- if (measurementTime > 0) {
- optionsBuilder = optionsBuilder.measurementTime(TimeValue.seconds(measurementTime));
- }
-
- return optionsBuilder;
- }
-
- /**
- * Apply warmup options to {@link ChainedOptionsBuilder}.
- *
- * @param optionsBuilder must not be {@literal null}.
- * @return {@link ChainedOptionsBuilder} with options applied.
- * @see #getWarmupIterations()
- * @see #getWarmupTime()
- */
- private ChainedOptionsBuilder warmup(ChainedOptionsBuilder optionsBuilder) {
-
- int warmupIterations = getWarmupIterations();
- long warmupTime = getWarmupTime();
-
- if (warmupIterations > 0) {
- optionsBuilder = optionsBuilder.warmupIterations(warmupIterations);
- }
-
- if (warmupTime > 0) {
- optionsBuilder = optionsBuilder.warmupTime(TimeValue.seconds(warmupTime));
- }
-
- return optionsBuilder;
- }
-
- /**
- * Apply forks option to {@link ChainedOptionsBuilder}.
- *
- * @param optionsBuilder must not be {@literal null}.
- * @return {@link ChainedOptionsBuilder} with options applied.
- * @see #getForksCount()
- */
- private ChainedOptionsBuilder forks(ChainedOptionsBuilder optionsBuilder) {
-
- int forks = getForksCount();
-
- if (forks <= 0) {
- return optionsBuilder;
- }
-
- return optionsBuilder.forks(forks);
- }
-
- /**
- * Apply report option to {@link ChainedOptionsBuilder}.
- *
- * @param optionsBuilder must not be {@literal null}.
- * @return {@link ChainedOptionsBuilder} with options applied.
- * @throws IOException if report file cannot be created.
- * @see #getReportDirectory()
- */
- private ChainedOptionsBuilder report(ChainedOptionsBuilder optionsBuilder, Class> jmhTestClass) throws IOException {
-
- String reportDir = getReportDirectory();
-
- if (!StringUtils.hasText(reportDir)) {
- return optionsBuilder;
- }
-
- String reportFilePath = reportDir + (reportDir.endsWith(File.separator) ? "" : File.separator) + reportFilename(jmhTestClass);
- File file = ResourceUtils.getFile(reportFilePath);
-
- if (file.exists()) {
- file.delete();
- } else {
-
- file.getParentFile().mkdirs();
- file.createNewFile();
- }
-
- optionsBuilder.resultFormat(ResultFormatType.JSON);
- optionsBuilder.result(reportFilePath);
-
- return optionsBuilder;
- }
-
- /**
- * Publish results to an external system.
- *
- * @param results must not be {@literal null}.
- */
- void publishResults(Collection results) {
-
- if (CollectionUtils.isEmpty(results) || !environment.containsProperty("publishTo")) {
- return;
- }
-
- String uri = environment.getProperty("publishTo");
- try {
- ResultsWriter.forUri(uri).write(results);
- } catch (Exception e) {
- System.err.println(String.format("Cannot save benchmark results to '%s'. Error was %s.", uri, e));
- }
- }
-}
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/Microbenchmark.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/Microbenchmark.java
deleted file mode 100644
index 93c6f2a..0000000
--- a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/Microbenchmark.java
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- *
- * 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
- *
- * https://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.springframework.data.microbenchmark.common;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import org.junit.runner.Description;
-import org.junit.runner.manipulation.Filter;
-import org.junit.runner.manipulation.NoTestsRemainException;
-import org.junit.runner.manipulation.Sorter;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
-import org.junit.runners.BlockJUnit4ClassRunner;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.InitializationError;
-import org.junit.runners.model.Statement;
-import org.openjdk.jmh.annotations.Benchmark;
-import org.openjdk.jmh.infra.BenchmarkParams;
-import org.openjdk.jmh.infra.IterationParams;
-import org.openjdk.jmh.results.BenchmarkResult;
-import org.openjdk.jmh.results.IterationResult;
-import org.openjdk.jmh.results.RunResult;
-import org.openjdk.jmh.runner.Defaults;
-import org.openjdk.jmh.runner.NoBenchmarksException;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.format.OutputFormat;
-import org.openjdk.jmh.runner.format.OutputFormatFactory;
-import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
-import org.openjdk.jmh.runner.options.Options;
-import org.openjdk.jmh.util.UnCloseablePrintStream;
-import org.openjdk.jmh.util.Utils;
-import org.springframework.util.StringUtils;
-
-/**
- * JMH Microbenchmark runner that turns methods annotated with {@link Benchmark} into runnable methods allowing
- * execution through JUnit.
- *
- * @author Mark Paluch
- */
-public class Microbenchmark extends BlockJUnit4ClassRunner {
-
- private final Object childrenLock = new Object();
- private final JmhSupport jmhRunner = new JmhSupport();
-
- private Collection filteredChildren;
-
- /**
- * Creates a {@link Microbenchmark} to run {@link Class test class}.
- *
- * @param testClass
- * @throws InitializationError if the test class is malformed.
- */
- public Microbenchmark(Class> testClass) throws InitializationError {
- super(testClass);
- }
-
- /**
- * Ignore JUnit validation as we're using JMH here.
- *
- * @param errors
- */
- @Override
- protected void collectInitializationErrors(List errors) {}
-
- /**
- * JMH has no means to exclude benchmark methods.
- */
- @Override
- protected boolean isIgnored(FrameworkMethod child) {
- return false;
- }
-
- /**
- * Returns the methods that run tests. Default implementation returns all methods annotated with {@code @Test} on this
- * class and superclasses that are not overridden.
- */
- protected List computeTestMethods() {
-
- List annotatedMethods = new ArrayList<>(getTestClass().getAnnotatedMethods(Benchmark.class));
-
- annotatedMethods.sort(Comparator.comparing(Microbenchmark::getBenchmarkName));
-
- return Collections.unmodifiableList(annotatedMethods);
- }
-
- /*
- * (non-Javadoc)
- * @see org.junit.runners.ParentRunner#classBlock(org.junit.runner.notification.RunNotifier)
- */
- @Override
- protected Statement classBlock(RunNotifier notifier) {
- return childrenInvoker(notifier);
- }
-
- /*
- * (non-Javadoc)
- * @see org.junit.runners.ParentRunner#getDescription()
- */
- @Override
- public Description getDescription() {
-
- Description description = Description.createSuiteDescription(getName(), getRunnerAnnotations());
-
- getFilteredChildren().stream().map(this::describeChild).forEach(description::addChild);
-
- return description;
- }
-
- /*
- * (non-Javadoc)
- * @see org.junit.runners.ParentRunner#filter(org.junit.runner.manipulation.Filter)
- */
- public void filter(Filter filter) throws NoTestsRemainException {
-
- synchronized (childrenLock) {
-
- List children = new ArrayList<>(getFilteredChildren());
- List filtered = children.stream().filter(it -> {
-
- if (filter.shouldRun(describeChild(it))) {
- try {
- filter.apply(it);
- return true;
- } catch (NoTestsRemainException e) {
- return false;
- }
- }
- return false;
- }).collect(Collectors.toList());
-
- if (filtered.isEmpty()) {
- throw new NoTestsRemainException();
- }
-
- filteredChildren = Collections.unmodifiableCollection(filtered);
- }
- }
-
- /*
- * (non-Javadoc)
- * @see org.junit.runners.ParentRunner#sort(org.junit.runner.manipulation.Sorter)
- */
- public void sort(Sorter sorter) {
-
- synchronized (childrenLock) {
-
- getFilteredChildren().forEach(sorter::apply);
-
- List sortedChildren = new ArrayList<>(getFilteredChildren());
-
- sortedChildren.sort((o1, o2) -> sorter.compare(describeChild(o1), describeChild(o2)));
-
- filteredChildren = Collections.unmodifiableCollection(sortedChildren);
- }
- }
-
- /**
- * Run matching {@link org.openjdk.jmh.annotations.Benchmark} methods with options collected from
- * {@link org.springframework.core.env.Environment}.
- */
- @Override
- protected Statement childrenInvoker(RunNotifier notifier) {
-
- Collection methods = getFilteredChildren();
- CacheFunction cache = new CacheFunction(methods, this::describeChild);
-
- if (methods.isEmpty()) {
- return new Statement() {
- @Override
- public void evaluate() {}
- };
- }
-
- return new Statement() {
-
- @Override
- public void evaluate() throws Throwable {
- try {
- doRun(notifier, methods, cache);
- } catch (NoBenchmarksException | NoTestsRemainException e) {
- methods.forEach(it -> notifier.fireTestIgnored(describeChild(it)));
- }
- }
- };
- }
-
- void doRun(RunNotifier notifier, Collection methods, CacheFunction cache) throws Exception {
-
- Class> jmhTestClass = getTestClass().getJavaClass();
- List includes = jmhRunner.includes(jmhTestClass, methods);
-
- if (includes.isEmpty()) {
- throw new NoTestsRemainException();
- }
-
- ChainedOptionsBuilder optionsBuilder = jmhRunner.options(jmhTestClass);
-
- includes.forEach(optionsBuilder::include);
-
- Options options = optionsBuilder.build();
- NotifyingOutputFormat notifyingOutputFormat = new NotifyingOutputFormat(notifier, cache,
- createOutputFormat(options));
-
- jmhRunner.publishResults(new Runner(options, notifyingOutputFormat).run());
- }
-
- private Collection getFilteredChildren() {
-
- if (filteredChildren == null) {
- synchronized (childrenLock) {
- if (filteredChildren == null) {
- filteredChildren = Collections.unmodifiableCollection(getChildren());
- }
- }
- }
- return filteredChildren;
- }
-
- private static OutputFormat createOutputFormat(Options options) {
-
- // sadly required here as the check cannot be made before calling this method in constructor
- if (options == null) {
- throw new IllegalArgumentException("Options not allowed to be null.");
- }
-
- PrintStream out;
- if (options.getOutput().hasValue()) {
- try {
- out = new PrintStream(options.getOutput().get());
- } catch (FileNotFoundException ex) {
- throw new IllegalStateException(ex);
- }
- } else {
- // Protect the System.out from accidental closing
- try {
- out = new UnCloseablePrintStream(System.out, Utils.guessConsoleEncoding());
- } catch (UnsupportedEncodingException ex) {
- throw new IllegalStateException(ex);
- }
- }
-
- return OutputFormatFactory.createFormatInstance(out, options.verbosity().orElse(Defaults.VERBOSITY));
- }
-
- private static String getBenchmarkName(FrameworkMethod it) {
- return it.getDeclaringClass().getName() + "." + it.getName();
- }
-
- /**
- * {@link OutputFormat} that delegates to another {@link OutputFormat} and notifies {@link RunNotifier} about the
- * progress.
- */
- static class NotifyingOutputFormat implements OutputFormat {
-
- private final RunNotifier notifier;
- private final Function descriptionResolver;
- private final OutputFormat delegate;
- private final List log = new CopyOnWriteArrayList<>();
-
- private volatile String lastKnownBenchmark;
- private volatile boolean recordOutput;
-
- NotifyingOutputFormat(RunNotifier notifier, Function methods, OutputFormat delegate) {
- this.notifier = notifier;
- this.descriptionResolver = methods;
- this.delegate = delegate;
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#iteration(org.openjdk.jmh.infra.BenchmarkParams, org.openjdk.jmh.infra.IterationParams, int)
- */
- @Override
- public void iteration(BenchmarkParams benchParams, IterationParams params, int iteration) {
- delegate.iteration(benchParams, params, iteration);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#iterationResult(org.openjdk.jmh.infra.BenchmarkParams, org.openjdk.jmh.infra.IterationParams, int, org.openjdk.jmh.results.IterationResult)
- */
- @Override
- public void iterationResult(BenchmarkParams benchParams, IterationParams params, int iteration,
- IterationResult data) {
- delegate.iterationResult(benchParams, params, iteration, data);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#startBenchmark(org.openjdk.jmh.infra.BenchmarkParams)
- */
- @Override
- public void startBenchmark(BenchmarkParams benchParams) {
-
- log.clear();
-
- lastKnownBenchmark = benchParams.getBenchmark();
- notifier.fireTestStarted(descriptionResolver.apply(benchParams.getBenchmark()));
-
- delegate.startBenchmark(benchParams);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#endBenchmark(org.openjdk.jmh.results.BenchmarkResult)
- */
- @Override
- public void endBenchmark(BenchmarkResult result) {
-
- recordOutput = false;
- String lastKnownBenchmark = this.lastKnownBenchmark;
- if (result != null) {
- notifier.fireTestFinished(descriptionResolver.apply(result.getParams().getBenchmark()));
- } else if (lastKnownBenchmark != null) {
-
- String output = StringUtils.collectionToDelimitedString(log, System.getProperty("line.separator"));
- notifier.fireTestFailure(
- new Failure(descriptionResolver.apply(lastKnownBenchmark), new JmhRunnerException(output)));
- }
-
- log.clear();
- delegate.endBenchmark(result);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#startRun()
- */
- @Override
- public void startRun() {
- delegate.startRun();
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#endRun(java.util.Collection)
- */
- @Override
- public void endRun(Collection result) {
- delegate.endRun(result);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#print(java.lang.String)
- */
- @Override
- public void print(String s) {
- delegate.print(s);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#println(java.lang.String)
- */
- @Override
- public void println(String s) {
-
- if (recordOutput && StringUtils.hasText(s)) {
- log.add(s);
- }
-
- if (s.equals("")) {
- recordOutput = true;
- }
-
- delegate.println(s);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#flush()
- */
- @Override
- public void flush() {
- delegate.flush();
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#close()
- */
- @Override
- public void close() {
- delegate.close();
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#verbosePrintln(java.lang.String)
- */
- @Override
- public void verbosePrintln(String s) {
- delegate.verbosePrintln(s);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#write(int)
- */
- @Override
- public void write(int b) {
- delegate.write(b);
- }
-
- /*
- * (non-Javadoc)
- * @see org.openjdk.jmh.runner.format.OutputFormat#write(byte[])
- */
- @Override
- public void write(byte[] b) throws IOException {
- delegate.write(b);
- }
- }
-
- /**
- * Exception proxy without stack trace.
- */
- static class JmhRunnerException extends RuntimeException {
-
- private static final long serialVersionUID = -1385006784559013618L;
-
- JmhRunnerException(String message) {
- super(message);
- }
-
- /*
- * (non-Javadoc)
- * @see java.lang.Throwable#fillInStackTrace()
- */
- @Override
- public synchronized Throwable fillInStackTrace() {
- return null;
- }
- }
-
- /**
- * Cache {@link Function} for benchmark names to {@link Description}.
- */
- static class CacheFunction implements Function {
-
- private final Map methodMap = new ConcurrentHashMap<>();
- private final Collection methods;
- private final Function describeFunction;
-
- CacheFunction(Collection methods, Function describeFunction) {
- this.methods = methods;
- this.describeFunction = describeFunction;
- }
-
- /**
- * Resolve a benchmark name (fqcn + "." + method name) to a {@link Description}.
- *
- * @param benchmarkName
- * @return
- */
- public Description apply(String benchmarkName) {
-
- FrameworkMethod frameworkMethod = methodMap.computeIfAbsent(benchmarkName, key -> {
-
- Optional method = methods.stream().filter(it -> getBenchmarkName(it).equals(key)).findFirst();
-
- return method.orElseThrow(() -> new IllegalArgumentException(
- String.format("Cannot resolve %s to a FrameworkMethod!", benchmarkName)));
- });
-
- return describeFunction.apply(frameworkMethod);
- }
- }
-
-}
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MicrobenchmarkResultsWriterFactory.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MicrobenchmarkResultsWriterFactory.java
new file mode 100644
index 0000000..b3986bd
--- /dev/null
+++ b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MicrobenchmarkResultsWriterFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 the original author or authors.
+ *
+ * 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 org.springframework.data.microbenchmark.common;
+
+import jmh.mbr.core.ResultsWriter;
+import jmh.mbr.core.ResultsWriterFactory;
+
+/**
+ * {@link ResultsWriterFactory} plugin via {@link java.util.ServiceLoader}.
+ *
+ * @author Mark Paluch
+ */
+public class MicrobenchmarkResultsWriterFactory implements ResultsWriterFactory {
+
+ @Override
+ public ResultsWriter forUri(String uri) {
+
+ if (uri.startsWith("http")) {
+ return new HttpResultsWriter(uri);
+ }
+
+ if (uri.startsWith("mongo")) {
+ return new MongoResultsWriter(uri);
+ }
+
+ return null;
+ }
+}
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MongoResultsWriter.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MongoResultsWriter.java
index 3881711..9ce7e9c 100644
--- a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MongoResultsWriter.java
+++ b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/MongoResultsWriter.java
@@ -15,13 +15,18 @@
*/
package org.springframework.data.microbenchmark.common;
+import jmh.mbr.core.ResultsWriter;
+import lombok.RequiredArgsConstructor;
+
import java.util.Collection;
import java.util.Date;
import java.util.List;
import org.bson.Document;
import org.openjdk.jmh.results.RunResult;
+import org.openjdk.jmh.runner.format.OutputFormat;
import org.springframework.core.env.StandardEnvironment;
+import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -32,21 +37,31 @@ import com.mongodb.client.MongoDatabase;
import com.mongodb.util.JSON;
/**
- * MongoDB specific {@link ResultsWriter} implementation.
+ * MongoDB specific {@link ResultsWriterOld} implementation.
*
* @author Christoph Strobl
- * @since 2.0
+ * @author Mark Paluch
*/
+@RequiredArgsConstructor
class MongoResultsWriter implements ResultsWriter {
private final String uri;
- MongoResultsWriter(String uri) {
- this.uri = uri;
+ @Override
+ public void write(OutputFormat output, Collection results) {
+
+ if (CollectionUtils.isEmpty(results)) {
+ return;
+ }
+
+ try {
+ doWrite(results);
+ } catch (RuntimeException e) {
+ output.println("Failed to write results: " + e.toString());
+ }
}
- @Override
- public void write(Collection results) {
+ private void doWrite(Collection results) {
Date now = new Date();
StandardEnvironment env = new StandardEnvironment();
@@ -89,7 +104,7 @@ class MongoResultsWriter implements ResultsWriter {
* @param doc
* @return
*/
- private Document fixDocumentKeys(Document doc) {
+ private static Document fixDocumentKeys(Document doc) {
Document sanitized = new Document();
diff --git a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/ResultsWriter.java b/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/ResultsWriter.java
deleted file mode 100644
index 3e14ac9..0000000
--- a/benchmark/support/src/main/java/org/springframework/data/microbenchmark/common/ResultsWriter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2018 the original author or authors.
- *
- * 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
- *
- * https://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.springframework.data.microbenchmark.common;
-
-import lombok.SneakyThrows;
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-
-import org.openjdk.jmh.results.RunResult;
-import org.openjdk.jmh.results.format.ResultFormatFactory;
-import org.openjdk.jmh.results.format.ResultFormatType;
-
-/**
- * @author Christoph Strobl
- * @since 2.0
- */
-interface ResultsWriter {
-
- /**
- * Write the {@link RunResult}s.
- *
- * @param results can be {@literal null}.
- */
- void write(Collection results);
-
- /**
- * Get the uri specific {@link ResultsWriter}.
- *
- * @param uri must not be {@literal null}.
- * @return
- */
- static ResultsWriter forUri(String uri) {
- return uri.startsWith("mongodb:") ? new MongoResultsWriter(uri) : new HttpResultsWriter(uri);
- }
-
- /**
- * Convert {@link RunResult}s to JMH Json representation.
- *
- * @param results
- * @return json string representation of results.
- * @see org.openjdk.jmh.results.format.JSONResultFormat
- */
- @SneakyThrows
- static String jsonifyResults(Collection results) {
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ResultFormatFactory.getInstance(ResultFormatType.JSON, new PrintStream(baos, true, "UTF-8")).writeOut(results);
-
- return new String(baos.toByteArray(), StandardCharsets.UTF_8);
- }
-}
diff --git a/benchmark/support/src/main/resources/META-INF/services/jmh.mbr.core.ResultsWriterFactory b/benchmark/support/src/main/resources/META-INF/services/jmh.mbr.core.ResultsWriterFactory
new file mode 100644
index 0000000..eebba55
--- /dev/null
+++ b/benchmark/support/src/main/resources/META-INF/services/jmh.mbr.core.ResultsWriterFactory
@@ -0,0 +1 @@
+org.springframework.data.microbenchmark.common.MicrobenchmarkResultsWriterFactory