diff --git a/Jenkinsfile b/Jenkinsfile index c988db31fa1a96858952d4a4166aa91c3e610998..353d723548073c3f55cb9dd4a95833af2333a399 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -63,16 +63,19 @@ pipeline { sshagent(credentials: ['kieker-irl-key']) { unstash 'yaml' sh ''' - echo "put kieker-python-results.yaml" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} - echo "put kieker-java-results.yaml" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} - echo "put open-telementry-results.yaml" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} - echo "put insepct-it-results.yaml" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} -# sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/all-results.json -# compile-results/bin/compile-results results-Kieker/results-text.csv all-results.json -# echo "put all-results.json" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} -# echo "put partial-results.json" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} -# echo "put relative-results.json" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} - ''' + mkdir all + cd all + sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/kieker-java.yaml + sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/kieker-python.yaml +# sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/opentelemetry.yaml +# sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL}/inspectit.yaml + cd .. + compile-results/bin/compile-results -i *-results.yaml -l all -t all -j all -w 100 + cd all + echo "put *.yaml" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} + echo "put *.html" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} + echo "put *.json" | sftp -oNoHostAuthenticationForLocalhost=yes -oStrictHostKeyChecking=no -oUser=repo -F /dev/null -i ${KEYSTORE} ${UPDATE_SITE_URL} + ''' } } post { diff --git a/frameworks/Kieker/java/benchmark.sh b/frameworks/Kieker/java/benchmark.sh index f415b3b455a57680a2c914dc6221ddf8a2614ffe..3ceefc51b6839d5bfe619aa0c7c14766d59ad016 100755 --- a/frameworks/Kieker/java/benchmark.sh +++ b/frameworks/Kieker/java/benchmark.sh @@ -55,6 +55,12 @@ info "----------------------------------" info "Setup..." info "----------------------------------" +# This is necessary, as the framework name is originally +# derived from the directory the script is sitting in, but +# Kieker supports multiple languages and has multiple +# sub directories for each programming language. +export FRAMEWORK_NAME="kieker-${FRAMEWORK_NAME}" + cd "${BASE_DIR}" # load agent diff --git a/frameworks/Kieker/python/benchmark.sh b/frameworks/Kieker/python/benchmark.sh index cdb96b4213e37782f09dca9d5c8273cb0539405f..30cc37b8e221dd0def1a9959052e80aec4944a73 100755 --- a/frameworks/Kieker/python/benchmark.sh +++ b/frameworks/Kieker/python/benchmark.sh @@ -55,6 +55,12 @@ info "----------------------------------" info "Setup..." info "----------------------------------" +# This is necessary, as the framework name is originally +# derived from the directory the script is sitting in, but +# Kieker supports multiple languages and has multiple +# sub directories for each programming language. +export FRAMEWORK_NAME="kieker-${FRAMEWORK_NAME}" + cd "${BASE_DIR}" # load agent diff --git a/frameworks/statistics.r b/frameworks/statistics.r index 34434e0457f7da615703e52742864513a0b5d9eb..3906626122abec4817700bbe87e292822b98480f 100644 --- a/frameworks/statistics.r +++ b/frameworks/statistics.r @@ -90,19 +90,27 @@ print(resultstext) currentTime <- as.numeric(Sys.time()) +mktext <- function(value) { + if (is.na(value)) { + return(".NAN") + } else { + return(format(value, scientific=TRUE)) + } +} + write(paste("kind:", configs.framework_name), file=out_yaml_fn,append=FALSE) write("experiments:", file=out_yaml_fn, append=TRUE) write(paste("- timestamp:", currentTime), file=out_yaml_fn, append=TRUE) write(" measurements:", file=out_yaml_fn, append=TRUE) for (writer_idx in (1:(numberOfWriters))) { write(paste(" ", configs.labels[writer_idx], ": [", - format(printvalues["mean",writer_idx], scientific=TRUE), ",", - format(printvalues["sd",writer_idx], scientific=TRUE), ",", - format(printvalues["ci95%",writer_idx], scientific=TRUE), ",", - format(printvalues["md25%",writer_idx], scientific=TRUE), ",", - format(printvalues["md50%",writer_idx], scientific=TRUE), ",", - format(printvalues["md75%",writer_idx], scientific=TRUE), ",", - format(printvalues["max",writer_idx], scientific=TRUE), ",", - format(printvalues["min",writer_idx], scientific=TRUE), "]"), file=out_yaml_fn, append=TRUE) + mktext(printvalues["mean",writer_idx]), ",", + mktext(printvalues["sd",writer_idx]), ",", + mktext(printvalues["ci95%",writer_idx]), ",", + mktext(printvalues["md25%",writer_idx]), ",", + mktext(printvalues["md50%",writer_idx]), ",", + mktext(printvalues["md75%",writer_idx]), ",", + mktext(printvalues["max",writer_idx]), ",", + mktext(printvalues["min",writer_idx]), "]"), file=out_yaml_fn, append=TRUE) } # end diff --git a/tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java b/tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java new file mode 100644 index 0000000000000000000000000000000000000000..66a525b46faca72122c887e71ac21ea7a237ce61 --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/ChartAssemblerStage.java @@ -0,0 +1,57 @@ +/** + * + */ +package moobench.tools.results; + +import java.util.List; +import java.util.Map; + +import moobench.tools.results.data.Chart; +import moobench.tools.results.data.Experiment; +import moobench.tools.results.data.ExperimentLog; +import moobench.tools.results.data.Measurements; +import moobench.tools.results.data.ValueTuple; +import teetime.stage.basic.AbstractTransformation; + +/** + * @author Reiner Jung + * @since 1.3.0 + * + */ +public class ChartAssemblerStage extends AbstractTransformation<ExperimentLog, Chart> { + + @Override + protected void execute(ExperimentLog element) throws Exception { + Chart chart = new Chart(element.getKind()); + for (Experiment experiment : element.getExperiments()) { + long timestamp = Double.valueOf(experiment.getTimestamp()).longValue(); + ValueTuple tuple = new ValueTuple(timestamp); + + addHeaderIfMissing(chart.getHeaders(), experiment.getMeasurements()); + fillInData(chart.getHeaders(), tuple.getValues(), experiment.getMeasurements()); + + chart.getValues().add(tuple); + } + + this.outputPort.send(chart); + } + + private void fillInData(List<String> headers, List<Double> values, Map<String, Measurements> measurements) { + for (String key : headers) { + Measurements value = measurements.get(key); + if (value != null) { + values.add(value.getMean()); + } else + values.add(Double.NaN); + } + } + + private void addHeaderIfMissing(List<String> headers, Map<String, Measurements> measurements) { + for (String key : measurements.keySet()) { + if (!headers.stream().anyMatch(header -> header.equals(key))) { + headers.add(key); + } + } + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java b/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java index 8035cf4580510889fb33d0ba0c8a23912075d43b..9dd450d1a594012ba0e5bbdbf81bc3c224f0655f 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/CompileResultsMain.java @@ -4,8 +4,6 @@ package moobench.tools.results; import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; import com.beust.jcommander.JCommander; diff --git a/tools/compile-results/src/main/java/moobench/tools/results/ComputeTableStage.java b/tools/compile-results/src/main/java/moobench/tools/results/ComputeTableStage.java new file mode 100644 index 0000000000000000000000000000000000000000..dd341abdc9eeaed100de5ddf7db9ea981d00c923 --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/ComputeTableStage.java @@ -0,0 +1,63 @@ +/** + * + */ +package moobench.tools.results; + +import java.util.List; +import java.util.Map.Entry; + +import moobench.tools.results.data.Experiment; +import moobench.tools.results.data.ExperimentLog; +import moobench.tools.results.data.Measurements; +import moobench.tools.results.data.TableInformation; +import teetime.stage.basic.AbstractTransformation; + +/** + * @author reiner + * + */ +public class ComputeTableStage extends AbstractTransformation<ExperimentLog, TableInformation> { + + @Override + protected void execute(final ExperimentLog log) throws Exception { + final List<Experiment> experiments = log.getExperiments(); + if (experiments.size() > 0) { + final Experiment current = experiments.get(experiments.size()-1); + int first = experiments.size() - 10; + int last = experiments.size() - 2; + if (first < 0) { + first = 0; + } + if (last < 0) { + last = 0; + } + final Experiment previous = new Experiment(); + for (int i = first; i < last; i++) { + final Experiment experiment = experiments.get(i); + for (final Entry<String, Measurements> entry : experiment.getMeasurements().entrySet()) { + final Measurements measurements = entry.getValue(); + if (!previous.getMeasurements().containsKey(entry.getKey())) { + previous.getMeasurements().put(entry.getKey(), measurements); + } else { + final Measurements previousMeasurements = previous.getMeasurements().get(entry.getKey()); + previous.getMeasurements().put(entry.getKey(), this.computePrevious(previousMeasurements, measurements)); + } + } + } + + this.outputPort.send(new TableInformation(log.getKind(), current, previous)); + } + } + + private Measurements computePrevious(final Measurements previousMeasurements, final Measurements measurements) { + return new Measurements((measurements.getMean() + previousMeasurements.getMean())/2, + (measurements.getStandardDeviation() + previousMeasurements.getStandardDeviation())/2, + (measurements.getConvidence() + previousMeasurements.getConvidence())/2, + (measurements.getLowerQuartile() + previousMeasurements.getLowerQuartile())/2, + (measurements.getMedian() + previousMeasurements.getMedian())/2, + (measurements.getUpperQuartile() + previousMeasurements.getUpperQuartile())/2, + (measurements.getMin() + previousMeasurements.getMin())/2, + (measurements.getMax() + previousMeasurements.getMax())/2); + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java b/tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java index 3695517d76fb50007e1e548a037bac8eab48d7fb..e27cafb71d0e05e4313ec50874dd2e94aec99c01 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/ElementProducer.java @@ -25,8 +25,10 @@ public class ElementProducer<O> extends AbstractProducerStage<O> { @Override protected void execute() throws Exception { for (O element : elements) { + this.logger.debug(String.format("Reading log %s", element)); this.outputPort.send(element); } + this.workCompleted(); } } diff --git a/tools/compile-results/src/main/java/moobench/tools/results/FileSink.java b/tools/compile-results/src/main/java/moobench/tools/results/FileSink.java new file mode 100644 index 0000000000000000000000000000000000000000..df1b3e00e9398f502396756d1464a2f769e0d94b --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/FileSink.java @@ -0,0 +1,22 @@ +package moobench.tools.results; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; + +import moobench.tools.results.data.OutputFile; +import teetime.framework.AbstractConsumerStage; + +public class FileSink extends AbstractConsumerStage<OutputFile> { + + @Override + protected void execute(final OutputFile outputFile) throws Exception { + try (final BufferedWriter writer = Files.newBufferedWriter(outputFile.getFilePath())) { + writer.write(outputFile.getContent()); + writer.close(); + } catch(final IOException e) { + this.logger.error("Cannot write file {}", outputFile.getFilePath().toString()); + } + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/GenerateHtmlTableStage.java b/tools/compile-results/src/main/java/moobench/tools/results/GenerateHtmlTableStage.java new file mode 100644 index 0000000000000000000000000000000000000000..4780590a2bc3dbf3ec1044e6eb716c5985f241ff --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/GenerateHtmlTableStage.java @@ -0,0 +1,75 @@ +package moobench.tools.results; + +import java.nio.file.Path; +import java.util.Set; + +import moobench.tools.results.data.Measurements; +import moobench.tools.results.data.OutputFile; +import moobench.tools.results.data.TableInformation; +import teetime.stage.basic.AbstractTransformation; + +public class GenerateHtmlTableStage extends AbstractTransformation<TableInformation, OutputFile> { + + private final Path tablePath; + + public GenerateHtmlTableStage(final Path tablePath) { + this.tablePath = tablePath; + } + + @Override + protected void execute(final TableInformation element) throws Exception { + String content = "<table>\n" + " <tr>\n" + " <th>setup</th>\n" + " <th>run</th>\n" + + " <th>mean</th>\n" + " <th>ci</th>\n" + " <th>sd</th>\n" + " <th>1.quartile</th>\n" + + " <th>median</th>\n" + " <th>3.quartile</th>\n" + " <th>min</th>\n" + " <th>max</th>\n" + + " </tr>\n"; + final Set<String> currentKeySet = element.getCurrent().getMeasurements().keySet(); + final Set<String> previousKeySet = element.getPrevious().getMeasurements().keySet(); + final Set<String> completeKeySet = new OrderedSet<>(); + if (currentKeySet != null) { + completeKeySet.addAll(currentKeySet); + } + if (previousKeySet != null) { + completeKeySet.addAll(previousKeySet); + } + + for (final String key : completeKeySet) { + content += this.addMode(key, element.getCurrent().getMeasurements().get(key), + element.getPrevious().getMeasurements().get(key)); + } + content += "</table>\n"; + this.outputPort.send(new OutputFile(this.tablePath.resolve(element.getName() + ".html"), content)); + } + + private String addMode(final String key, final Measurements current, final Measurements previous) { + String result = ""; + if (current != null) { + result = this.createRow(key, "current", current); + } + if (previous != null) { + result += this.createRow(key, "past", previous); + } + return result; + } + + private String createRow(final String key, final String run, final Measurements measurements) { + final StringBuilder cells = new StringBuilder(); + cells.append(String.format(" <td style=\"text-align: left;\">%s</td>\n", key)); + cells.append(String.format(" <td style=\"text-align: left;\">%s</td>\n", run)); + + this.addDouble(cells, measurements.getMean()); + this.addDouble(cells, measurements.getConvidence()); + this.addDouble(cells, measurements.getStandardDeviation()); + this.addDouble(cells, measurements.getLowerQuartile()); + this.addDouble(cells, measurements.getMedian()); + this.addDouble(cells, measurements.getUpperQuartile()); + this.addDouble(cells, measurements.getMin()); + this.addDouble(cells, measurements.getMax()); + + return String.format(" <tr>\n%s </tr>\n", cells.toString()); + } + + private StringBuilder addDouble(final StringBuilder cells, final Double value) { + return cells.append(String.format(" <td style=\"text-align: right;\">%1.2f</td>\n", value)); + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java b/tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java new file mode 100644 index 0000000000000000000000000000000000000000..9dd23fc882e55d1e5a9147d3916f523ba3ed5bd2 --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/JsonLogSink.java @@ -0,0 +1,44 @@ +package moobench.tools.results; + +import java.nio.file.Files; +import java.nio.file.Path; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import moobench.tools.results.data.Chart; +import moobench.tools.results.data.ValueTuple; +import teetime.framework.AbstractConsumerStage; + +public class JsonLogSink extends AbstractConsumerStage<Chart> { + + private Path path; + + public JsonLogSink(Path path) { + this.path = path; + } + + @Override + protected void execute(Chart chart) throws Exception { + Path jsonLog = this.path.resolve(chart.getName() + ".json"); + ObjectMapper mapper = new ObjectMapper(); + + ObjectNode node = mapper.createObjectNode(); + ArrayNode arrayNode = node.putArray("results"); + + for(ValueTuple value : chart.getValues()) { + ObjectNode objectNode = mapper.createObjectNode(); + for (int i = 0;i < chart.getHeaders().size();i++) { + String name = chart.getHeaders().get(i); + Double number = value.getValues().get(i); + objectNode.put(name, number); + } + objectNode.put("time", value.getTimestamp()); + arrayNode.add(objectNode); + } + + mapper.writeValue(Files.newBufferedWriter(jsonLog), node); + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java b/tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java index 0c7f4664fe3af86c746770efc79756a9ff928160..128eab4cf5052ab4ca8741e55caeade98ea12722 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/LogAppenderStage.java @@ -3,56 +3,37 @@ */ package moobench.tools.results; +import java.util.HashMap; import java.util.Map; import moobench.tools.results.data.Experiment; import moobench.tools.results.data.ExperimentLog; -import teetime.framework.AbstractStage; -import teetime.framework.InputPort; +import teetime.framework.AbstractConsumerStage; import teetime.framework.OutputPort; /** * @author Reiner Jung * @since 1.3.0 */ -public class LogAppenderStage extends AbstractStage { +public class LogAppenderStage extends AbstractConsumerStage<ExperimentLog> { - private final InputPort<ExperimentLog> newDataInputPort = this.createInputPort(ExperimentLog.class); - private final InputPort<ExperimentLog> logInputPort = this.createInputPort(ExperimentLog.class); private final OutputPort<ExperimentLog> outputPort = this.createOutputPort(ExperimentLog.class); - private Map<String,ExperimentLog> logs; - - public InputPort<ExperimentLog> getNewDataInputPort() { - return newDataInputPort; - } - - public InputPort<ExperimentLog> getLogInputPort() { - return logInputPort; - } + private Map<String,ExperimentLog> logs = new HashMap<>(); public OutputPort<ExperimentLog> getOutputPort() { return outputPort; } @Override - protected void execute() throws Exception { - ExperimentLog newData = this.newDataInputPort.receive(); - if (newData != null) { - appendData(newData); - } - ExperimentLog logData = this.logInputPort.receive(); - if (logData != null) { - appendData(logData); - } - } - - private void appendData(ExperimentLog newData) { - ExperimentLog presentLog = logs.get(newData.getKind()); + protected void execute(ExperimentLog log) throws Exception { + ExperimentLog presentLog = logs.get(log.getKind()); if (presentLog != null) { - for (Experiment experiment : newData.getExperiments()) { + for (Experiment experiment : log.getExperiments()) { presentLog.getExperiments().add(experiment); } + } else { + logs.put(log.getKind(), log); } } diff --git a/tools/compile-results/src/main/java/moobench/tools/results/LogWriter.java b/tools/compile-results/src/main/java/moobench/tools/results/LogWriter.java deleted file mode 100644 index cce1495031ebb4cf3d231afec6ee0367fa25de21..0000000000000000000000000000000000000000 --- a/tools/compile-results/src/main/java/moobench/tools/results/LogWriter.java +++ /dev/null @@ -1,47 +0,0 @@ -package moobench.tools.results; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import teetime.framework.AbstractConsumerStage; - -public class LogWriter extends AbstractConsumerStage<List<Map<String,JsonNode>>> { - - private Path logJson; - - public LogWriter(Path logJson) { - this.logJson = logJson; - } - - @Override - protected void execute(List<Map<String,JsonNode>> list) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - ObjectNode node = mapper.createObjectNode(); - ArrayNode arrayNode = node.putArray("results"); - - for(Map<String, JsonNode> map : list) { - ObjectNode objectNode = mapper.createObjectNode(); - for (Entry<String, JsonNode> entry : map.entrySet()) { - JsonNode value = entry.getValue(); - if (value.isDouble()) - objectNode.put(entry.getKey(), value.asDouble()); - else if (value.isInt()) - objectNode.put(entry.getKey(), value.asInt()); - else - this.logger.warn("property {} is of type {}", entry.getKey(), value.getNodeType().toString()); - } - arrayNode.add(objectNode); - } - - mapper.writeValue(Files.newBufferedWriter(logJson), node); - } - -} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/MainLogReader.java b/tools/compile-results/src/main/java/moobench/tools/results/MainLogReader.java deleted file mode 100644 index f22e2aecebc783488b302b8290d9473edc689e0c..0000000000000000000000000000000000000000 --- a/tools/compile-results/src/main/java/moobench/tools/results/MainLogReader.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * - */ -package moobench.tools.results; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import teetime.framework.AbstractProducerStage; - -/** - * @author reiner - * - */ -public class MainLogReader extends AbstractProducerStage<List<Map<String,JsonNode>>> { - - private static final String RESULTS_LABEL = "results"; - - private final Path mainLogJson; - - public MainLogReader(Path mainLogJson) { - this.mainLogJson = mainLogJson; - } - - @Override - protected void execute() throws JsonProcessingException, IOException { - List<Map<String,JsonNode>> result = new ArrayList<Map<String,JsonNode>>(); - JsonNode node; - if (Files.exists(mainLogJson)) { - node = readJsonFile(); - } else { - node = readJsonString(); - } - - JsonNode resultsNode = node.get(RESULTS_LABEL); - if ((resultsNode instanceof ArrayNode)) { - ArrayNode arrayNode = (ArrayNode)resultsNode; - Iterator<JsonNode> iterator = arrayNode.elements(); - while (iterator.hasNext()) { - JsonNode element = iterator.next(); - if (element instanceof ObjectNode) { - ObjectNode objectNode = (ObjectNode)element; - - Iterator<Entry<String, JsonNode>> elementIterator = objectNode.fields(); - Map<String,JsonNode> row = new HashMap<>(); - while (elementIterator.hasNext()) { - Entry<String, JsonNode> parameter = elementIterator.next(); - row.put(parameter.getKey(), parameter.getValue()); - } - result.add(row); - } - } - } - - this.outputPort.send(result); - this.workCompleted(); - } - - - - private JsonNode readJsonString() throws JsonMappingException, JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - String value = "{ \"results\" : [] }"; - return mapper.readTree(value); - } - - private JsonNode readJsonFile() throws JsonProcessingException, IOException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readTree(Files.newInputStream(mainLogJson)); - } - -} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/MappingFileReader.java b/tools/compile-results/src/main/java/moobench/tools/results/MappingFileReader.java deleted file mode 100644 index 30e3de105393d6f6a5f6403ca055c24f5baaa72a..0000000000000000000000000000000000000000 --- a/tools/compile-results/src/main/java/moobench/tools/results/MappingFileReader.java +++ /dev/null @@ -1,20 +0,0 @@ -package moobench.tools.results; - -import java.nio.file.Path; -import java.util.Map; - -import teetime.framework.AbstractProducerStage; - -public class MappingFileReader extends AbstractProducerStage<Map<String,String>> { - - public MappingFileReader(Path mappingFile) { - // TODO Auto-generated constructor stub - } - - @Override - protected void execute() throws Exception { - // TODO Auto-generated method stub - this.workCompleted(); - } - -} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/MergeDataStage.java b/tools/compile-results/src/main/java/moobench/tools/results/MergeDataStage.java deleted file mode 100644 index 85cd673c0cd9be0f43ca6b5596adf663eee10aa8..0000000000000000000000000000000000000000 --- a/tools/compile-results/src/main/java/moobench/tools/results/MergeDataStage.java +++ /dev/null @@ -1,87 +0,0 @@ -package moobench.tools.results; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import teetime.framework.AbstractStage; -import teetime.framework.InputPort; -import teetime.framework.OutputPort; - -public class MergeDataStage extends AbstractStage { - - private static final String BUILD_LABEL = "build"; - - private final InputPort<Map<String, String>> mappingInputPort = this.createInputPort(); - private final InputPort<List<Map<String, JsonNode>>> mainLogInputPort = this.createInputPort(); - private final InputPort<Map<String, JsonNode>> newDataInputPort = this.createInputPort(); - - private final OutputPort<List<Map<String, JsonNode>>> outputPort = this.createOutputPort(); - - private List<Map<String, JsonNode>> mainLog; - private List<Map<String, JsonNode>> bufferLog = new ArrayList<>(); - private Map<String, String> mapping; - - - @Override - protected void execute() throws Exception { - List<Map<String, JsonNode>> log = this.mainLogInputPort.receive(); - if (log != null) { - mainLog = log; - } - Map<String, String> newMapping = this.mappingInputPort.receive(); - if (newMapping != null) { - mapping = newMapping; - } - Map<String, JsonNode> newData = this.newDataInputPort.receive(); - if (newData != null) { - bufferLog.add(newData); - } - } - - @Override - protected void onTerminating() { - moveNewData(); - this.outputPort.send(mainLog); - super.onTerminating(); - } - - private void moveNewData() { - int last = mainLog.size()-1; - int build = mainLog.get(last).get(BUILD_LABEL).asInt() + 1; - - Map<String,JsonNode> node = new HashMap<>(); - node.put(BUILD_LABEL, new ObjectMapper().getNodeFactory().numberNode(build)); - - for (Map<String, JsonNode> data : bufferLog) { - for (Entry<String, JsonNode> entry : data.entrySet()) { - node.put(entry.getKey(), entry.getValue()); - } - } - bufferLog.clear(); - mainLog.add(node); - } - - - public InputPort<List<Map<String, JsonNode>>> getMainLogInputPort() { - return this.mainLogInputPort; - } - - public InputPort<Map<String,String>> getMappingInputPort() { - return this.mappingInputPort; - } - - public InputPort<Map<String,JsonNode>> getNewDataInputPort() { - return this.newDataInputPort ; - } - - public OutputPort<List<Map<String, JsonNode>>> getOutputPort() { - return this.outputPort; - } - -} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java b/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java new file mode 100644 index 0000000000000000000000000000000000000000..b2f6bb66fb8bdc84963dbe66b8d215ec4a373e86 --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/OrderedSet.java @@ -0,0 +1,29 @@ +package moobench.tools.results; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; + +public class OrderedSet<T> extends ArrayList<T> implements Set<T> { + + private static final long serialVersionUID = 719655465496957772L; + + @Override + public boolean add(final T value) { + if (!super.contains(value)) { + return super.add(value); + } else { + return false; + } + } + + @Override + public boolean addAll(final Collection<? extends T> values) { + boolean changed = false; + for(final T value : values) { + changed |= this.add(value); + } + return changed; + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/SpecialArrayElementStage.java b/tools/compile-results/src/main/java/moobench/tools/results/SpecialArrayElementStage.java deleted file mode 100644 index 0579d9997a48952474eacc23f8807150447364c2..0000000000000000000000000000000000000000 --- a/tools/compile-results/src/main/java/moobench/tools/results/SpecialArrayElementStage.java +++ /dev/null @@ -1,23 +0,0 @@ -package moobench.tools.results; - -import java.nio.file.Path; -import java.util.List; - -import teetime.framework.AbstractProducerStage; - -public class SpecialArrayElementStage extends AbstractProducerStage<Path> { - - private List<Path> resultCsvPaths; - - public SpecialArrayElementStage(List<Path> resultCsvPaths) { - this.resultCsvPaths = resultCsvPaths; - } - - @Override - protected void execute() throws Exception { - for(Path path : resultCsvPaths) { - this.outputPort.send(path); - } - this.workCompleted(); - } -} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java b/tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java new file mode 100644 index 0000000000000000000000000000000000000000..5d0e484918c8b7e438fe332a210c3c2ae89e3e7f --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/TailChartStage.java @@ -0,0 +1,40 @@ +/** + * + */ +package moobench.tools.results; + +import moobench.tools.results.data.Chart; +import teetime.stage.basic.AbstractFilter; + +/** + * @author reiner + * + */ +public class TailChartStage extends AbstractFilter<Chart> { + + private Integer window; + + public TailChartStage(Integer window) { + this.window = window; + } + + @Override + protected void execute(Chart chart) throws Exception { + if (window != null) { + int size = chart.getValues().size(); + if (size > window) { + Chart newChart = new Chart(chart.getName()); + newChart.getHeaders().addAll(chart.getHeaders()); + for (int i = size - window; i < size;i++) { + newChart.getValues().add(chart.getValues().get(i)); + } + this.outputPort.send(newChart); + } else { + this.outputPort.send(chart); + } + } else { + this.outputPort.send(chart); + } + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java b/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java index 8232d5c4eec39fc0a85dfcc8eeacb2f32a882171..90b56acf33b3bfe64942f24efe9288786e093187 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/TeetimeConfiguration.java @@ -1,11 +1,10 @@ package moobench.tools.results; +import java.io.File; +import java.io.FilenameFilter; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.databind.JsonNode; import moobench.tools.results.data.ExperimentLog; import teetime.framework.Configuration; @@ -14,36 +13,62 @@ import teetime.stage.basic.distributor.strategy.CopyByReferenceStrategy; public class TeetimeConfiguration extends Configuration { - public TeetimeConfiguration(Settings settings) { - List<Path> logFilePaths = new ArrayList<Path>(); - for (Path path : settings.getInputPaths()) { - logFilePaths.add(settings.getLogPath().resolve(path.getFileName())); - } - - ElementProducer<Path> yamlInputPathsProducer = new ElementProducer<>(settings.getInputPaths()); - ElementProducer<Path> yamlLogPathsProducer = new ElementProducer<>(logFilePaths); - - YamlReaderStage yamlInputReader = new YamlReaderStage(); - YamlReaderStage yamlLogReader = new YamlReaderStage(); - - LogAppenderStage logAppenderStage = new LogAppenderStage(); - Distributor<ExperimentLog> distributor = new Distributor<>(new CopyByReferenceStrategy()); - - YamlLogSink yamlLogSink = new YamlLogSink(); - - //ChartAssemblerStage :: chartAssemblerStage - //JsonLogSink :: jsonLogSink - //GenerateHtmlTable :: generateHtmlTable - //FileSink :: fileSink - - this.connectPorts(yamlInputPathsProducer.getOutputPort(), yamlInputReader.getInputPort()); - this.connectPorts(yamlLogPathsProducer.getOutputPort(), yamlLogReader.getInputPort()); - - this.connectPorts(yamlInputReader.getOutputPort(), logAppenderStage.getNewDataInputPort()); - this.connectPorts(yamlLogReader.getOutputPort(), logAppenderStage.getLogInputPort()); - - this.connectPorts(logAppenderStage.getOutputPort(), distributor.getInputPort()); - - this.connectPorts(distributor.getNewOutputPort(), yamlLogSink.getInputPort()); - } + public TeetimeConfiguration(final Settings settings) { + final List<Path> logFilePaths = this.createInputPaths(settings); + + final ElementProducer<Path> yamlInputPathsProducer = new ElementProducer<>(logFilePaths); + + final YamlReaderStage yamlInputReader = new YamlReaderStage(); + + final LogAppenderStage logAppenderStage = new LogAppenderStage(); + final Distributor<ExperimentLog> distributor = new Distributor<>(new CopyByReferenceStrategy()); + + final YamlLogSink yamlLogSink = new YamlLogSink(settings.getLogPath()); + + final ChartAssemblerStage chartAssemblerStage = new ChartAssemblerStage(); + final TailChartStage tailChartStage = new TailChartStage(settings.getWindow()); + final JsonLogSink jsonLogSink = new JsonLogSink(settings.getJsonLogPath()); + final ComputeTableStage computeTableStage = new ComputeTableStage(); + final GenerateHtmlTableStage generateHtmlTableStage = new GenerateHtmlTableStage(settings.getTablePath()); + final FileSink fileSink = new FileSink(); + + this.connectPorts(yamlInputPathsProducer.getOutputPort(), yamlInputReader.getInputPort()); + this.connectPorts(yamlInputReader.getOutputPort(), logAppenderStage.getInputPort()); + + this.connectPorts(logAppenderStage.getOutputPort(), distributor.getInputPort()); + + this.connectPorts(distributor.getNewOutputPort(), yamlLogSink.getInputPort()); + this.connectPorts(distributor.getNewOutputPort(), chartAssemblerStage.getInputPort()); + this.connectPorts(distributor.getNewOutputPort(), computeTableStage.getInputPort()); + + this.connectPorts(computeTableStage.getOutputPort(), generateHtmlTableStage.getInputPort()); + this.connectPorts(generateHtmlTableStage.getOutputPort(), fileSink.getInputPort()); + + this.connectPorts(chartAssemblerStage.getOutputPort(), tailChartStage.getInputPort()); + this.connectPorts(tailChartStage.getOutputPort(), jsonLogSink.getInputPort()); + } + + private List<Path> createInputPaths(final Settings settings) { + final ArrayList<Path> logFilePaths = new ArrayList<Path>(); + for (final Path path : settings.getInputPaths()) { + logFilePaths.add(path); + } + final FilenameFilter filter = new FilenameFilter() { + + @Override + public boolean accept(final File file, final String name) { + final int last = name.lastIndexOf("."); + if (last < 0) { + return false; + } + final String extension = name.substring(last+1); + return "yaml".equals(extension); + } + }; + for (final File file : settings.getLogPath().toFile().listFiles(filter)) { + logFilePaths.add(file.toPath()); + } + + return logFilePaths; + } } diff --git a/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java b/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java index 7603550727d283cc64d4a2abdd902e86819cb1fd..de3d9186bb32e0c7b2fa4461a0d03519b4bbf029 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/YamlLogSink.java @@ -1,13 +1,67 @@ package moobench.tools.results; +import java.io.FileWriter; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.Tag; +import org.yaml.snakeyaml.representer.Represent; +import org.yaml.snakeyaml.representer.Representer; + import moobench.tools.results.data.ExperimentLog; +import moobench.tools.results.data.Measurements; import teetime.framework.AbstractConsumerStage; public class YamlLogSink extends AbstractConsumerStage<ExperimentLog> { + Path logPath; + + public YamlLogSink(Path logPath) { + this.logPath = logPath; + } + @Override - protected void execute(ExperimentLog element) throws Exception { - // TODO Auto-generated method stub + protected void execute(ExperimentLog log) throws Exception { + Path logPath = this.logPath.resolve(String.format("%s.yaml", log.getKind())); + + Representer representer = new LogRepresenter(); + DumperOptions options = new DumperOptions(); + Yaml yaml = new Yaml(representer, options); + + FileWriter writer = new FileWriter(logPath.toFile()); + yaml.dump(log, writer); + } + + private class LogRepresenter extends Representer { + + public LogRepresenter() { + this.representers.put(Measurements.class, new RepresentMeasurements()); + } + + private class RepresentMeasurements implements Represent { + + @Override + public Node representData(Object data) { + Measurements measurements = (Measurements)data; + + List<Double> values = new ArrayList<>(); + values.add(measurements.getMean()); + values.add(measurements.getStandardDeviation()); + values.add(measurements.getConvidence()); + values.add(measurements.getLowerQuartile()); + values.add(measurements.getMedian()); + values.add(measurements.getUpperQuartile()); + values.add(measurements.getMin()); + values.add(measurements.getMax()); + + return representSequence(new Tag("!!" + Measurements.class.getCanonicalName()), values, defaultFlowStyle); + } + + } } } diff --git a/tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java b/tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java index e64b2e50a1fa5c20ba63bf41882decf1f1ddf83f..0cbbe6c34793606988c285a3a007b41f4bc56791 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/YamlReaderStage.java @@ -14,11 +14,14 @@ public class YamlReaderStage extends AbstractTransformation<Path, ExperimentLog> @Override protected void execute(Path path) throws Exception { - Yaml yaml = new Yaml(new Constructor(ExperimentLog.class)); - InputStream inputStream = Files.newInputStream(path); - ExperimentLog data = yaml.load(inputStream); - - this.outputPort.send(data); + if (Files.exists(path)) { + Yaml yaml = new Yaml(new Constructor(ExperimentLog.class)); + InputStream inputStream = Files.newInputStream(path); + ExperimentLog data = yaml.load(inputStream); + + this.outputPort.send(data); + } else + this.logger.error("Cannot read YAML log file {}", path.toString()); } } diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/Chart.java b/tools/compile-results/src/main/java/moobench/tools/results/data/Chart.java new file mode 100644 index 0000000000000000000000000000000000000000..0c6ca85152ef21a72033e256889627318774a05b --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/data/Chart.java @@ -0,0 +1,27 @@ +package moobench.tools.results.data; + +import java.util.ArrayList; +import java.util.List; + +public class Chart { + + final String name; + final List<String> headers = new ArrayList<>(); + final List<ValueTuple> values = new ArrayList<ValueTuple>(); + + public Chart(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public List<String> getHeaders() { + return headers; + } + + public List<ValueTuple> getValues() { + return values; + } +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java b/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java index e6d1dc877f81286b282e2f4a292ff8d7685f53d8..a14f9bd44de1cdf04198cd0cf3993735822b7ffc 100644 --- a/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java +++ b/tools/compile-results/src/main/java/moobench/tools/results/data/Measurements.java @@ -2,16 +2,16 @@ package moobench.tools.results.data; public class Measurements { - private double mean; - private double convidence; - private double standardDeviation; - private double lowerQuartile; - private double median; - private double upperQuartile; - private double max; - private double min; + private Double mean; + private Double convidence; + private Double standardDeviation; + private Double lowerQuartile; + private Double median; + private Double upperQuartile; + private Double max; + private Double min; - public Measurements(double mean, double standardDeviation, double convidence, double lowerQuartile, double median, double upperQuartile, double min, double max) { + public Measurements(Double mean, Double standardDeviation, Double convidence, Double lowerQuartile, Double median, Double upperQuartile, Double min, Double max) { this.mean = mean; this.convidence = convidence; this.standardDeviation = standardDeviation; @@ -22,7 +22,7 @@ public class Measurements { this.max = max; } - public double getMean() { + public Double getMean() { return mean; } @@ -32,31 +32,31 @@ public class Measurements { * * @return convidence value */ - public double getConvidence() { + public Double getConvidence() { return convidence; } - public double getStandardDeviation() { + public Double getStandardDeviation() { return standardDeviation; } - public double getLowerQuartile() { + public Double getLowerQuartile() { return lowerQuartile; } - public double getMedian() { + public Double getMedian() { return median; } - public double getUpperQuartile() { + public Double getUpperQuartile() { return upperQuartile; } - public double getMin() { + public Double getMin() { return min; } - public double getMax() { + public Double getMax() { return max; } diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java b/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java new file mode 100644 index 0000000000000000000000000000000000000000..b1bdfe117964ac1dc5e10a152b7a7ebb89f26f49 --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/data/OutputFile.java @@ -0,0 +1,23 @@ +package moobench.tools.results.data; + +import java.nio.file.Path; + +public class OutputFile { + + Path filePath; + String content; + + public OutputFile(final Path filePath, final String content) { + this.filePath = filePath; + this.content = content; + } + + public Path getFilePath() { + return this.filePath; + } + + public String getContent() { + return this.content; + } + +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java b/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java new file mode 100644 index 0000000000000000000000000000000000000000..8a73e5d80ee8a7417e24af91ed03d81a32c96c81 --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/data/TableInformation.java @@ -0,0 +1,27 @@ +package moobench.tools.results.data; + +public class TableInformation { + + private final String name; + + private final Experiment current; + private final Experiment previous; + + public TableInformation(final String name, final Experiment current, final Experiment previous) { + this.name = name; + this.current = current; + this.previous = previous; + } + + public String getName() { + return this.name; + } + + public Experiment getCurrent() { + return this.current; + } + + public Experiment getPrevious() { + return this.previous; + } +} diff --git a/tools/compile-results/src/main/java/moobench/tools/results/data/ValueTuple.java b/tools/compile-results/src/main/java/moobench/tools/results/data/ValueTuple.java new file mode 100644 index 0000000000000000000000000000000000000000..905a075dcf60ae76ffa9dea58cc41805141562fd --- /dev/null +++ b/tools/compile-results/src/main/java/moobench/tools/results/data/ValueTuple.java @@ -0,0 +1,23 @@ +package moobench.tools.results.data; + +import java.util.ArrayList; +import java.util.List; + +public class ValueTuple { + + long timestamp; + + List<Double> values = new ArrayList<>(); + + public ValueTuple(long timestamp) { + this.timestamp = timestamp; + } + + public long getTimestamp() { + return timestamp; + } + + public List<Double> getValues() { + return values; + } +}