#97 - Remove Microbenchmark runner in favor of mp911de/microbenchmark-runner.
This commit is contained in:
@@ -45,6 +45,12 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.mp911de.microbenchmark-runner</groupId>
|
||||||
|
<artifactId>microbenchmark-runner-junit4</artifactId>
|
||||||
|
<version>0.1.0.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
@@ -119,6 +125,10 @@
|
|||||||
<id>spring-libs-snapshot</id>
|
<id>spring-libs-snapshot</id>
|
||||||
<url>https://repo.spring.io/libs-snapshot</url>
|
<url>https://repo.spring.io/libs-snapshot</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<pluginRepositories>
|
<pluginRepositories>
|
||||||
|
|||||||
@@ -21,6 +21,11 @@
|
|||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.mp911de.microbenchmark-runner</groupId>
|
||||||
|
<artifactId>microbenchmark-runner-junit4</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.microbenchmark.common;
|
package org.springframework.data.microbenchmark.common;
|
||||||
|
|
||||||
|
import jmh.mbr.junit4.Microbenchmark;
|
||||||
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.openjdk.jmh.annotations.Fork;
|
import org.openjdk.jmh.annotations.Fork;
|
||||||
import org.openjdk.jmh.annotations.Measurement;
|
import org.openjdk.jmh.annotations.Measurement;
|
||||||
@@ -29,9 +31,10 @@ import org.openjdk.jmh.annotations.Warmup;
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @see Microbenchmark
|
* @see Microbenchmark
|
||||||
*/
|
*/
|
||||||
@Warmup(iterations = JmhSupport.WARMUP_ITERATIONS)
|
@Warmup(iterations = 5)
|
||||||
@Measurement(iterations = JmhSupport.MEASUREMENT_ITERATIONS)
|
@Measurement(iterations = 10)
|
||||||
@Fork(JmhSupport.FORKS)
|
@Fork(value = 1, jvmArgs = { "-server", "-XX:+HeapDumpOnOutOfMemoryError", "-Xms1024m", "-Xmx1024m",
|
||||||
|
"-XX:MaxDirectMemorySize=1024m" })
|
||||||
@State(Scope.Thread)
|
@State(Scope.Thread)
|
||||||
@RunWith(Microbenchmark.class)
|
@RunWith(Microbenchmark.class)
|
||||||
public abstract class AbstractMicrobenchmark {
|
public abstract class AbstractMicrobenchmark {
|
||||||
|
|||||||
@@ -15,8 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.microbenchmark.common;
|
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.io.OutputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -26,30 +28,37 @@ import java.time.Duration;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.openjdk.jmh.results.RunResult;
|
import org.openjdk.jmh.results.RunResult;
|
||||||
|
import org.openjdk.jmh.runner.format.OutputFormat;
|
||||||
import org.springframework.core.env.StandardEnvironment;
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ResultsWriter} implementation of {@link URLConnection}.
|
* {@link ResultsWriterOld} implementation of {@link URLConnection}.
|
||||||
*
|
*
|
||||||
* @since 2.0
|
* @author Christoph Strobl
|
||||||
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
class HttpResultsWriter implements ResultsWriter {
|
class HttpResultsWriter implements ResultsWriter {
|
||||||
|
|
||||||
private final String url;
|
private final String url;
|
||||||
|
|
||||||
HttpResultsWriter(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
public void write(OutputFormat output, Collection<RunResult> results) {
|
||||||
public void write(Collection<RunResult> results) {
|
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(results)) {
|
if (CollectionUtils.isEmpty(results)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
doWrite(results);
|
||||||
|
} catch (IOException e) {
|
||||||
|
output.println("Failed to write results: " + e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doWrite(Collection<RunResult> results) throws IOException {
|
||||||
|
|
||||||
StandardEnvironment env = new StandardEnvironment();
|
StandardEnvironment env = new StandardEnvironment();
|
||||||
|
|
||||||
String projectVersion = env.getProperty("project.version", "unknown");
|
String projectVersion = env.getProperty("project.version", "unknown");
|
||||||
|
|||||||
@@ -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. <br />
|
|
||||||
* 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<String> includes(Class<?> testClass, Collection<FrameworkMethod> 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<RunResult> 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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<FrameworkMethod> 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<Throwable> 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<FrameworkMethod> computeTestMethods() {
|
|
||||||
|
|
||||||
List<FrameworkMethod> 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<FrameworkMethod> children = new ArrayList<>(getFilteredChildren());
|
|
||||||
List<FrameworkMethod> 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<FrameworkMethod> 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<FrameworkMethod> 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<FrameworkMethod> methods, CacheFunction cache) throws Exception {
|
|
||||||
|
|
||||||
Class<?> jmhTestClass = getTestClass().getJavaClass();
|
|
||||||
List<String> 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<FrameworkMethod> 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<String, Description> descriptionResolver;
|
|
||||||
private final OutputFormat delegate;
|
|
||||||
private final List<String> log = new CopyOnWriteArrayList<>();
|
|
||||||
|
|
||||||
private volatile String lastKnownBenchmark;
|
|
||||||
private volatile boolean recordOutput;
|
|
||||||
|
|
||||||
NotifyingOutputFormat(RunNotifier notifier, Function<String, Description> 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<RunResult> 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("<failure>")) {
|
|
||||||
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<String, Description> {
|
|
||||||
|
|
||||||
private final Map<String, FrameworkMethod> methodMap = new ConcurrentHashMap<>();
|
|
||||||
private final Collection<FrameworkMethod> methods;
|
|
||||||
private final Function<FrameworkMethod, Description> describeFunction;
|
|
||||||
|
|
||||||
CacheFunction(Collection<FrameworkMethod> methods, Function<FrameworkMethod, Description> 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<FrameworkMethod> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,13 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.microbenchmark.common;
|
package org.springframework.data.microbenchmark.common;
|
||||||
|
|
||||||
|
import jmh.mbr.core.ResultsWriter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.openjdk.jmh.results.RunResult;
|
import org.openjdk.jmh.results.RunResult;
|
||||||
|
import org.openjdk.jmh.runner.format.OutputFormat;
|
||||||
import org.springframework.core.env.StandardEnvironment;
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -32,21 +37,31 @@ import com.mongodb.client.MongoDatabase;
|
|||||||
import com.mongodb.util.JSON;
|
import com.mongodb.util.JSON;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MongoDB specific {@link ResultsWriter} implementation.
|
* MongoDB specific {@link ResultsWriterOld} implementation.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @since 2.0
|
* @author Mark Paluch
|
||||||
*/
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
class MongoResultsWriter implements ResultsWriter {
|
class MongoResultsWriter implements ResultsWriter {
|
||||||
|
|
||||||
private final String uri;
|
private final String uri;
|
||||||
|
|
||||||
MongoResultsWriter(String uri) {
|
@Override
|
||||||
this.uri = uri;
|
public void write(OutputFormat output, Collection<RunResult> results) {
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(results)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
doWrite(results);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
output.println("Failed to write results: " + e.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void doWrite(Collection<RunResult> results) {
|
||||||
public void write(Collection<RunResult> results) {
|
|
||||||
|
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
StandardEnvironment env = new StandardEnvironment();
|
StandardEnvironment env = new StandardEnvironment();
|
||||||
@@ -89,7 +104,7 @@ class MongoResultsWriter implements ResultsWriter {
|
|||||||
* @param doc
|
* @param doc
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Document fixDocumentKeys(Document doc) {
|
private static Document fixDocumentKeys(Document doc) {
|
||||||
|
|
||||||
Document sanitized = new Document();
|
Document sanitized = new Document();
|
||||||
|
|
||||||
|
|||||||
@@ -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<RunResult> 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<RunResult> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
org.springframework.data.microbenchmark.common.MicrobenchmarkResultsWriterFactory
|
||||||
Reference in New Issue
Block a user