diff --git a/src/main/java/teetime/util/StatisticsUtil.java b/src/main/java/teetime/util/StatisticsUtil.java
index 4708e96f30ea0e13cb2458c141220a77da0ee1ff..38788e19740fc8bc83118af4a631152615459b10 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 26c8a884e64b7f641f543b25c6b1af8cdaa07c59..109824ffda5e28b4c4c287b29b1e1aa41c7495a4 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 54869f0f5f87ddef489d44244976ef4c4ef88cda..ece1f1d074beb50afa9c07048043b854ffc3379e 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 0000000000000000000000000000000000000000..9466ae3b966523f8e7516e4df5e0e1be87ad8011
--- /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 69b48f8792575d5f83f4be76e9153735e44d3871..215d0a373c86e811e7eca12bfde171325b96c067 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 9eed7af8c1fa66205bb6df385e523f1fc91fdbd3..0ef9b18b8e687e12b2f693c3afbbe11780baed34 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 da53b65840e5548aa47bd36f4d6948a7d8c70042..2da0688944ebb5dbbc8bd2409ea784b8c29deb2b 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 6343ff5769b91f3aaf7917bf1f6f65b0fa7e5052..f6fa0e0a4b56667dce0b0ec405757094d3931c1a 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 a861ed382dbb652ef6b39d65ba2deca351f2176c..869f09b96f25a704a670e7ba40ea324fec7343b5 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 4a6a81e07c18f3efd6d646f376b8d78eea0aa301..5bcfadf9c8c18fe79d6dc1d2c91d4645e5c4479d 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 fb0015574b86a0cba6520defdd051d92e67ca902..931edb9c10030f011683a33833d052b856e0863f 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 0000000000000000000000000000000000000000..25f19d8ab4d1bd7fc400c09520e3586cc1d2bb81
--- /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 0000000000000000000000000000000000000000..bcc6a8f34d77d0742fad67ae3dac68e9f1d2fd8d
--- /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 34f94507a6193ba09712b6285800a8f64cb926d6..e950ea40c759cff850541315a5ef6a8090d763c7 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");