blob: 8703fb99d18743e2a8e2349187037e46ab8648e1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.quarkus.performance.regression;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RegExUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
@picocli.CommandLine.Command(description = "Run a performance test against a list of Camel Quarkus versions and print a report")
public class PerfRegressionCommand implements Runnable {
private static Path PERF_SAMPLE_TEMPLATE_FOLDER = Paths.get("cq-perf-regression-sample-base");
@Parameters(paramLabel = "<versions>", arity = "1..*", description = "A list of versions, e.g: 2.7.0 2.8.0-SNAPSHOT")
private String[] cqVersions = {};
@Option(names = { "-cqs",
"--camel-quarkus-staging-repository" }, description = "Camel Quarkus staging repository, e.g: https://repository.apache.org/content/repositories/orgapachecamel-1423")
private String cqStagingRepository;
@Option(names = { "-cs",
"--camel-staging-repository" }, description = "Camel staging repository, e.g: https://repository.apache.org/content/repositories/orgapachecamel-1424")
private String camelStagingRepository;
@Option(names = { "-d",
"--duration" }, defaultValue = "10m", description = "The duration of a single performance test scenario (e.g. 45s, 30m, 1h). Up to 2 scenarios per version could be run.")
private String singleScenarioDuration;
@Option(names = { "-an",
"--also-run-native-mode" }, description = "Tells whether the throughput test should also be run in native mode. By default, run in JVM mode only.")
private boolean alsoRunNativeMode;
@Override
public void run() {
PerformanceRegressionReport report = new PerformanceRegressionReport(singleScenarioDuration);
Path cqVersionsUnderTestFolder = Paths.get("target/cq-versions-under-test");
try {
Files.createDirectories(cqVersionsUnderTestFolder);
FileUtils.cleanDirectory(cqVersionsUnderTestFolder.toFile());
for (String cqVersion : cqVersions) {
runPerfRegressionForCqVersion(cqVersionsUnderTestFolder.resolve(cqVersion), cqVersion, report);
}
System.out.println(report.printAll());
} catch (IOException | XmlPullParserException e) {
throw new RuntimeException("An issue has been caught while trying to setup performance regression tests.", e);
}
}
private void runPerfRegressionForCqVersion(Path cqVersionUnderTestFolder, String cqVersion,
PerformanceRegressionReport report) throws IOException, XmlPullParserException {
// Copy the template project into a folder dedicated to cqVersion tests
FileUtils.copyDirectory(PERF_SAMPLE_TEMPLATE_FOLDER.toFile(), cqVersionUnderTestFolder.toFile());
FileEditionHelper.instantiateHyperfoilBenchmark(cqVersionUnderTestFolder, singleScenarioDuration);
FileEditionHelper.instantiatePomFile(cqVersionUnderTestFolder, cqVersion, cqStagingRepository, camelStagingRepository);
// Locally sets the right maven version in the maven wrapper
// camel-quarkus >= 2.6.0.CR1 => maven 3.8.4
// camel-quarkus >= 2.1.0 => maven 3.8.1
String targetMavenVersion = getTargetMavenVersion(cqVersionUnderTestFolder);
setMvnwMavenVersion(cqVersionUnderTestFolder, targetMavenVersion);
// Run performance regression test in JVM mode
double jvmThroughput = runPerfRegression(cqVersionUnderTestFolder, "integration-test");
report.setCategoryMeasureForVersion(cqVersion, "JVM", jvmThroughput);
// Run performance regression test in native mode
if (alsoRunNativeMode) {
double nativeThroughput = runPerfRegression(cqVersionUnderTestFolder,
"integration-test -Dnative -Dquarkus.native.container-build=true");
report.setCategoryMeasureForVersion(cqVersion, "Native", nativeThroughput);
}
}
private static String getTargetMavenVersion(Path cqVersionUnderTestFolder) {
String stdoutAndStdErr = MvnwCmdHelper.execute(cqVersionUnderTestFolder,
"help:evaluate -Dexpression='target-maven-version' -q -DforceStdout");
String targetMavenVersion = stdoutAndStdErr
.substring(stdoutAndStdErr.lastIndexOf(System.lineSeparator()) + System.lineSeparator().length());
return "null object or invalid expression".equals(targetMavenVersion) ? "3.8.1" : targetMavenVersion;
}
private static void setMvnwMavenVersion(Path cqVersionUnderTestFolder, String targetMavenVersion) {
MvnwCmdHelper.execute(cqVersionUnderTestFolder, "wrapper:wrapper -Dmaven=" + targetMavenVersion);
}
private static double runPerfRegression(Path cqVersionUnderTestFolder, String args) {
String stdout = MvnwCmdHelper.execute(cqVersionUnderTestFolder, args);
// Extract the throughput from a log line like "15:26:23,110 INFO (main) [i.h.m.RunMojo] Requests/sec: 1153.56"
String throughput = RegExUtils.replacePattern(stdout, ".*RunMojo] Requests/sec: ([0-9.,]+).*", "$1");
return Double.parseDouble(throughput);
}
}