diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/JmhRunner.java b/jmh-client/src/main/java/com/openelements/jmh/client/JmhRunner.java index f890922a..e1ef5835 100644 --- a/jmh-client/src/main/java/com/openelements/jmh/client/JmhRunner.java +++ b/jmh-client/src/main/java/com/openelements/jmh/client/JmhRunner.java @@ -2,9 +2,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.openelements.jmh.common.BenchmarkExecution; -import com.openelements.jmh.client.factory.BenchmarkFactory; +import com.openelements.jmh.client.jmh.BenchmarkFactory; import com.openelements.jmh.client.json.BenchmarkJsonFactory; +import com.openelements.jmh.common.BenchmarkExecution; import java.io.FileWriter; import java.io.IOException; import java.util.Collection; @@ -18,45 +18,46 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; +@Deprecated public class JmhRunner { - private final Set classes; + private final Set classes; - public JmhRunner() { - this.classes = new HashSet<>(); - } + public JmhRunner() { + this.classes = new HashSet<>(); + } - public void addBenchmarkClass(final Class cls) { - classes.add(cls); - } + public void addBenchmarkClass(final Class cls) { + classes.add(cls); + } - public void run() throws RunnerException { - final OptionsBuilder optionsBuilder = new OptionsBuilder(); - classes.forEach(cls -> optionsBuilder.getIncludes().add(cls.getName())); - final Runner runner = new Runner(optionsBuilder.build()); - Collection run = runner.run(); + public void run() throws RunnerException { + final OptionsBuilder optionsBuilder = new OptionsBuilder(); + classes.forEach(cls -> optionsBuilder.getIncludes().add(cls.getName())); + final Runner runner = new Runner(optionsBuilder.build()); + Collection run = runner.run(); + + final Gson gson = new GsonBuilder().create(); + String jsonString = gson.toJson(run); + try (final FileWriter fileWriter = new FileWriter("raw-jmh-data.json")) { + fileWriter.write(jsonString); + } catch (final IOException e) { + e.printStackTrace(); + } + + Set results = run.stream() + .map(BenchmarkFactory::convert) + .collect(Collectors.toSet()); + + results.stream().forEach(benchmark -> { + final String json = BenchmarkJsonFactory.toJson(benchmark); + final String filename = UUID.randomUUID().toString() + ".json"; + try (final FileWriter fileWriter = new FileWriter(filename)) { + fileWriter.write(json); + } catch (final IOException e) { + e.printStackTrace(); + } + }); - final Gson gson = new GsonBuilder().create(); - String jsonString = gson.toJson(run); - try (final FileWriter fileWriter = new FileWriter("raw-jmh-data.json")) { - fileWriter.write(jsonString); - } catch (final IOException e) { - e.printStackTrace(); } - - Set results = run.stream() - .map(BenchmarkFactory::convert) - .collect(Collectors.toSet()); - - results.stream().forEach(benchmark -> { - final String json = BenchmarkJsonFactory.toJson(benchmark); - final String filename = UUID.randomUUID().toString() + ".json"; - try (final FileWriter fileWriter = new FileWriter(filename)) { - fileWriter.write(json); - } catch (final IOException e) { - e.printStackTrace(); - } - }); - - } } diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/JmhUploader.java b/jmh-client/src/main/java/com/openelements/jmh/client/JmhUploader.java index 9a2847a1..baa5435b 100644 --- a/jmh-client/src/main/java/com/openelements/jmh/client/JmhUploader.java +++ b/jmh-client/src/main/java/com/openelements/jmh/client/JmhUploader.java @@ -1,12 +1,8 @@ package com.openelements.jmh.client; +import com.openelements.jmh.client.io.RestClient; +import com.openelements.jmh.client.jmh.BenchmarkFactory; import com.openelements.jmh.common.BenchmarkExecution; -import com.openelements.jmh.client.factory.BenchmarkFactory; -import com.openelements.jmh.client.json.BenchmarkJsonFactory; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -17,47 +13,37 @@ import org.openjdk.jmh.runner.options.OptionsBuilder; +@Deprecated public class JmhUploader { - private final Set classes; - - public JmhUploader() { - this.classes = new HashSet<>(); - } - - public void addBenchmarkClass(final Class cls) { - classes.add(cls); - } - - public void run() throws RunnerException { - final OptionsBuilder optionsBuilder = new OptionsBuilder(); - classes.forEach(cls -> optionsBuilder.getIncludes().add(cls.getName())); - final Runner runner = new Runner(optionsBuilder.build()); - Collection run = runner.run(); - - Set results = run.stream() - .map(result -> BenchmarkFactory.convert(result)) - .collect(Collectors.toSet()); - - results.stream().forEach(benchmark -> { - final String json = BenchmarkJsonFactory.toJson(benchmark); - - try { - final HttpRequest request = HttpRequest.newBuilder() - .uri(new URI("http://localhost:8080/benchmark")) - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(json)) - .build(); - - final HttpResponse response = HttpClient - .newBuilder() - .build() - .send(request, HttpResponse.BodyHandlers.discarding()); - System.out.println(response); - } catch (Exception e) { - e.printStackTrace(); - } - }); - - } + private final Set classes; + + public JmhUploader() { + this.classes = new HashSet<>(); + } + + public void addBenchmarkClass(final Class cls) { + classes.add(cls); + } + + public void run() throws RunnerException { + final OptionsBuilder optionsBuilder = new OptionsBuilder(); + classes.forEach(cls -> optionsBuilder.getIncludes().add(cls.getName())); + final Runner runner = new Runner(optionsBuilder.build()); + Collection run = runner.run(); + + final Set results = run.stream() + .map(result -> BenchmarkFactory.convert(result)) + .collect(Collectors.toSet()); + + final RestClient restClient = new RestClient("http://localhost:8080"); + results.stream().forEach(benchmark -> { + try { + restClient.post(benchmark); + } catch (Exception e) { + e.printStackTrace(); + } + }); + + } } diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/Main.java b/jmh-client/src/main/java/com/openelements/jmh/client/Main.java new file mode 100644 index 00000000..cf7e0bf1 --- /dev/null +++ b/jmh-client/src/main/java/com/openelements/jmh/client/Main.java @@ -0,0 +1,24 @@ +package com.openelements.jmh.client; + +import com.openelements.jmh.client.io.FileClient; +import com.openelements.jmh.client.io.RestClient; +import com.openelements.jmh.client.jmh.BenchmarkFactory; +import com.openelements.jmh.client.jmh.JmhExecutor; + +public class Main { + + public static void main(String[] args) throws Exception { + final RestClient restClient = new RestClient(); + final FileClient fileClient = new FileClient("target/benchmark/"); + JmhExecutor.executeAll().stream() + .map(BenchmarkFactory::convert) + .forEach(benchmarkExecution -> { + try { + fileClient.write(benchmarkExecution); + restClient.post(benchmarkExecution); + } catch (final Exception e) { + throw new RuntimeException("Error in posting result", e); + } + }); + } +} diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/io/FileClient.java b/jmh-client/src/main/java/com/openelements/jmh/client/io/FileClient.java new file mode 100644 index 00000000..511d23a1 --- /dev/null +++ b/jmh-client/src/main/java/com/openelements/jmh/client/io/FileClient.java @@ -0,0 +1,42 @@ +package com.openelements.jmh.client.io; + +import com.openelements.jmh.client.json.BenchmarkJsonFactory; +import com.openelements.jmh.common.BenchmarkExecution; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Collection; +import java.util.Objects; + +public class FileClient { + + private final Path directory; + + public FileClient(@NonNull final String directoryPath) { + this(Path.of(directoryPath)); + } + + public FileClient(@NonNull final Path directory) { + this.directory = Objects.requireNonNull(directory, "directory must not be null"); + } + + public void write(@NonNull final Collection benchmarkExecutions) throws Exception { + Objects.requireNonNull(benchmarkExecutions, "benchmarkExecutions must not be null"); + for (final BenchmarkExecution benchmarkExecution : benchmarkExecutions) { + write(benchmarkExecution); + } + } + + public void write(@NonNull final BenchmarkExecution benchmarkExecution) throws Exception { + Objects.requireNonNull(benchmarkExecution, "benchmarkExecution must not be null"); + directory.toFile().mkdirs(); + final File file = new File(directory.toFile(), benchmarkExecution.benchmarkName() + ".json"); + final String json = BenchmarkJsonFactory.toJson(benchmarkExecution); + Files.deleteIfExists(file.toPath()); + Files.writeString(file.toPath(), json, StandardCharsets.UTF_8, StandardOpenOption.WRITE, + StandardOpenOption.CREATE); + } +} diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/io/RestClient.java b/jmh-client/src/main/java/com/openelements/jmh/client/io/RestClient.java new file mode 100644 index 00000000..f4ba03de --- /dev/null +++ b/jmh-client/src/main/java/com/openelements/jmh/client/io/RestClient.java @@ -0,0 +1,58 @@ +package com.openelements.jmh.client.io; + +import com.openelements.jmh.client.json.BenchmarkJsonFactory; +import com.openelements.jmh.common.BenchmarkExecution; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublisher; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandler; +import java.util.Objects; + +public class RestClient { + + public static final String CONTENT_TYPE_HEADER_NAME = "Content-Type"; + public static final String CONTENT_TYPE_HEADER_VALUE = "application/json"; + public static final String LOCALHOST = "http://localhost:8080"; + private final String baseUrl; + + public RestClient(@NonNull String baseUrl) { + this.baseUrl = Objects.requireNonNull(baseUrl, "baseUrl must not be null"); + } + + public RestClient() { + this(LOCALHOST); + } + + public void post(@NonNull BenchmarkExecution benchmarkExecution) throws Exception { + final String json = BenchmarkJsonFactory.toJson(benchmarkExecution); + post(json); + } + + private void post(@NonNull String json) throws Exception { + final BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.ofString(json); + final HttpRequest request = HttpRequest.newBuilder() + .uri(getUrl()) + .header(CONTENT_TYPE_HEADER_NAME, CONTENT_TYPE_HEADER_VALUE) + .POST(bodyPublisher) + .build(); + + final HttpClient httpClient = HttpClient.newBuilder().build(); + final BodyHandler bodyHandler = HttpResponse.BodyHandlers.discarding(); + final HttpResponse response = httpClient.send(request, bodyHandler); + System.out.println(response); + } + + @NonNull + private URI getUrl() throws URISyntaxException { + if (baseUrl.endsWith("/")) { + return new URI(baseUrl + "api/benchmark"); + } else { + return new URI(baseUrl + "/api/benchmark"); + } + } + +} diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/factory/BenchmarkFactory.java b/jmh-client/src/main/java/com/openelements/jmh/client/jmh/BenchmarkFactory.java similarity index 73% rename from jmh-client/src/main/java/com/openelements/jmh/client/factory/BenchmarkFactory.java rename to jmh-client/src/main/java/com/openelements/jmh/client/jmh/BenchmarkFactory.java index 1490fdd7..49206861 100644 --- a/jmh-client/src/main/java/com/openelements/jmh/client/factory/BenchmarkFactory.java +++ b/jmh-client/src/main/java/com/openelements/jmh/client/jmh/BenchmarkFactory.java @@ -1,40 +1,47 @@ -package com.openelements.jmh.client.factory; +package com.openelements.jmh.client.jmh; -import com.openelements.jmh.common.BenchmarkExecution; import com.openelements.jmh.common.BenchmarkConfiguration; +import com.openelements.jmh.common.BenchmarkExecution; import com.openelements.jmh.common.BenchmarkExecutionMetadata; +import com.openelements.jmh.common.BenchmarkExecutionResult; import com.openelements.jmh.common.BenchmarkInfrastructure; import com.openelements.jmh.common.BenchmarkMeasurementConfiguration; import com.openelements.jmh.common.BenchmarkType; -import com.openelements.jmh.common.BenchmarkExecutionResult; import com.openelements.jmh.common.BenchmarkUnit; import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.Objects; -import org.openjdk.jmh.infra.BenchmarkParams; -import org.openjdk.jmh.infra.IterationParams; -import org.openjdk.jmh.results.RunResult; - import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.time.Instant; +import java.util.Collection; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.infra.BenchmarkParams; +import org.openjdk.jmh.infra.IterationParams; +import org.openjdk.jmh.results.RunResult; public class BenchmarkFactory { private BenchmarkFactory() { } + public static Collection convert(@NonNull final Collection jmhResults) { + Objects.requireNonNull(jmhResults, "jmhResults must not be null"); + return jmhResults.stream().map(BenchmarkFactory::convert).toList(); + } + @NonNull public static BenchmarkExecution convert(@NonNull final RunResult jmhResult) { Objects.requireNonNull(jmhResult, "jmhResult must not be null"); final BenchmarkInfrastructure infrastructure = convertToBenchmarkInfrastructure(jmhResult.getParams()); final BenchmarkConfiguration configuration = convertToBenchmarkConfiguration(jmhResult.getParams()); - final org.openjdk.jmh.results.BenchmarkResult benchmarkResult = jmhResult.getBenchmarkResults().stream().findFirst().orElseThrow(); + final org.openjdk.jmh.results.BenchmarkResult benchmarkResult = jmhResult.getBenchmarkResults().stream() + .findFirst().orElseThrow(); final BenchmarkExecutionMetadata execution = convertToBenchmarkExecution(benchmarkResult); final BenchmarkExecutionResult result = convertToBenchmarkResult(benchmarkResult.getPrimaryResult()); final String benchmarkName = jmhResult.getParams().getBenchmark(); - final BenchmarkExecution benchmark = new BenchmarkExecution(benchmarkName, BenchmarkType.THROUGHPUT, infrastructure, configuration, execution, result); + final BenchmarkExecution benchmark = new BenchmarkExecution(benchmarkName, BenchmarkType.THROUGHPUT, + infrastructure, configuration, execution, result); return benchmark; } @@ -54,11 +61,13 @@ private static BenchmarkInfrastructure convertToBenchmarkInfrastructure(@NonNull final int availableProcessors = osBean.getAvailableProcessors(); final String osVersion = osBean.getVersion(); final String osName = osBean.getName(); - return new BenchmarkInfrastructure(arch, availableProcessors, memory, osName, osVersion, jvmVersion, jvmName, jmhVersion); + return new BenchmarkInfrastructure(arch, availableProcessors, memory, osName, osVersion, jvmVersion, jvmName, + jmhVersion); } @NonNull - private static BenchmarkMeasurementConfiguration convertToBenchmarkMeasurementConfiguration(@NonNull final IterationParams params) { + private static BenchmarkMeasurementConfiguration convertToBenchmarkMeasurementConfiguration( + @NonNull final IterationParams params) { Objects.requireNonNull(params, "params must not be null"); final int warmupIterations = params.getCount(); final int warmupBatchSize = params.getBatchSize(); @@ -70,28 +79,48 @@ private static BenchmarkMeasurementConfiguration convertToBenchmarkMeasurementCo @NonNull private static BenchmarkConfiguration convertToBenchmarkConfiguration(@NonNull final BenchmarkParams params) { Objects.requireNonNull(params, "params must not be null"); - final BenchmarkMeasurementConfiguration warmupConfiguration = convertToBenchmarkMeasurementConfiguration(params.getWarmup()); - final BenchmarkMeasurementConfiguration measurementConfiguration = convertToBenchmarkMeasurementConfiguration(params.getMeasurement()); + final BenchmarkMeasurementConfiguration warmupConfiguration = convertToBenchmarkMeasurementConfiguration( + params.getWarmup()); + final BenchmarkMeasurementConfiguration measurementConfiguration = convertToBenchmarkMeasurementConfiguration( + params.getMeasurement()); final int threads = params.getThreads(); final int forks = params.getForks(); final long timeout = params.getTimeout().getTime(); final TimeUnit timeoutTimeunit = params.getTimeout().getTimeUnit(); - return new BenchmarkConfiguration(threads, forks, timeout, timeoutTimeunit, measurementConfiguration, warmupConfiguration); + return new BenchmarkConfiguration(threads, forks, timeout, timeoutTimeunit, measurementConfiguration, + warmupConfiguration); } @NonNull - private static BenchmarkExecutionResult convertToBenchmarkResult(@NonNull final org.openjdk.jmh.results.Result benchmarkResult) { + private static BenchmarkExecutionResult convertToBenchmarkResult( + @NonNull final org.openjdk.jmh.results.Result benchmarkResult) { Objects.requireNonNull(benchmarkResult, "benchmarkResult must not be null"); final String unit = benchmarkResult.getScoreUnit(); final double value = benchmarkResult.getScore(); - final double error = benchmarkResult.getScoreError(); - final double min = benchmarkResult.getStatistics().getMin(); - final double max = benchmarkResult.getStatistics().getMax(); + final Double error; + if (Objects.equals(benchmarkResult.getScoreError(), Double.NaN)) { + error = null; + } else { + error = benchmarkResult.getScoreError(); + } + final Double min; + if (Objects.equals(benchmarkResult.getStatistics().getMin(), Double.NaN)) { + min = null; + } else { + min = benchmarkResult.getStatistics().getMin(); + } + final Double max; + if (Objects.equals(benchmarkResult.getStatistics().getMax(), Double.NaN)) { + max = null; + } else { + max = benchmarkResult.getStatistics().getMax(); + } return new BenchmarkExecutionResult(value, error, min, max, BenchmarkUnit.getForJmhName(unit)); } @NonNull - private static BenchmarkExecutionMetadata convertToBenchmarkExecution(@NonNull final org.openjdk.jmh.results.BenchmarkResult benchmarkResult) { + private static BenchmarkExecutionMetadata convertToBenchmarkExecution( + @NonNull final org.openjdk.jmh.results.BenchmarkResult benchmarkResult) { Objects.requireNonNull(benchmarkResult, "benchmarkResult must not be null"); final Instant startTimeInstant = Instant.ofEpochMilli(benchmarkResult.getMetadata().getStartTime()); final Instant warmupTimeInstant = Instant.ofEpochMilli(benchmarkResult.getMetadata().getWarmupTime()); @@ -99,7 +128,8 @@ private static BenchmarkExecutionMetadata convertToBenchmarkExecution(@NonNull f final Instant stopTimeInstant = Instant.ofEpochMilli(benchmarkResult.getMetadata().getStopTime()); final long warmupOps = benchmarkResult.getMetadata().getWarmupOps(); final long measurementOps = benchmarkResult.getMetadata().getMeasurementOps(); - return new BenchmarkExecutionMetadata(startTimeInstant, warmupTimeInstant, measurementTimeInstant, stopTimeInstant, warmupOps, measurementOps); + return new BenchmarkExecutionMetadata(startTimeInstant, warmupTimeInstant, measurementTimeInstant, + stopTimeInstant, warmupOps, measurementOps); } } diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/jmh/JmhExecutor.java b/jmh-client/src/main/java/com/openelements/jmh/client/jmh/JmhExecutor.java new file mode 100644 index 00000000..5f1296aa --- /dev/null +++ b/jmh-client/src/main/java/com/openelements/jmh/client/jmh/JmhExecutor.java @@ -0,0 +1,36 @@ +package com.openelements.jmh.client.jmh; + +import edu.umd.cs.findbugs.annotations.NonNull; +import java.util.Collection; +import java.util.Objects; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Defaults; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +public class JmhExecutor { + + @NonNull + public static Collection execute(@NonNull final Collection benchmarkClasses) throws Exception { + Objects.requireNonNull(benchmarkClasses, "BenchmarkClasses must not be null"); + final OptionsBuilder optionsBuilder = new OptionsBuilder(); + benchmarkClasses.forEach(cls -> optionsBuilder.getIncludes().add(cls.getName())); + return execute(optionsBuilder.build()); + } + + @NonNull + public static Collection executeAll() throws Exception { + final OptionsBuilder optionsBuilder = new OptionsBuilder(); + optionsBuilder.getIncludes().add(Defaults.INCLUDE_BENCHMARKS); + return execute(optionsBuilder.build()); + } + + @NonNull + private static Collection execute(@NonNull final Options options) throws Exception { + Objects.requireNonNull(options, "Options must not be null"); + final Runner runner = new Runner(options); + return runner.run(); + } + +} diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/json/BenchmarkJsonFactory.java b/jmh-client/src/main/java/com/openelements/jmh/client/json/BenchmarkJsonFactory.java index ab07c1af..2b46a148 100644 --- a/jmh-client/src/main/java/com/openelements/jmh/client/json/BenchmarkJsonFactory.java +++ b/jmh-client/src/main/java/com/openelements/jmh/client/json/BenchmarkJsonFactory.java @@ -17,6 +17,7 @@ import com.openelements.jmh.client.json.converter.InstantConverter; import edu.umd.cs.findbugs.annotations.NonNull; import java.time.Instant; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Objects; @@ -43,7 +44,7 @@ private static Gson createGson() { } @NonNull - public static String toJson(@NonNull final Set benchmarks) { + public static String toJson(@NonNull final Collection benchmarks) { Objects.requireNonNull(benchmarks, "benchmarks must not be null"); return createGson().toJson(benchmarks); } diff --git a/jmh-client/src/main/java/com/openelements/jmh/client/json/converter/BenchmarkInfrastructureConverter.java b/jmh-client/src/main/java/com/openelements/jmh/client/json/converter/BenchmarkInfrastructureConverter.java index fd7faa2b..6aefad25 100644 --- a/jmh-client/src/main/java/com/openelements/jmh/client/json/converter/BenchmarkInfrastructureConverter.java +++ b/jmh-client/src/main/java/com/openelements/jmh/client/json/converter/BenchmarkInfrastructureConverter.java @@ -16,7 +16,8 @@ public final class BenchmarkInfrastructureConverter implements JsonSerializer { @Override - public BenchmarkInfrastructure deserialize(@NonNull final JsonElement json, @NonNull final Type typeOfT, @NonNull final JsonDeserializationContext context) + public BenchmarkInfrastructure deserialize(@NonNull final JsonElement json, @NonNull final Type typeOfT, + @NonNull final JsonDeserializationContext context) throws JsonParseException { Objects.requireNonNull(json, "json must not be null"); Objects.requireNonNull(context, "context must not be null"); @@ -27,13 +28,14 @@ public BenchmarkInfrastructure deserialize(@NonNull final JsonElement json, @Non final String osVersion = json.getAsJsonObject().get("osVersion").getAsString(); final String jvmVersion = json.getAsJsonObject().get("jvmVersion").getAsString(); final String jvmName = json.getAsJsonObject().get("jvmName").getAsString(); - final String jmhVendor = json.getAsJsonObject().get("jmhVendor").getAsString(); + final String jmhVersion = json.getAsJsonObject().get("jmhVersion").getAsString(); return new BenchmarkInfrastructure(arch, availableProcessors, memory, osName, osVersion, jvmVersion, jvmName, - jmhVendor); + jmhVersion); } @Override - public JsonElement serialize(@NonNull final BenchmarkInfrastructure src, @NonNull final Type typeOfSrc, @NonNull final JsonSerializationContext context) { + public JsonElement serialize(@NonNull final BenchmarkInfrastructure src, @NonNull final Type typeOfSrc, + @NonNull final JsonSerializationContext context) { Objects.requireNonNull(src, "src must not be null"); Objects.requireNonNull(context, "context must not be null"); final JsonObject json = new JsonObject(); @@ -44,7 +46,7 @@ public JsonElement serialize(@NonNull final BenchmarkInfrastructure src, @NonNul json.addProperty("osVersion", src.osVersion()); json.addProperty("jvmVersion", src.jvmVersion()); json.addProperty("jvmName", src.jvmName()); - json.addProperty("jmhVendor", src.jmhVersion()); + json.addProperty("jmhVersion", src.jmhVersion()); return json; } } diff --git a/jmh-client/src/main/java/module-info.java b/jmh-client/src/main/java/module-info.java index 9dff49fd..ef1304c2 100644 --- a/jmh-client/src/main/java/module-info.java +++ b/jmh-client/src/main/java/module-info.java @@ -1,13 +1,13 @@ module com.openelements.jmh.client { - requires com.openelements.jmh.common; - requires jmh.core; - requires java.net.http; - requires com.google.gson; - requires java.management; - requires jdk.management; - requires static com.github.spotbugs.annotations; + requires com.openelements.jmh.common; + requires jmh.core; + requires java.net.http; + requires com.google.gson; + requires java.management; + requires jdk.management; + requires static com.github.spotbugs.annotations; - exports com.openelements.jmh.client; - exports com.openelements.jmh.client.json; - exports com.openelements.jmh.client.factory; + exports com.openelements.jmh.client; + exports com.openelements.jmh.client.json; + exports com.openelements.jmh.client.jmh; } \ No newline at end of file diff --git a/jmh-common/src/main/java/com/openelements/jmh/common/BenchmarkConfiguration.java b/jmh-common/src/main/java/com/openelements/jmh/common/BenchmarkConfiguration.java index 777efffb..76854f6b 100644 --- a/jmh-common/src/main/java/com/openelements/jmh/common/BenchmarkConfiguration.java +++ b/jmh-common/src/main/java/com/openelements/jmh/common/BenchmarkConfiguration.java @@ -5,26 +5,28 @@ import java.util.concurrent.TimeUnit; /** - * Configuration for a benchmark. This configuration is used to configure the benchmark. It is added to a {@link BenchmarkExecution} to store the configuration of the benchmark for the given execution. - * @param threads number of threads to use for the benchmark - * @param forks number of forks to use for the benchmark - * @param timeout timeout for the benchmark - * @param timeoutUnit unit of the timeout + * Configuration for a benchmark. This configuration is used to configure the benchmark. It is added to a + * {@link BenchmarkExecution} to store the configuration of the benchmark for the given execution. + * + * @param threads number of threads to use for the benchmark + * @param forks number of forks to use for the benchmark + * @param timeout timeout for the benchmark + * @param timeoutUnit unit of the timeout * @param measurementConfiguration configuration for the measurement phase - * @param warmupConfiguration configuration for the warmup phase + * @param warmupConfiguration configuration for the warmup phase */ public record BenchmarkConfiguration(int threads, int forks, long timeout, @NonNull TimeUnit timeoutUnit, @NonNull BenchmarkMeasurementConfiguration measurementConfiguration, @NonNull BenchmarkMeasurementConfiguration warmupConfiguration) { public BenchmarkConfiguration { - if(threads < 1) { + if (threads < 1) { throw new IllegalArgumentException("threads must be greater than 0"); } - if(forks < 1) { - throw new IllegalArgumentException("forks must be greater than 0"); + if (forks < 0) { + throw new IllegalArgumentException("forks must be 0 or a positive value"); } - if(timeout < 1) { + if (timeout < 1) { throw new IllegalArgumentException("timeout must be greater than 0"); } Objects.requireNonNull(timeoutUnit, "timeoutUnit must not be null"); diff --git a/jmh-common/src/test/java/com/openelements/jmh/common/test/BenchmarkConfigurationTest.java b/jmh-common/src/test/java/com/openelements/jmh/common/test/BenchmarkConfigurationTest.java index a8134a9b..c75b226d 100644 --- a/jmh-common/src/test/java/com/openelements/jmh/common/test/BenchmarkConfigurationTest.java +++ b/jmh-common/src/test/java/com/openelements/jmh/common/test/BenchmarkConfigurationTest.java @@ -13,18 +13,28 @@ void testBadInstantiation() { final BenchmarkMeasurementConfiguration measurementConfig = DummyFactory.createBenchmarkMeasurementConfiguration(); final BenchmarkMeasurementConfiguration warmupConfig = DummyFactory.createBenchmarkMeasurementConfiguration(); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(-1, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(0, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(-100, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(1, -1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(1, 0, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(1, -100, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(1, 1, -1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(1, 1, 0, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(IllegalArgumentException.class, () -> new BenchmarkConfiguration(1, 1, -100, TimeUnit.SECONDS, measurementConfig, warmupConfig)); - Assertions.assertThrows(NullPointerException.class, () -> new BenchmarkConfiguration(1, 1, 1, null, measurementConfig, warmupConfig)); - Assertions.assertThrows(NullPointerException.class, () -> new BenchmarkConfiguration(1, 1, 1, TimeUnit.SECONDS, null, warmupConfig)); - Assertions.assertThrows(NullPointerException.class, () -> new BenchmarkConfiguration(1, 1, 1, TimeUnit.SECONDS, measurementConfig, null)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(-1, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(0, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(-100, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(1, -1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(1, -100, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(1, 1, -1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(1, 1, 0, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(IllegalArgumentException.class, + () -> new BenchmarkConfiguration(1, 1, -100, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertThrows(NullPointerException.class, + () -> new BenchmarkConfiguration(1, 1, 1, null, measurementConfig, warmupConfig)); + Assertions.assertThrows(NullPointerException.class, + () -> new BenchmarkConfiguration(1, 1, 1, TimeUnit.SECONDS, null, warmupConfig)); + Assertions.assertThrows(NullPointerException.class, + () -> new BenchmarkConfiguration(1, 1, 1, TimeUnit.SECONDS, measurementConfig, null)); } @Test @@ -32,6 +42,7 @@ void testInstantiation() { final BenchmarkMeasurementConfiguration measurementConfig = DummyFactory.createBenchmarkMeasurementConfiguration(); final BenchmarkMeasurementConfiguration warmupConfig = DummyFactory.createBenchmarkMeasurementConfiguration(); - Assertions.assertDoesNotThrow(() -> new BenchmarkConfiguration(1, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); + Assertions.assertDoesNotThrow( + () -> new BenchmarkConfiguration(1, 1, 1, TimeUnit.SECONDS, measurementConfig, warmupConfig)); } } diff --git a/jmh-store/src/main/java/com/openelements/jmh/store/db/entities/TimeseriesEntity.java b/jmh-store/src/main/java/com/openelements/jmh/store/db/entities/TimeseriesEntity.java index ef93b6b3..f364b79f 100644 --- a/jmh-store/src/main/java/com/openelements/jmh/store/db/entities/TimeseriesEntity.java +++ b/jmh-store/src/main/java/com/openelements/jmh/store/db/entities/TimeseriesEntity.java @@ -12,114 +12,114 @@ @Table(indexes = @Index(columnList = "benchmarkId")) public class TimeseriesEntity { - @Id - @GeneratedValue - private Long id; + @Id + @GeneratedValue + private Long id; - @Column(nullable = false) - private Long benchmarkId; + @Column(nullable = false) + private Long benchmarkId; - @Column(nullable = false) - private Instant timestamp; + @Column(nullable = false) + private Instant timestamp; - @Column(nullable = false) - private double measurement; + @Column(nullable = false) + private double measurement; - @Column(nullable = false) - private double error; + @Column(nullable = true) + private Double error; - @Column(nullable = false) - private double min; + @Column(nullable = true) + private Double min; - @Column(nullable = false) - private double max; + @Column(nullable = true) + private Double max; - @Column(nullable = true) - private Integer availableProcessors; + @Column(nullable = true) + private Integer availableProcessors; - @Column(nullable = true) - private Long memory; + @Column(nullable = true) + private Long memory; - @Column(nullable = true) - private String jvmVersion; + @Column(nullable = true) + private String jvmVersion; - public void setId(final Long id) { - this.id = id; - } + public void setId(final Long id) { + this.id = id; + } - public Long getId() { - return id; - } + public Long getId() { + return id; + } - public Long getBenchmarkId() { - return benchmarkId; - } + public Long getBenchmarkId() { + return benchmarkId; + } - public void setBenchmarkId(final Long benchmarkId) { - this.benchmarkId = benchmarkId; - } + public void setBenchmarkId(final Long benchmarkId) { + this.benchmarkId = benchmarkId; + } - public Instant getTimestamp() { - return timestamp; - } + public Instant getTimestamp() { + return timestamp; + } - public void setTimestamp(final Instant timestamp) { - this.timestamp = timestamp; - } + public void setTimestamp(final Instant timestamp) { + this.timestamp = timestamp; + } - public double getMeasurement() { - return measurement; - } + public double getMeasurement() { + return measurement; + } - public void setMeasurement(final double value) { - this.measurement = value; - } + public void setMeasurement(final double value) { + this.measurement = value; + } - public double getError() { - return error; - } + public Double getError() { + return error; + } - public void setError(final double error) { - this.error = error; - } + public void setError(final Double error) { + this.error = error; + } - public double getMin() { - return min; - } + public Double getMin() { + return min; + } - public void setMin(final double min) { - this.min = min; - } + public void setMin(final Double min) { + this.min = min; + } - public double getMax() { - return max; - } + public Double getMax() { + return max; + } - public void setMax(final double max) { - this.max = max; - } + public void setMax(final Double max) { + this.max = max; + } - public Integer getAvailableProcessors() { - return availableProcessors; - } + public Integer getAvailableProcessors() { + return availableProcessors; + } - public void setAvailableProcessors(final Integer availableProcessors) { - this.availableProcessors = availableProcessors; - } + public void setAvailableProcessors(final Integer availableProcessors) { + this.availableProcessors = availableProcessors; + } - public Long getMemory() { - return memory; - } + public Long getMemory() { + return memory; + } - public void setMemory(final Long memory) { - this.memory = memory; - } + public void setMemory(final Long memory) { + this.memory = memory; + } - public String getJvmVersion() { - return jvmVersion; - } + public String getJvmVersion() { + return jvmVersion; + } - public void setJvmVersion(final String jvmVersion) { - this.jvmVersion = jvmVersion; - } + public void setJvmVersion(final String jvmVersion) { + this.jvmVersion = jvmVersion; + } } diff --git a/jmh-store/src/main/java/com/openelements/jmh/store/shared/Timeseries.java b/jmh-store/src/main/java/com/openelements/jmh/store/shared/Timeseries.java index d0962020..88ff9e48 100644 --- a/jmh-store/src/main/java/com/openelements/jmh/store/shared/Timeseries.java +++ b/jmh-store/src/main/java/com/openelements/jmh/store/shared/Timeseries.java @@ -2,8 +2,8 @@ import java.time.Instant; -public record Timeseries(Long id, Instant timestamp, double value, double error, - double min, double max, Integer availableProcessors, +public record Timeseries(Long id, Instant timestamp, double value, Double error, + Double min, Double max, Integer availableProcessors, Long memory, String jvmVersion) { } diff --git a/sample/pom.xml b/sample/pom.xml index f0879425..3ed0b62a 100644 --- a/sample/pom.xml +++ b/sample/pom.xml @@ -14,13 +14,12 @@ ${project.groupId} - jmh-runner + jmh-client ${project.version} org.openjdk.jmh jmh-generator-annprocess - 1.34 provided diff --git a/sample/src/main/java/com/openelements/benchmark/SampleBenchmark.java b/sample/src/main/java/com/openelements/benchmark/SampleBenchmark.java index 7b3399bd..ac8bc392 100644 --- a/sample/src/main/java/com/openelements/benchmark/SampleBenchmark.java +++ b/sample/src/main/java/com/openelements/benchmark/SampleBenchmark.java @@ -1,6 +1,9 @@ package com.openelements.benchmark; -import com.openelements.jmh.runner.JmhUploader; +import com.openelements.jmh.client.io.FileClient; +import com.openelements.jmh.client.io.RestClient; +import com.openelements.jmh.client.jmh.BenchmarkFactory; +import com.openelements.jmh.client.jmh.JmhExecutor; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -21,26 +24,32 @@ @State(Scope.Benchmark) public class SampleBenchmark { - @Benchmark - @Fork(0) - @Warmup(iterations = 2, time = 2) - @Threads(2) - @Measurement(iterations = 4, time = 3) - @OutputTimeUnit(TimeUnit.MILLISECONDS) - @BenchmarkMode(Mode.Throughput) - public void doIt(Blackhole blackhole) throws NoSuchAlgorithmException { - String value = UUID.randomUUID().toString(); - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] encodedhash = digest.digest(value.getBytes(StandardCharsets.UTF_8)); - blackhole.consume(encodedhash); - } + @Benchmark + @Fork(0) + @Warmup(iterations = 1, time = 1) + @Threads(2) + @Measurement(iterations = 2, time = 2) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @BenchmarkMode(Mode.Throughput) + public void doIt(Blackhole blackhole) throws NoSuchAlgorithmException { + String value = UUID.randomUUID().toString(); + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] encodedhash = digest.digest(value.getBytes(StandardCharsets.UTF_8)); + blackhole.consume(encodedhash); + } - public static void main(final String[] args) throws Exception { - while (true) { - JmhUploader jmh = new JmhUploader(); - jmh.addBenchmarkClass(SampleBenchmark.class); - jmh.addBenchmarkClass(SampleBenchmark2.class); - jmh.run(); + public static void main(final String[] args) throws Exception { + final FileClient fileClient = new FileClient("target/benchmark/"); + final RestClient restClient = new RestClient(); + JmhExecutor.executeAll().stream() + .map(BenchmarkFactory::convert) + .forEach(benchmarkExecution -> { + try { + fileClient.write(benchmarkExecution); + restClient.post(benchmarkExecution); + } catch (final Exception e) { + throw new RuntimeException("Error in posting result", e); + } + }); } - } } diff --git a/sample/src/main/java/com/openelements/benchmark/SampleBenchmark2.java b/sample/src/main/java/com/openelements/benchmark/SampleBenchmark2.java index a0dd659a..2bda046f 100644 --- a/sample/src/main/java/com/openelements/benchmark/SampleBenchmark2.java +++ b/sample/src/main/java/com/openelements/benchmark/SampleBenchmark2.java @@ -16,15 +16,15 @@ @State(Scope.Benchmark) public class SampleBenchmark2 { - @Benchmark - @Fork(0) - @Warmup(iterations = 2, time = 2) - @Threads(2) - @Measurement(iterations = 4, time = 3) - @OutputTimeUnit(TimeUnit.MILLISECONDS) - @BenchmarkMode(Mode.Throughput) - public void doIt() throws Exception { - Thread.sleep(new Random(System.currentTimeMillis()).nextLong(1, 10)); - } + @Benchmark + @Fork(0) + @Warmup(iterations = 1, time = 1) + @Threads(2) + @Measurement(iterations = 2, time = 2) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @BenchmarkMode(Mode.Throughput) + public void doIt() throws Exception { + Thread.sleep(new Random(System.currentTimeMillis()).nextLong(1, 10)); + } }