Skip to content

Commit 6a5a83d

Browse files
authored
Add option to output all results to disk (#4344)
1 parent 258f7ca commit 6a5a83d

File tree

4 files changed

+150
-19
lines changed

4 files changed

+150
-19
lines changed

test/sdk-benchmarks/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@
205205
<version>${awsjavasdk.version}</version>
206206
<scope>compile</scope>
207207
</dependency>
208+
<dependency>
209+
<groupId>commons-cli</groupId>
210+
<artifactId>commons-cli</artifactId>
211+
<scope>compile</scope>
212+
</dependency>
208213
</dependencies>
209214

210215
<dependencyManagement>
@@ -368,6 +373,8 @@
368373
<argument>-classpath</argument>
369374
<classpath/>
370375
<argument>software.amazon.awssdk.benchmark.BenchmarkRunner</argument>
376+
<!-- Fail process on failed benchmarks -->
377+
<argument>-c</argument>
371378
</arguments>
372379
</configuration>
373380
</plugin>

test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkResultProcessor.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.net.URL;
2525
import java.util.ArrayList;
2626
import java.util.Collection;
27+
import java.util.HashMap;
2728
import java.util.List;
2829
import java.util.Map;
2930
import java.util.Objects;
@@ -34,6 +35,7 @@
3435
import software.amazon.awssdk.benchmark.stats.SdkBenchmarkParams;
3536
import software.amazon.awssdk.benchmark.stats.SdkBenchmarkResult;
3637
import software.amazon.awssdk.benchmark.stats.SdkBenchmarkStatistics;
38+
import software.amazon.awssdk.benchmark.utils.BenchmarkProcessorOutput;
3739
import software.amazon.awssdk.utils.Logger;
3840

3941

@@ -66,15 +68,18 @@ class BenchmarkResultProcessor {
6668
* Process benchmark results
6769
*
6870
* @param results the results of the benchmark
69-
* @return the benchmark Id that failed the regression
71+
* @return the benchmark results
7072
*/
71-
List<String> processBenchmarkResult(Collection<RunResult> results) {
72-
List<SdkBenchmarkResult> currentData = new ArrayList<>();
73+
BenchmarkProcessorOutput processBenchmarkResult(Collection<RunResult> results) {
74+
Map<String, SdkBenchmarkResult> benchmarkResults = new HashMap<>();
75+
7376
for (RunResult result : results) {
7477
String benchmarkId = getBenchmarkId(result.getParams());
78+
SdkBenchmarkResult sdkBenchmarkData = constructSdkBenchmarkResult(result);
79+
80+
benchmarkResults.put(benchmarkId, sdkBenchmarkData);
7581

7682
SdkBenchmarkResult baselineResult = baseline.get(benchmarkId);
77-
SdkBenchmarkResult sdkBenchmarkData = constructSdkBenchmarkResult(result);
7883

7984
if (baselineResult == null) {
8085
log.warn(() -> {
@@ -90,15 +95,14 @@ List<String> processBenchmarkResult(Collection<RunResult> results) {
9095
continue;
9196
}
9297

93-
currentData.add(sdkBenchmarkData);
94-
9598
if (!validateBenchmarkResult(sdkBenchmarkData, baselineResult)) {
9699
failedBenchmarkIds.add(benchmarkId);
97100
}
98101
}
99102

100-
log.info(() -> "Current result: " + serializeResult(currentData));
101-
return failedBenchmarkIds;
103+
BenchmarkProcessorOutput output = new BenchmarkProcessorOutput(benchmarkResults, failedBenchmarkIds);
104+
log.info(() -> "Current result: " + serializeResult(output));
105+
return output;
102106
}
103107

104108
private SdkBenchmarkResult constructSdkBenchmarkResult(RunResult runResult) {
@@ -169,9 +173,9 @@ private boolean validateBenchmarkParams(SdkBenchmarkParams current, SdkBenchmark
169173
return current.getMode() == baseline.getMode();
170174
}
171175

172-
private String serializeResult(List<SdkBenchmarkResult> currentData) {
176+
private String serializeResult(BenchmarkProcessorOutput processorOutput) {
173177
try {
174-
return OBJECT_MAPPER.writeValueAsString(currentData);
178+
return OBJECT_MAPPER.writeValueAsString(processorOutput);
175179
} catch (JsonProcessingException e) {
176180
log.error(() -> "Failed to serialize current result", e);
177181
}

test/sdk-benchmarks/src/main/java/software/amazon/awssdk/benchmark/BenchmarkRunner.java

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,23 @@
1515

1616
package software.amazon.awssdk.benchmark;
1717

18-
import com.fasterxml.jackson.core.JsonProcessingException;
18+
import static software.amazon.awssdk.benchmark.utils.BenchmarkConstant.OBJECT_MAPPER;
19+
20+
import java.io.IOException;
21+
import java.io.OutputStream;
22+
import java.nio.file.Files;
23+
import java.nio.file.Path;
24+
import java.nio.file.Paths;
1925
import java.util.ArrayList;
2026
import java.util.Arrays;
2127
import java.util.Collection;
2228
import java.util.List;
29+
import java.util.stream.Collectors;
30+
import org.apache.commons.cli.CommandLine;
31+
import org.apache.commons.cli.CommandLineParser;
32+
import org.apache.commons.cli.DefaultParser;
33+
import org.apache.commons.cli.Options;
34+
import org.apache.commons.cli.ParseException;
2335
import org.openjdk.jmh.results.RunResult;
2436
import org.openjdk.jmh.runner.Runner;
2537
import org.openjdk.jmh.runner.RunnerException;
@@ -45,6 +57,8 @@
4557
import software.amazon.awssdk.benchmark.enhanced.dynamodb.EnhancedClientQueryV1MapperComparisonBenchmark;
4658
import software.amazon.awssdk.benchmark.enhanced.dynamodb.EnhancedClientScanV1MapperComparisonBenchmark;
4759
import software.amazon.awssdk.benchmark.enhanced.dynamodb.EnhancedClientUpdateV1MapperComparisonBenchmark;
60+
import software.amazon.awssdk.benchmark.stats.SdkBenchmarkResult;
61+
import software.amazon.awssdk.benchmark.utils.BenchmarkProcessorOutput;
4862
import software.amazon.awssdk.utils.Logger;
4963

5064

@@ -84,13 +98,15 @@ public class BenchmarkRunner {
8498

8599
private final List<String> benchmarksToRun;
86100
private final BenchmarkResultProcessor resultProcessor;
101+
private final BenchmarkRunnerOptions options;
87102

88-
private BenchmarkRunner(List<String> benchmarksToRun) {
103+
private BenchmarkRunner(List<String> benchmarksToRun, BenchmarkRunnerOptions options) {
89104
this.benchmarksToRun = benchmarksToRun;
90105
this.resultProcessor = new BenchmarkResultProcessor();
106+
this.options = options;
91107
}
92108

93-
public static void main(String... args) throws RunnerException, JsonProcessingException {
109+
public static void main(String... args) throws Exception {
94110
List<String> benchmarksToRun = new ArrayList<>();
95111
benchmarksToRun.addAll(SYNC_BENCHMARKS);
96112
benchmarksToRun.addAll(ASYNC_BENCHMARKS);
@@ -99,13 +115,14 @@ public static void main(String... args) throws RunnerException, JsonProcessingEx
99115

100116
log.info(() -> "Skipping tests, to reduce benchmark times: \n" + MAPPER_BENCHMARKS + "\n" + METRIC_BENCHMARKS);
101117

102-
103-
BenchmarkRunner runner = new BenchmarkRunner(benchmarksToRun);
118+
BenchmarkRunner runner = new BenchmarkRunner(benchmarksToRun, parseOptions(args));
104119

105120
runner.runBenchmark();
106121
}
107122

108123
private void runBenchmark() throws RunnerException {
124+
log.info(() -> "Running with options: " + options);
125+
109126
ChainedOptionsBuilder optionsBuilder = new OptionsBuilder();
110127

111128
benchmarksToRun.forEach(optionsBuilder::include);
@@ -114,11 +131,70 @@ private void runBenchmark() throws RunnerException {
114131

115132
Collection<RunResult> results = new Runner(optionsBuilder.build()).run();
116133

117-
List<String> failedResult = resultProcessor.processBenchmarkResult(results);
134+
BenchmarkProcessorOutput processedResults = resultProcessor.processBenchmarkResult(results);
135+
List<String> failedResults = processedResults.getFailedBenchmarks();
136+
137+
if (options.outputPath != null) {
138+
log.info(() -> "Writing results to " + options.outputPath);
139+
writeResults(processedResults, options.outputPath);
140+
}
141+
142+
if (options.check && !failedResults.isEmpty()) {
143+
log.info(() -> "Failed perf regression tests: " + failedResults);
144+
throw new RuntimeException("Perf regression tests failed: " + failedResults);
145+
}
146+
}
147+
148+
private static BenchmarkRunnerOptions parseOptions(String[] args) throws ParseException {
149+
Options cliOptions = new Options();
150+
cliOptions.addOption("o", "output", true,
151+
"The path to write the benchmark results to.");
152+
cliOptions.addOption("c", "check", false,
153+
"If specified, exit with error code 1 if the results are not within the baseline.");
154+
155+
CommandLineParser parser = new DefaultParser();
156+
CommandLine cmdLine = parser.parse(cliOptions, args);
157+
158+
BenchmarkRunnerOptions options = new BenchmarkRunnerOptions()
159+
.check(cmdLine.hasOption("c"));
160+
161+
if (cmdLine.hasOption("o")) {
162+
options.outputPath(Paths.get(cmdLine.getOptionValue("o")));
163+
}
164+
165+
return options;
166+
}
167+
168+
private static void writeResults(BenchmarkProcessorOutput output, Path outputPath) {
169+
List<SdkBenchmarkResult> results = output.getBenchmarkResults().values().stream().collect(Collectors.toList());
170+
try (OutputStream os = Files.newOutputStream(outputPath)) {
171+
OBJECT_MAPPER.writeValue(os, results);
172+
} catch (IOException e) {
173+
log.error(() -> "Failed to write the results to " + outputPath, e);
174+
throw new RuntimeException(e);
175+
}
176+
}
177+
178+
private static class BenchmarkRunnerOptions {
179+
private Path outputPath;
180+
private boolean check;
181+
182+
public BenchmarkRunnerOptions outputPath(Path outputPath) {
183+
this.outputPath = outputPath;
184+
return this;
185+
}
186+
187+
public BenchmarkRunnerOptions check(boolean check) {
188+
this.check = check;
189+
return this;
190+
}
118191

119-
if (!failedResult.isEmpty()) {
120-
log.info(() -> "Failed perf regression tests: " + failedResult);
121-
throw new RuntimeException("Perf regression tests failed: " + failedResult);
192+
@Override
193+
public String toString() {
194+
return "BenchmarkRunnerOptions{" +
195+
"outputPath=" + outputPath +
196+
", check=" + check +
197+
'}';
122198
}
123199
}
124200
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.benchmark.utils;
17+
18+
import com.fasterxml.jackson.annotation.JsonCreator;
19+
import java.util.List;
20+
import java.util.Map;
21+
import software.amazon.awssdk.benchmark.stats.SdkBenchmarkResult;
22+
23+
/**
24+
* The output object of the benchmark processor. This contains the results of the all the benchmarks that were run, and the
25+
* list of benchmarks that failed.
26+
*/
27+
public final class BenchmarkProcessorOutput {
28+
private final Map<String, SdkBenchmarkResult> benchmarkResults;
29+
private final List<String> failedBenchmarks;
30+
31+
@JsonCreator
32+
public BenchmarkProcessorOutput(Map<String, SdkBenchmarkResult> benchmarkResults, List<String> failedBenchmarks) {
33+
this.benchmarkResults = benchmarkResults;
34+
this.failedBenchmarks = failedBenchmarks;
35+
}
36+
37+
public Map<String, SdkBenchmarkResult> getBenchmarkResults() {
38+
return benchmarkResults;
39+
}
40+
41+
public List<String> getFailedBenchmarks() {
42+
return failedBenchmarks;
43+
}
44+
}

0 commit comments

Comments
 (0)