From bde3013b389aa317c6466ea29de520c9ada5194f Mon Sep 17 00:00:00 2001 From: 123liuziming <448918299@qq.com> Date: Fri, 28 Jun 2024 23:35:56 +0800 Subject: [PATCH 1/2] fix windows benchmark fail --- .../java/io/opentelemetry/OverheadTests.java | 25 ++++++++++---- .../opentelemetry/containers/K6Container.java | 5 ++- .../results/ResultsCollector.java | 6 ++-- .../util/ContainerNamingConvention.java | 33 +++++++++++++++++++ .../util/LocalNamingConvention.java | 33 +++++++++++++++++++ .../opentelemetry/util/NamingConvention.java | 33 +++++-------------- .../opentelemetry/util/NamingConventions.java | 14 +++++--- 7 files changed, 106 insertions(+), 43 deletions(-) create mode 100644 benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java create mode 100644 benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java b/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java index b69a6d708294..86756a230f39 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java @@ -110,7 +110,7 @@ void runAppOnce(TestConfig config, Agent agent) throws Exception { } private void startRecording(Agent agent, GenericContainer petclinic) throws Exception { - Path outFile = namingConventions.container.jfrFile(agent); + String outFile = namingConventions.container.jfrFile(agent); String[] command = { "jcmd", "1", @@ -123,16 +123,27 @@ private void startRecording(Agent agent, GenericContainer petclinic) throws E petclinic.execInContainer(command); } - private void doWarmupPhase(TestConfig testConfig, GenericContainer petclinic) throws IOException, InterruptedException { - System.out.println("Performing startup warming phase for " + testConfig.getWarmupSeconds() + " seconds..."); + private void doWarmupPhase(TestConfig testConfig, GenericContainer petclinic) + throws IOException, InterruptedException { + System.out.println( + "Performing startup warming phase for " + testConfig.getWarmupSeconds() + " seconds..."); // excluding the JFR recording from the warmup causes strange inconsistencies in the results System.out.println("Starting disposable JFR warmup recording..."); - String[] startCommand = {"jcmd", "1", "JFR.start", "settings=/app/overhead.jfc", "dumponexit=true", "name=warmup", "filename=warmup.jfr"}; + String[] startCommand = { + "jcmd", + "1", + "JFR.start", + "settings=/app/overhead.jfc", + "dumponexit=true", + "name=warmup", + "filename=warmup.jfr" + }; petclinic.execInContainer(startCommand); - long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(testConfig.getWarmupSeconds()); - while(System.currentTimeMillis() < deadline) { + long deadline = + System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(testConfig.getWarmupSeconds()); + while (System.currentTimeMillis() < deadline) { GenericContainer k6 = new GenericContainer<>(DockerImageName.parse("loadimpact/k6")) .withNetwork(NETWORK) @@ -151,7 +162,7 @@ private void doWarmupPhase(TestConfig testConfig, GenericContainer petclinic) private void writeStartupTimeFile(Agent agent, long start) throws IOException { long delta = System.currentTimeMillis() - start; - Path startupPath = namingConventions.local.startupDurationFile(agent); + Path startupPath = Path.of(namingConventions.local.startupDurationFile(agent)); Files.writeString(startupPath, String.valueOf(delta)); } } diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java b/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java index ff022970dbb3..7f6994d1a5d7 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java @@ -8,7 +8,6 @@ import io.opentelemetry.agents.Agent; import io.opentelemetry.config.TestConfig; import io.opentelemetry.util.NamingConventions; -import java.nio.file.Path; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,7 +34,7 @@ public K6Container( } public GenericContainer build() { - Path k6OutputFile = namingConventions.container.k6Results(agent); + String k6OutputFile = namingConventions.container.k6Results(agent); return new GenericContainer<>(DockerImageName.parse("loadimpact/k6")) .withNetwork(network) .withNetworkAliases("k6") @@ -52,7 +51,7 @@ public GenericContainer build() { "--rps", String.valueOf(config.getMaxRequestRate()), "--summary-export", - k6OutputFile.toString(), + k6OutputFile, "/app/basic.js") .withStartupCheckStrategy( new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(15))); diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java b/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java index c2012cdf41b9..d7b47bb7fbc9 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java @@ -54,14 +54,14 @@ private AppPerfResults readAgentResults(Agent agent, TestConfig config) { private AppPerfResults.Builder addStartupTime(AppPerfResults.Builder builder, Agent agent) throws IOException { - Path file = namingConvention.startupDurationFile(agent); + Path file = Path.of(namingConvention.startupDurationFile(agent)); long startupDuration = Long.parseLong(new String(Files.readAllBytes(file)).trim()); return builder.startupDurationMs(startupDuration); } private AppPerfResults.Builder addK6Results(AppPerfResults.Builder builder, Agent agent) throws IOException { - Path k6File = namingConvention.k6Results(agent); + Path k6File = Path.of(namingConvention.k6Results(agent)); String json = new String(Files.readAllBytes(k6File)); double iterationAvg = read(json, "$.metrics.iteration_duration.avg"); double iterationP95 = read(json, "$.metrics.iteration_duration['p(95)']"); @@ -82,7 +82,7 @@ private static double read(String json, String jsonPath) { private AppPerfResults.Builder addJfrResults(AppPerfResults.Builder builder, Agent agent) throws IOException { - Path jfrFile = namingConvention.jfrFile(agent); + Path jfrFile = Path.of(namingConvention.jfrFile(agent)); return builder .totalGCTime(readTotalGCTime(jfrFile)) .totalAllocated(readTotalAllocated(jfrFile)) diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java new file mode 100644 index 000000000000..8866ea28e92c --- /dev/null +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.util; + +import io.opentelemetry.agents.Agent; + +public class ContainerNamingConvention implements NamingConvention { + private final String dir; + + public ContainerNamingConvention(String dir) { + this.dir = dir; + } + + public String k6Results(Agent agent) { + + return String.join("/", dir, "k6_out_" + agent.getName() + ".json"); + } + + public String jfrFile(Agent agent) { + return String.join("/", dir, "petclinic-" + agent.getName() + ".jfr"); + } + + public String startupDurationFile(Agent agent) { + return String.join("/", dir, "startup-time-" + agent.getName() + ".txt"); + } + + public String root() { + return dir; + } +} diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java new file mode 100644 index 000000000000..4c4305e849a3 --- /dev/null +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.util; + +import io.opentelemetry.agents.Agent; +import java.nio.file.Paths; + +public class LocalNamingConvention implements NamingConvention { + private final String dir; + + public LocalNamingConvention(String dir) { + this.dir = dir; + } + + public String k6Results(Agent agent) { + return Paths.get(dir, "k6_out_" + agent.getName() + ".json").toString(); + } + + public String jfrFile(Agent agent) { + return Paths.get(dir, "petclinic-" + agent.getName() + ".jfr").toString(); + } + + public String startupDurationFile(Agent agent) { + return Paths.get(dir, "startup-time-" + agent.getName() + ".txt").toString(); + } + + public String root() { + return dir; + } +} diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java index 96a45eceeef3..afbdd653e9a5 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java @@ -6,51 +6,34 @@ package io.opentelemetry.util; import io.opentelemetry.agents.Agent; -import java.nio.file.Path; -import java.nio.file.Paths; /** * This utility class provides the standard file naming conventions, primarily for files that are * shared between containers and the test runner. It consolidates the naming logic into one place to * ensure consistency, reduce duplication, and decrease errors. */ -public class NamingConvention { - - private final String dir; - - public NamingConvention(String dir) { - this.dir = dir; - } - +public interface NamingConvention { /** - * Returns a path to the location of the k6 results json file. + * Returns a path string to the location of the k6 results json file. * * @param agent The agent to get results file path for */ - public Path k6Results(Agent agent) { - return Paths.get(dir, "k6_out_" + agent.getName() + ".json"); - } + String k6Results(Agent agent); /** - * Returns a path to the location of the jfr output file for a given agent run. + * Returns a path string to the location of the jfr output file for a given agent run. * * @param agent The agent to get the jfr file path for. */ - public Path jfrFile(Agent agent) { - return Paths.get(dir, "petclinic-" + agent.getName() + ".jfr"); - } + String jfrFile(Agent agent); /** - * Returns the path to the file that contains the startup duration for a given agent run. + * Returns the path string to the file that contains the startup duration for a given agent run. * * @param agent The agent to get the startup duration for. */ - public Path startupDurationFile(Agent agent) { - return Paths.get(dir, "startup-time-" + agent.getName() + ".txt"); - } + String startupDurationFile(Agent agent); /** Returns the root path that this naming convention was configured with. */ - public String root() { - return dir; - } + String root(); } diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java index 6caf28dfef31..4aeca8f7a92e 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java @@ -5,18 +5,22 @@ package io.opentelemetry.util; -/** An container to hold both the local and container naming conventions. */ +/** A container to hold both the local and container naming conventions. */ public class NamingConventions { - public final NamingConvention container = new NamingConvention("/results"); - public final NamingConvention local = new NamingConvention("."); + public final NamingConvention container = new ContainerNamingConvention("/results"); + public final NamingConvention local = new LocalNamingConvention("."); - /** @return Root path for the local naming convention (where results are output) */ + /** + * @return Root path for the local naming convention (where results are output) + */ public String localResults() { return local.root(); } - /** @return Root path for the container naming convention (where results are output) */ + /** + * @return Root path for the container naming convention (where results are output) + */ public String containerResults() { return container.root(); } From 121408204f0140fd33906bc4031332838cc2a549 Mon Sep 17 00:00:00 2001 From: 123liuziming <448918299@qq.com> Date: Fri, 28 Jun 2024 23:35:56 +0800 Subject: [PATCH 2/2] fix windows benchmark fail --- .../java/io/opentelemetry/OverheadTests.java | 25 ++++++++++---- .../opentelemetry/containers/K6Container.java | 5 ++- .../results/ResultsCollector.java | 6 ++-- .../util/ContainerNamingConvention.java | 33 +++++++++++++++++++ .../util/LocalNamingConvention.java | 33 +++++++++++++++++++ .../opentelemetry/util/NamingConvention.java | 33 +++++-------------- .../opentelemetry/util/NamingConventions.java | 14 +++++--- 7 files changed, 106 insertions(+), 43 deletions(-) create mode 100644 benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java create mode 100644 benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java b/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java index b69a6d708294..86756a230f39 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/OverheadTests.java @@ -110,7 +110,7 @@ void runAppOnce(TestConfig config, Agent agent) throws Exception { } private void startRecording(Agent agent, GenericContainer petclinic) throws Exception { - Path outFile = namingConventions.container.jfrFile(agent); + String outFile = namingConventions.container.jfrFile(agent); String[] command = { "jcmd", "1", @@ -123,16 +123,27 @@ private void startRecording(Agent agent, GenericContainer petclinic) throws E petclinic.execInContainer(command); } - private void doWarmupPhase(TestConfig testConfig, GenericContainer petclinic) throws IOException, InterruptedException { - System.out.println("Performing startup warming phase for " + testConfig.getWarmupSeconds() + " seconds..."); + private void doWarmupPhase(TestConfig testConfig, GenericContainer petclinic) + throws IOException, InterruptedException { + System.out.println( + "Performing startup warming phase for " + testConfig.getWarmupSeconds() + " seconds..."); // excluding the JFR recording from the warmup causes strange inconsistencies in the results System.out.println("Starting disposable JFR warmup recording..."); - String[] startCommand = {"jcmd", "1", "JFR.start", "settings=/app/overhead.jfc", "dumponexit=true", "name=warmup", "filename=warmup.jfr"}; + String[] startCommand = { + "jcmd", + "1", + "JFR.start", + "settings=/app/overhead.jfc", + "dumponexit=true", + "name=warmup", + "filename=warmup.jfr" + }; petclinic.execInContainer(startCommand); - long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(testConfig.getWarmupSeconds()); - while(System.currentTimeMillis() < deadline) { + long deadline = + System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(testConfig.getWarmupSeconds()); + while (System.currentTimeMillis() < deadline) { GenericContainer k6 = new GenericContainer<>(DockerImageName.parse("loadimpact/k6")) .withNetwork(NETWORK) @@ -151,7 +162,7 @@ private void doWarmupPhase(TestConfig testConfig, GenericContainer petclinic) private void writeStartupTimeFile(Agent agent, long start) throws IOException { long delta = System.currentTimeMillis() - start; - Path startupPath = namingConventions.local.startupDurationFile(agent); + Path startupPath = Path.of(namingConventions.local.startupDurationFile(agent)); Files.writeString(startupPath, String.valueOf(delta)); } } diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java b/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java index ff022970dbb3..7f6994d1a5d7 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/containers/K6Container.java @@ -8,7 +8,6 @@ import io.opentelemetry.agents.Agent; import io.opentelemetry.config.TestConfig; import io.opentelemetry.util.NamingConventions; -import java.nio.file.Path; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,7 +34,7 @@ public K6Container( } public GenericContainer build() { - Path k6OutputFile = namingConventions.container.k6Results(agent); + String k6OutputFile = namingConventions.container.k6Results(agent); return new GenericContainer<>(DockerImageName.parse("loadimpact/k6")) .withNetwork(network) .withNetworkAliases("k6") @@ -52,7 +51,7 @@ public GenericContainer build() { "--rps", String.valueOf(config.getMaxRequestRate()), "--summary-export", - k6OutputFile.toString(), + k6OutputFile, "/app/basic.js") .withStartupCheckStrategy( new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(15))); diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java b/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java index c2012cdf41b9..d7b47bb7fbc9 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/results/ResultsCollector.java @@ -54,14 +54,14 @@ private AppPerfResults readAgentResults(Agent agent, TestConfig config) { private AppPerfResults.Builder addStartupTime(AppPerfResults.Builder builder, Agent agent) throws IOException { - Path file = namingConvention.startupDurationFile(agent); + Path file = Path.of(namingConvention.startupDurationFile(agent)); long startupDuration = Long.parseLong(new String(Files.readAllBytes(file)).trim()); return builder.startupDurationMs(startupDuration); } private AppPerfResults.Builder addK6Results(AppPerfResults.Builder builder, Agent agent) throws IOException { - Path k6File = namingConvention.k6Results(agent); + Path k6File = Path.of(namingConvention.k6Results(agent)); String json = new String(Files.readAllBytes(k6File)); double iterationAvg = read(json, "$.metrics.iteration_duration.avg"); double iterationP95 = read(json, "$.metrics.iteration_duration['p(95)']"); @@ -82,7 +82,7 @@ private static double read(String json, String jsonPath) { private AppPerfResults.Builder addJfrResults(AppPerfResults.Builder builder, Agent agent) throws IOException { - Path jfrFile = namingConvention.jfrFile(agent); + Path jfrFile = Path.of(namingConvention.jfrFile(agent)); return builder .totalGCTime(readTotalGCTime(jfrFile)) .totalAllocated(readTotalAllocated(jfrFile)) diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java new file mode 100644 index 000000000000..8866ea28e92c --- /dev/null +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/ContainerNamingConvention.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.util; + +import io.opentelemetry.agents.Agent; + +public class ContainerNamingConvention implements NamingConvention { + private final String dir; + + public ContainerNamingConvention(String dir) { + this.dir = dir; + } + + public String k6Results(Agent agent) { + + return String.join("/", dir, "k6_out_" + agent.getName() + ".json"); + } + + public String jfrFile(Agent agent) { + return String.join("/", dir, "petclinic-" + agent.getName() + ".jfr"); + } + + public String startupDurationFile(Agent agent) { + return String.join("/", dir, "startup-time-" + agent.getName() + ".txt"); + } + + public String root() { + return dir; + } +} diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java new file mode 100644 index 000000000000..4c4305e849a3 --- /dev/null +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/LocalNamingConvention.java @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.util; + +import io.opentelemetry.agents.Agent; +import java.nio.file.Paths; + +public class LocalNamingConvention implements NamingConvention { + private final String dir; + + public LocalNamingConvention(String dir) { + this.dir = dir; + } + + public String k6Results(Agent agent) { + return Paths.get(dir, "k6_out_" + agent.getName() + ".json").toString(); + } + + public String jfrFile(Agent agent) { + return Paths.get(dir, "petclinic-" + agent.getName() + ".jfr").toString(); + } + + public String startupDurationFile(Agent agent) { + return Paths.get(dir, "startup-time-" + agent.getName() + ".txt").toString(); + } + + public String root() { + return dir; + } +} diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java index 96a45eceeef3..afbdd653e9a5 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConvention.java @@ -6,51 +6,34 @@ package io.opentelemetry.util; import io.opentelemetry.agents.Agent; -import java.nio.file.Path; -import java.nio.file.Paths; /** * This utility class provides the standard file naming conventions, primarily for files that are * shared between containers and the test runner. It consolidates the naming logic into one place to * ensure consistency, reduce duplication, and decrease errors. */ -public class NamingConvention { - - private final String dir; - - public NamingConvention(String dir) { - this.dir = dir; - } - +public interface NamingConvention { /** - * Returns a path to the location of the k6 results json file. + * Returns a path string to the location of the k6 results json file. * * @param agent The agent to get results file path for */ - public Path k6Results(Agent agent) { - return Paths.get(dir, "k6_out_" + agent.getName() + ".json"); - } + String k6Results(Agent agent); /** - * Returns a path to the location of the jfr output file for a given agent run. + * Returns a path string to the location of the jfr output file for a given agent run. * * @param agent The agent to get the jfr file path for. */ - public Path jfrFile(Agent agent) { - return Paths.get(dir, "petclinic-" + agent.getName() + ".jfr"); - } + String jfrFile(Agent agent); /** - * Returns the path to the file that contains the startup duration for a given agent run. + * Returns the path string to the file that contains the startup duration for a given agent run. * * @param agent The agent to get the startup duration for. */ - public Path startupDurationFile(Agent agent) { - return Paths.get(dir, "startup-time-" + agent.getName() + ".txt"); - } + String startupDurationFile(Agent agent); /** Returns the root path that this naming convention was configured with. */ - public String root() { - return dir; - } + String root(); } diff --git a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java index 6caf28dfef31..4aeca8f7a92e 100644 --- a/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java +++ b/benchmark-overhead/src/test/java/io/opentelemetry/util/NamingConventions.java @@ -5,18 +5,22 @@ package io.opentelemetry.util; -/** An container to hold both the local and container naming conventions. */ +/** A container to hold both the local and container naming conventions. */ public class NamingConventions { - public final NamingConvention container = new NamingConvention("/results"); - public final NamingConvention local = new NamingConvention("."); + public final NamingConvention container = new ContainerNamingConvention("/results"); + public final NamingConvention local = new LocalNamingConvention("."); - /** @return Root path for the local naming convention (where results are output) */ + /** + * @return Root path for the local naming convention (where results are output) + */ public String localResults() { return local.root(); } - /** @return Root path for the container naming convention (where results are output) */ + /** + * @return Root path for the container naming convention (where results are output) + */ public String containerResults() { return container.root(); }