From 93e77f376544a9c183ebbad5b63d06c8ccdf5346 Mon Sep 17 00:00:00 2001 From: Christian Wulf <chw@informatik.uni-kiel.de> Date: Wed, 25 Jun 2014 12:17:30 +0200 Subject: [PATCH] added performance comparison for methodcallWithPorts variant --- .../java/teetime/util/StatisticsUtil.java | 1 + .../core/pipe/OrderedGrowableArrayPipe.java | 2 +- .../framework/core/pipe/SpScPipe.java | 10 +- .../examples/AllTests.java | 101 ++++++++++ .../MethodCallThroughputAnalysis14.java | 12 +- .../MethodCallThroughputAnalysis15.java | 4 +- ...dCallThoughputTimestampAnalysis16Test.java | 55 +++--- .../MethodCallThroughputAnalysis16.java | 17 +- ...dCallThoughputTimestampAnalysis17Test.java | 8 +- .../MethodCallThroughputAnalysis17.java | 3 +- .../MethodCallThroughputAnalysis18.java | 3 +- ...dCallThoughputTimestampAnalysis19Test.java | 91 +++++++++ .../MethodCallThroughputAnalysis19.java | 182 ++++++++++++++++++ src/test/java/test/PerformanceResult.java | 5 + 14 files changed, 443 insertions(+), 51 deletions(-) create mode 100644 src/test/java/teetime/variant/methodcallWithPorts/examples/AllTests.java create mode 100644 src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThoughputTimestampAnalysis19Test.java create mode 100644 src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThroughputAnalysis19.java diff --git a/src/main/java/teetime/util/StatisticsUtil.java b/src/main/java/teetime/util/StatisticsUtil.java index 4708e96f..38788e19 100644 --- a/src/main/java/teetime/util/StatisticsUtil.java +++ b/src/main/java/teetime/util/StatisticsUtil.java @@ -47,6 +47,7 @@ public class StatisticsUtil { public static PerformanceResult printStatistics(final long overallDurationInNs, final List<TimestampObject> timestampObjects) { PerformanceResult performanceResult = new PerformanceResult(); + performanceResult.overallDurationInNs = overallDurationInNs; System.out.println("Duration: " + TimeUnit.NANOSECONDS.toMillis(overallDurationInNs) + " ms"); final List<Long> sortedDurationsInNs = new ArrayList<Long>(timestampObjects.size() / 2); diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/OrderedGrowableArrayPipe.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/OrderedGrowableArrayPipe.java index 26c8a884..109824ff 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/OrderedGrowableArrayPipe.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/OrderedGrowableArrayPipe.java @@ -11,7 +11,7 @@ public class OrderedGrowableArrayPipe<T> extends AbstractPipe<T> { private int tail; public OrderedGrowableArrayPipe() { - this(17); + this(1); } public OrderedGrowableArrayPipe(final int initialCapacity) { diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/SpScPipe.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/SpScPipe.java index 54869f0f..ece1f1d0 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/SpScPipe.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/SpScPipe.java @@ -6,10 +6,14 @@ import teetime.variant.methodcallWithPorts.framework.core.OutputPort; public class SpScPipe<T> extends AbstractPipe<T> { - private final FFBufferOrdered3<T> queue = new FFBufferOrdered3<T>(100010); + private final FFBufferOrdered3<T> queue; - public static <T> void connect(final OutputPort<T> sourcePort, final InputPort<T> targetPort) { - IPipe<T> pipe = new SpScPipe<T>(); + public SpScPipe(final int initialCapacity) { + this.queue = new FFBufferOrdered3<T>(initialCapacity); + } + + public static <T> void connect(final OutputPort<T> sourcePort, final InputPort<T> targetPort, final int initialCapacity) { + IPipe<T> pipe = new SpScPipe<T>(initialCapacity); sourcePort.setPipe(pipe); targetPort.setPipe(pipe); } diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/AllTests.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/AllTests.java new file mode 100644 index 00000000..9466ae3b --- /dev/null +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/AllTests.java @@ -0,0 +1,101 @@ +package teetime.variant.methodcallWithPorts.examples; + +import static org.junit.Assert.assertEquals; + +import java.util.Map; +import java.util.Map.Entry; + +import org.junit.AfterClass; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +import teetime.variant.methodcall.examples.experiment01.MethodCallThoughputTimestampAnalysis1Test; +import teetime.variant.methodcallWithPorts.examples.experiment09.MethodCallThoughputTimestampAnalysis9Test; +import teetime.variant.methodcallWithPorts.examples.experiment10.MethodCallThoughputTimestampAnalysis10Test; +import teetime.variant.methodcallWithPorts.examples.experiment11.MethodCallThoughputTimestampAnalysis11Test; +import teetime.variant.methodcallWithPorts.examples.experiment14.MethodCallThoughputTimestampAnalysis14Test; +import teetime.variant.methodcallWithPorts.examples.experiment15.MethodCallThoughputTimestampAnalysis15Test; +import teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test; +import teetime.variant.methodcallWithPorts.examples.experiment17.MethodCallThoughputTimestampAnalysis17Test; +import teetime.variant.methodcallWithPorts.examples.experiment19.MethodCallThoughputTimestampAnalysis19Test; +import test.PerformanceResult; +import test.PerformanceTest; + +@RunWith(Suite.class) +@SuiteClasses({ + MethodCallThoughputTimestampAnalysis1Test.class, + MethodCallThoughputTimestampAnalysis9Test.class, + MethodCallThoughputTimestampAnalysis10Test.class, + MethodCallThoughputTimestampAnalysis11Test.class, + MethodCallThoughputTimestampAnalysis14Test.class, + MethodCallThoughputTimestampAnalysis15Test.class, + MethodCallThoughputTimestampAnalysis16Test.class, + MethodCallThoughputTimestampAnalysis17Test.class, + MethodCallThoughputTimestampAnalysis19Test.class, +}) +public class AllTests { + + private static final double RESULT_TESTS_16 = 30; + private static final double RESULT_TESTS_19 = 70; + + @AfterClass + public static void compareResults() { + Map<String, PerformanceResult> performanceResults = PerformanceTest.measurementRepository.performanceResults; + for (Entry<String, PerformanceResult> entry : performanceResults.entrySet()) { + System.out.println("---> " + entry.getKey() + "\n" + entry.getValue()); + } + + PerformanceResult test1 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcall.examples.experiment01.MethodCallThoughputTimestampAnalysis1Test)"); + PerformanceResult test9 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcallWithPorts.examples.experiment09.MethodCallThoughputTimestampAnalysis9Test)"); + PerformanceResult test10 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcallWithPorts.examples.experiment10.MethodCallThoughputTimestampAnalysis10Test)"); + PerformanceResult test11 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcallWithPorts.examples.experiment11.MethodCallThoughputTimestampAnalysis11Test)"); + PerformanceResult test14 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcallWithPorts.examples.experiment14.MethodCallThoughputTimestampAnalysis14Test)"); + PerformanceResult test15 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcallWithPorts.examples.experiment15.MethodCallThoughputTimestampAnalysis15Test)"); + PerformanceResult test16a = performanceResults + .get("testWithManyObjectsAnd1Thread(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + PerformanceResult test16b = performanceResults + .get("testWithManyObjectsAnd2Threads(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + PerformanceResult test16c = performanceResults + .get("testWithManyObjectsAnd4Threads(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + PerformanceResult test17 = performanceResults + .get("testWithManyObjects(teetime.variant.methodcallWithPorts.examples.experiment17.MethodCallThoughputTimestampAnalysis17Test)"); + PerformanceResult test19a = performanceResults + .get("testWithManyObjectsAnd1Thread(teetime.variant.methodcallWithPorts.examples.experiment19.MethodCallThoughputTimestampAnalysis19Test)"); + PerformanceResult test19b = performanceResults + .get("testWithManyObjectsAnd2Threads(teetime.variant.methodcallWithPorts.examples.experiment19.MethodCallThoughputTimestampAnalysis19Test)"); + PerformanceResult test19c = performanceResults + .get("testWithManyObjectsAnd4Threads(teetime.variant.methodcallWithPorts.examples.experiment19.MethodCallThoughputTimestampAnalysis19Test)"); + + assertEquals(60, (double) test14.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + assertEquals(14, (double) test10.quantiles.get(0.5) / test1.quantiles.get(0.5), 2.1); + assertEquals(32, (double) test11.quantiles.get(0.5) / test1.quantiles.get(0.5), 4.1); + assertEquals(22, (double) test9.quantiles.get(0.5) / test1.quantiles.get(0.5), 2.1); + assertEquals(44, (double) test15.quantiles.get(0.5) / test1.quantiles.get(0.5), 4.1); + + // below results vary too much + // assertEquals(RESULT_TESTS_16, (double) test16a.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + // assertEquals(RESULT_TESTS_16, (double) test16b.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + // assertEquals(RESULT_TESTS_16, (double) test16c.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + // + // assertEquals(RESULT_TESTS_19, (double) test19a.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + // assertEquals(RESULT_TESTS_19, (double) test19b.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + // assertEquals(RESULT_TESTS_19, (double) test19c.quantiles.get(0.5) / test1.quantiles.get(0.5), 5.1); + + assertEquals(39, (double) test17.quantiles.get(0.5) / test1.quantiles.get(0.5), 4.1); + + // check speedup + assertEquals(2, (double) test16a.overallDurationInNs / test16b.overallDurationInNs, 0.2); + assertEquals(2.5, (double) test16a.overallDurationInNs / test16c.overallDurationInNs, 0.2); + + assertEquals(2, (double) test19a.overallDurationInNs / test19b.overallDurationInNs, 0.2); + assertEquals(2.5, (double) test19a.overallDurationInNs / test19c.overallDurationInNs, 0.2); + } + +} diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment14/MethodCallThroughputAnalysis14.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment14/MethodCallThroughputAnalysis14.java index 69b48f87..215d0a37 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment14/MethodCallThroughputAnalysis14.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment14/MethodCallThroughputAnalysis14.java @@ -36,6 +36,8 @@ import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; */ public class MethodCallThroughputAnalysis14 extends Analysis { + private static final int SPSC_INITIAL_CAPACITY = 4; + private long numInputObjects; private ConstructorClosure<TimestampObject> inputObjectCreator; private int numNoopFilters; @@ -71,13 +73,13 @@ public class MethodCallThroughputAnalysis14 extends Analysis { pipeline.addIntermediateStage(stopTimestampFilter); pipeline.setLastStage(collectorSink); - SpScPipe.connect(objectProducer.getOutputPort(), startTimestampFilter.getInputPort()); - SpScPipe.connect(startTimestampFilter.getOutputPort(), noopFilters[0].getInputPort()); + SpScPipe.connect(objectProducer.getOutputPort(), startTimestampFilter.getInputPort(), SPSC_INITIAL_CAPACITY); + SpScPipe.connect(startTimestampFilter.getOutputPort(), noopFilters[0].getInputPort(), SPSC_INITIAL_CAPACITY); for (int i = 0; i < noopFilters.length - 1; i++) { - SpScPipe.connect(noopFilters[i].getOutputPort(), noopFilters[i + 1].getInputPort()); + SpScPipe.connect(noopFilters[i].getOutputPort(), noopFilters[i + 1].getInputPort(), SPSC_INITIAL_CAPACITY); } - SpScPipe.connect(noopFilters[noopFilters.length - 1].getOutputPort(), stopTimestampFilter.getInputPort()); - SpScPipe.connect(stopTimestampFilter.getOutputPort(), collectorSink.getInputPort()); + SpScPipe.connect(noopFilters[noopFilters.length - 1].getOutputPort(), stopTimestampFilter.getInputPort(), SPSC_INITIAL_CAPACITY); + SpScPipe.connect(stopTimestampFilter.getOutputPort(), collectorSink.getInputPort(), SPSC_INITIAL_CAPACITY); return new RunnableStage(pipeline); } diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment15/MethodCallThroughputAnalysis15.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment15/MethodCallThroughputAnalysis15.java index 9eed7af8..0ef9b18b 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment15/MethodCallThroughputAnalysis15.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment15/MethodCallThroughputAnalysis15.java @@ -40,6 +40,8 @@ import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; */ public class MethodCallThroughputAnalysis15 extends Analysis { + private static final int SPSC_INITIAL_CAPACITY = 4; + private int numInputObjects; private ConstructorClosure<TimestampObject> inputObjectCreator; private int numNoopFilters; @@ -95,7 +97,7 @@ public class MethodCallThroughputAnalysis15 extends Analysis { pipeline.addIntermediateStage(delay); pipeline.setLastStage(collectorSink); - SpScPipe.connect(clock.getOutputPort(), delay.getTimestampTriggerInputPort()); + SpScPipe.connect(clock.getOutputPort(), delay.getTimestampTriggerInputPort(), SPSC_INITIAL_CAPACITY); UnorderedGrowablePipe.connect(objectProducer.getOutputPort(), startTimestampFilter.getInputPort()); UnorderedGrowablePipe.connect(startTimestampFilter.getOutputPort(), noopFilters[0].getInputPort()); diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThoughputTimestampAnalysis16Test.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThoughputTimestampAnalysis16Test.java index da53b658..2da06889 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThoughputTimestampAnalysis16Test.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThoughputTimestampAnalysis16Test.java @@ -15,13 +15,12 @@ ***************************************************************************/ package teetime.variant.methodcallWithPorts.examples.experiment16; -import java.util.List; - +import org.junit.FixMethodOrder; import org.junit.Test; +import org.junit.runners.MethodSorters; import teetime.util.ConstructorClosure; import teetime.util.ListUtil; -import teetime.util.StatisticsUtil; import teetime.variant.explicitScheduling.examples.throughput.TimestampObject; import test.PerformanceTest; @@ -30,17 +29,40 @@ import test.PerformanceTest; * * @since 1.10 */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class MethodCallThoughputTimestampAnalysis16Test extends PerformanceTest { + // TODO use @Parameter for the number of threads + @Test public void testWithManyObjectsAnd1Thread() { - long durationWith1Thread = this.performAnalysis(1, -1); - this.performAnalysis(2, durationWith1Thread); - this.performAnalysis(4, durationWith1Thread); - // this.performAnalysis(8, stopWatch.getDurationInNs()); + this.performAnalysis(1); + } + + @Test + public void testWithManyObjectsAnd2Threads() { + this.performAnalysis(2); + } + + @Test + public void testWithManyObjectsAnd4Threads() { + this.performAnalysis(4); } - private long performAnalysis(final int numThreads, final long durationWith1Thread) { + // @AfterClass + // public static void afterClass() { + // PerformanceResult test16a = PerformanceTest.measurementRepository.performanceResults + // .get("testWithManyObjectsAnd1Thread(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + // PerformanceResult test16b = PerformanceTest.measurementRepository.performanceResults + // .get("testWithManyObjectsAnd2Threads(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + // PerformanceResult test16c = PerformanceTest.measurementRepository.performanceResults + // .get("testWithManyObjectsAnd4Threads(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + // // check speedup + // assertEquals(2, (double) test16a.overallDurationInNs / test16b.overallDurationInNs, 0.2); + // assertEquals(2.5, (double) test16a.overallDurationInNs / test16c.overallDurationInNs, 0.2); + // } + + private void performAnalysis(final int numThreads) { System.out.println("Testing teetime (mc) with NUM_OBJECTS_TO_CREATE=" + NUM_OBJECTS_TO_CREATE + ", NUM_NOOP_FILTERS=" + NUM_NOOP_FILTERS + "..."); @@ -63,22 +85,7 @@ public class MethodCallThoughputTimestampAnalysis16Test extends PerformanceTest analysis.onTerminate(); } - // TODO refactor test - - List<TimestampObject> timestampObjects = ListUtil.merge(analysis.getTimestampObjectsList()); - StatisticsUtil.printStatistics(this.stopWatch.getDurationInNs(), timestampObjects); - - if (durationWith1Thread != -1) { - double speedup = (double) durationWith1Thread / this.stopWatch.getDurationInNs(); - System.out.println("Speedup (from 1 to " + numThreads + " threads): " + String.format("%.2f", speedup)); - } - - return this.stopWatch.getDurationInNs(); + this.timestampObjects = ListUtil.merge(analysis.getTimestampObjectsList()); } - public static void main(final String[] args) { - MethodCallThoughputTimestampAnalysis16Test test = new MethodCallThoughputTimestampAnalysis16Test(); - test.before(); - test.testWithManyObjectsAnd1Thread(); - } } diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThroughputAnalysis16.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThroughputAnalysis16.java index 6343ff57..f6fa0e0a 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThroughputAnalysis16.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment16/MethodCallThroughputAnalysis16.java @@ -25,8 +25,8 @@ import teetime.variant.explicitScheduling.framework.core.Analysis; import teetime.variant.methodcallWithPorts.framework.core.Pipeline; import teetime.variant.methodcallWithPorts.framework.core.RunnableStage; import teetime.variant.methodcallWithPorts.framework.core.StageWithPort; +import teetime.variant.methodcallWithPorts.framework.core.pipe.SingleElementPipe; import teetime.variant.methodcallWithPorts.framework.core.pipe.SpScPipe; -import teetime.variant.methodcallWithPorts.framework.core.pipe.UnorderedGrowablePipe; import teetime.variant.methodcallWithPorts.stage.CollectorSink; import teetime.variant.methodcallWithPorts.stage.Distributor; import teetime.variant.methodcallWithPorts.stage.NoopFilter; @@ -42,6 +42,7 @@ import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; */ public class MethodCallThroughputAnalysis16 extends Analysis { + private static final int SPSC_INITIAL_CAPACITY = 100100; private static final int NUM_WORKER_THREADS = Runtime.getRuntime().availableProcessors(); private int numInputObjects; @@ -92,7 +93,7 @@ public class MethodCallThroughputAnalysis16 extends Analysis { pipeline.setFirstStage(objectProducer); pipeline.setLastStage(this.distributor); - UnorderedGrowablePipe.connect(objectProducer.getOutputPort(), this.distributor.getInputPort()); + SingleElementPipe.connect(objectProducer.getOutputPort(), this.distributor.getInputPort()); return pipeline; } @@ -120,16 +121,16 @@ public class MethodCallThroughputAnalysis16 extends Analysis { pipeline.addIntermediateStage(stopTimestampFilter); pipeline.setLastStage(collectorSink); - SpScPipe.connect(previousStage.getOutputPort(), relay.getInputPort()); + SpScPipe.connect(previousStage.getOutputPort(), relay.getInputPort(), SPSC_INITIAL_CAPACITY); - UnorderedGrowablePipe.connect(relay.getOutputPort(), startTimestampFilter.getInputPort()); + SingleElementPipe.connect(relay.getOutputPort(), startTimestampFilter.getInputPort()); - UnorderedGrowablePipe.connect(startTimestampFilter.getOutputPort(), noopFilters[0].getInputPort()); + SingleElementPipe.connect(startTimestampFilter.getOutputPort(), noopFilters[0].getInputPort()); for (int i = 0; i < noopFilters.length - 1; i++) { - UnorderedGrowablePipe.connect(noopFilters[i].getOutputPort(), noopFilters[i + 1].getInputPort()); + SingleElementPipe.connect(noopFilters[i].getOutputPort(), noopFilters[i + 1].getInputPort()); } - UnorderedGrowablePipe.connect(noopFilters[noopFilters.length - 1].getOutputPort(), stopTimestampFilter.getInputPort()); - UnorderedGrowablePipe.connect(stopTimestampFilter.getOutputPort(), collectorSink.getInputPort()); + SingleElementPipe.connect(noopFilters[noopFilters.length - 1].getOutputPort(), stopTimestampFilter.getInputPort()); + SingleElementPipe.connect(stopTimestampFilter.getOutputPort(), collectorSink.getInputPort()); return new RunnableStage(pipeline); } diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThoughputTimestampAnalysis17Test.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThoughputTimestampAnalysis17Test.java index a861ed38..869f09b9 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThoughputTimestampAnalysis17Test.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThoughputTimestampAnalysis17Test.java @@ -15,13 +15,10 @@ ***************************************************************************/ package teetime.variant.methodcallWithPorts.examples.experiment17; -import java.util.List; - import org.junit.Test; import teetime.util.ConstructorClosure; import teetime.util.ListUtil; -import teetime.util.StatisticsUtil; import teetime.variant.explicitScheduling.examples.throughput.TimestampObject; import test.PerformanceTest; @@ -58,10 +55,7 @@ public class MethodCallThoughputTimestampAnalysis17Test extends PerformanceTest analysis.onTerminate(); } - // TODO refactor test - - List<TimestampObject> timestampObjects = ListUtil.merge(analysis.getTimestampObjectsList()); - StatisticsUtil.printStatistics(this.stopWatch.getDurationInNs(), timestampObjects); + this.timestampObjects = ListUtil.merge(analysis.getTimestampObjectsList()); // } } } diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThroughputAnalysis17.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThroughputAnalysis17.java index 4a6a81e0..5bcfadf9 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThroughputAnalysis17.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment17/MethodCallThroughputAnalysis17.java @@ -45,6 +45,7 @@ import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; */ public class MethodCallThroughputAnalysis17 extends Analysis { + private static final int SPSC_INITIAL_CAPACITY = 100100; private static final int NUM_WORKER_THREADS = Runtime.getRuntime().availableProcessors(); private int numInputObjects; @@ -153,7 +154,7 @@ public class MethodCallThroughputAnalysis17 extends Analysis { pipeline.addIntermediateStage(stopTimestampFilter); pipeline.setLastStage(collectorSink); - IPipe<TimestampObject> startPipe = new SpScPipe<TimestampObject>(); + IPipe<TimestampObject> startPipe = new SpScPipe<TimestampObject>(SPSC_INITIAL_CAPACITY); try { for (int i = 0; i < this.numInputObjects; i++) { startPipe.add(this.inputObjectCreator.create()); diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment18/MethodCallThroughputAnalysis18.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment18/MethodCallThroughputAnalysis18.java index fb001557..931edb9c 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment18/MethodCallThroughputAnalysis18.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment18/MethodCallThroughputAnalysis18.java @@ -42,6 +42,7 @@ import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; */ public class MethodCallThroughputAnalysis18 extends Analysis { + private static final int SPSC_INITIAL_CAPACITY = 4; private static final int NUM_WORKER_THREADS = Runtime.getRuntime().availableProcessors(); private int numInputObjects; @@ -111,7 +112,7 @@ public class MethodCallThroughputAnalysis18 extends Analysis { pipeline.addIntermediateStage(stopTimestampFilter); pipeline.setLastStage(collectorSink); - SpScPipe.connect(previousStage.getOutputPort(), relay.getInputPort()); + SpScPipe.connect(previousStage.getOutputPort(), relay.getInputPort(), SPSC_INITIAL_CAPACITY); UnorderedGrowablePipe.connect(relay.getOutputPort(), startTimestampFilter.getInputPort()); diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThoughputTimestampAnalysis19Test.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThoughputTimestampAnalysis19Test.java new file mode 100644 index 00000000..25f19d8a --- /dev/null +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThoughputTimestampAnalysis19Test.java @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright 2014 Kieker Project (http://kieker-monitoring.net) + * + * Licensed 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 teetime.variant.methodcallWithPorts.examples.experiment19; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import teetime.util.ConstructorClosure; +import teetime.util.ListUtil; +import teetime.variant.explicitScheduling.examples.throughput.TimestampObject; +import test.PerformanceTest; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class MethodCallThoughputTimestampAnalysis19Test extends PerformanceTest { + + // TODO use @Parameter for the number of threads + + @Test + public void testWithManyObjectsAnd1Thread() { + this.performAnalysis(1); + } + + @Test + public void testWithManyObjectsAnd2Threads() { + this.performAnalysis(2); + } + + @Test + public void testWithManyObjectsAnd4Threads() { + this.performAnalysis(4); + } + + // @AfterClass + // public static void afterClass() { + // PerformanceResult test16a = PerformanceTest.measurementRepository.performanceResults + // .get("testWithManyObjectsAnd1Thread(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + // PerformanceResult test16b = PerformanceTest.measurementRepository.performanceResults + // .get("testWithManyObjectsAnd2Threads(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + // PerformanceResult test16c = PerformanceTest.measurementRepository.performanceResults + // .get("testWithManyObjectsAnd4Threads(teetime.variant.methodcallWithPorts.examples.experiment16.MethodCallThoughputTimestampAnalysis16Test)"); + // // check speedup + // assertEquals(2, (double) test16a.overallDurationInNs / test16b.overallDurationInNs, 0.2); + // assertEquals(2.5, (double) test16a.overallDurationInNs / test16c.overallDurationInNs, 0.2); + // } + + private void performAnalysis(final int numThreads) { + System.out.println("Testing teetime (mc) with NUM_OBJECTS_TO_CREATE=" + NUM_OBJECTS_TO_CREATE + ", NUM_NOOP_FILTERS=" + + NUM_NOOP_FILTERS + "..."); + + final MethodCallThroughputAnalysis19 analysis = new MethodCallThroughputAnalysis19(); + analysis.setNumWorkerThreads(numThreads); + analysis.setNumNoopFilters(NUM_NOOP_FILTERS); + analysis.setInput(NUM_OBJECTS_TO_CREATE, new ConstructorClosure<TimestampObject>() { + @Override + public TimestampObject create() { + return new TimestampObject(); + } + }); + analysis.init(); + + this.stopWatch.start(); + try { + analysis.start(); + } finally { + this.stopWatch.end(); + analysis.onTerminate(); + } + + this.timestampObjects = ListUtil.merge(analysis.getTimestampObjectsList()); + } + +} diff --git a/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThroughputAnalysis19.java b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThroughputAnalysis19.java new file mode 100644 index 00000000..bcc6a8f3 --- /dev/null +++ b/src/test/java/teetime/variant/methodcallWithPorts/examples/experiment19/MethodCallThroughputAnalysis19.java @@ -0,0 +1,182 @@ +/*************************************************************************** + * Copyright 2014 Kieker Project (http://kieker-monitoring.net) + * + * Licensed 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 teetime.variant.methodcallWithPorts.examples.experiment19; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import teetime.util.ConstructorClosure; +import teetime.variant.explicitScheduling.examples.throughput.TimestampObject; +import teetime.variant.explicitScheduling.framework.core.Analysis; +import teetime.variant.methodcallWithPorts.framework.core.Pipeline; +import teetime.variant.methodcallWithPorts.framework.core.RunnableStage; +import teetime.variant.methodcallWithPorts.framework.core.StageWithPort; +import teetime.variant.methodcallWithPorts.framework.core.pipe.OrderedGrowableArrayPipe; +import teetime.variant.methodcallWithPorts.framework.core.pipe.SpScPipe; +import teetime.variant.methodcallWithPorts.stage.CollectorSink; +import teetime.variant.methodcallWithPorts.stage.Distributor; +import teetime.variant.methodcallWithPorts.stage.NoopFilter; +import teetime.variant.methodcallWithPorts.stage.ObjectProducer; +import teetime.variant.methodcallWithPorts.stage.Relay; +import teetime.variant.methodcallWithPorts.stage.StartTimestampFilter; +import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThroughputAnalysis19 extends Analysis { + + private static final int SPSC_INITIAL_CAPACITY = 100100; + private static final int NUM_WORKER_THREADS = Runtime.getRuntime().availableProcessors(); + + private int numInputObjects; + private ConstructorClosure<TimestampObject> inputObjectCreator; + private int numNoopFilters; + + private final List<List<TimestampObject>> timestampObjectsList = new LinkedList<List<TimestampObject>>(); + + private Distributor<TimestampObject> distributor; + private Thread producerThread; + + private Thread[] workerThreads; + + private int numWorkerThreads; + + @Override + public void init() { + super.init(); + Pipeline<Void, TimestampObject> producerPipeline = this.buildProducerPipeline(this.numInputObjects, this.inputObjectCreator); + this.producerThread = new Thread(new RunnableStage(producerPipeline)); + + this.numWorkerThreads = Math.min(NUM_WORKER_THREADS, this.numWorkerThreads); + + this.workerThreads = new Thread[this.numWorkerThreads]; + for (int i = 0; i < this.workerThreads.length; i++) { + List<TimestampObject> resultList = new ArrayList<TimestampObject>(this.numInputObjects); + this.timestampObjectsList.add(resultList); + + Runnable workerRunnable = this.buildPipeline(producerPipeline, resultList); + this.workerThreads[i] = new Thread(workerRunnable); + } + + } + + private Pipeline<Void, TimestampObject> buildProducerPipeline(final int numInputObjects, final ConstructorClosure<TimestampObject> inputObjectCreator) { + final ObjectProducer<TimestampObject> objectProducer = new ObjectProducer<TimestampObject>(numInputObjects, inputObjectCreator); + this.distributor = new Distributor<TimestampObject>(); + + final Pipeline<Void, TimestampObject> pipeline = new Pipeline<Void, TimestampObject>(); + pipeline.setFirstStage(objectProducer); + pipeline.setLastStage(this.distributor); + + OrderedGrowableArrayPipe.connect(objectProducer.getOutputPort(), this.distributor.getInputPort()); + + return pipeline; + } + + /** + * @param numNoopFilters + * @since 1.10 + */ + private Runnable buildPipeline(final StageWithPort<Void, TimestampObject> previousStage, final List<TimestampObject> timestampObjects) { + Relay<TimestampObject> relay = new Relay<TimestampObject>(); + @SuppressWarnings("unchecked") + final NoopFilter<TimestampObject>[] noopFilters = new NoopFilter[this.numNoopFilters]; + // create stages + final StartTimestampFilter startTimestampFilter = new StartTimestampFilter(); + for (int i = 0; i < noopFilters.length; i++) { + noopFilters[i] = new NoopFilter<TimestampObject>(); + } + final StopTimestampFilter stopTimestampFilter = new StopTimestampFilter(); + final CollectorSink<TimestampObject> collectorSink = new CollectorSink<TimestampObject>(timestampObjects); + + final Pipeline<TimestampObject, Object> pipeline = new Pipeline<TimestampObject, Object>(); + pipeline.setFirstStage(relay); + pipeline.addIntermediateStage(startTimestampFilter); + pipeline.addIntermediateStages(noopFilters); + pipeline.addIntermediateStage(stopTimestampFilter); + pipeline.setLastStage(collectorSink); + + SpScPipe.connect(previousStage.getOutputPort(), relay.getInputPort(), SPSC_INITIAL_CAPACITY); + + OrderedGrowableArrayPipe.connect(relay.getOutputPort(), startTimestampFilter.getInputPort()); + + OrderedGrowableArrayPipe.connect(startTimestampFilter.getOutputPort(), noopFilters[0].getInputPort()); + for (int i = 0; i < noopFilters.length - 1; i++) { + OrderedGrowableArrayPipe.connect(noopFilters[i].getOutputPort(), noopFilters[i + 1].getInputPort()); + } + OrderedGrowableArrayPipe.connect(noopFilters[noopFilters.length - 1].getOutputPort(), stopTimestampFilter.getInputPort()); + OrderedGrowableArrayPipe.connect(stopTimestampFilter.getOutputPort(), collectorSink.getInputPort()); + + return new RunnableStage(pipeline); + } + + @Override + public void start() { + super.start(); + + this.producerThread.start(); + + for (Thread workerThread : this.workerThreads) { + workerThread.start(); + } + + try { + this.producerThread.join(); + } catch (InterruptedException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + try { + for (Thread workerThread : this.workerThreads) { + workerThread.join(); + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void setInput(final int numInputObjects, final ConstructorClosure<TimestampObject> inputObjectCreator) { + this.numInputObjects = numInputObjects; + this.inputObjectCreator = inputObjectCreator; + } + + public int getNumNoopFilters() { + return this.numNoopFilters; + } + + public void setNumNoopFilters(final int numNoopFilters) { + this.numNoopFilters = numNoopFilters; + } + + public List<List<TimestampObject>> getTimestampObjectsList() { + return this.timestampObjectsList; + } + + public int getNumWorkerThreads() { + return this.numWorkerThreads; + } + + public void setNumWorkerThreads(final int numWorkerThreads) { + this.numWorkerThreads = numWorkerThreads; + } + +} diff --git a/src/test/java/test/PerformanceResult.java b/src/test/java/test/PerformanceResult.java index 34f94507..e950ea40 100644 --- a/src/test/java/test/PerformanceResult.java +++ b/src/test/java/test/PerformanceResult.java @@ -6,6 +6,7 @@ import teetime.util.StatisticsUtil; public class PerformanceResult { + public long overallDurationInNs; public long sumInNs; public Map<Double, Long> quantiles; public long avgDurInNs; @@ -14,6 +15,10 @@ public class PerformanceResult { @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("overallDurationInNs: "); + stringBuilder.append(this.overallDurationInNs); + stringBuilder.append("\n"); + stringBuilder.append("sumInNs: "); stringBuilder.append(this.sumInNs); stringBuilder.append("\n"); -- GitLab