From 4ce74fdb8402135dd8e31077327b7974bc3d62ed Mon Sep 17 00:00:00 2001 From: Christian Wulf <chw@informatik.uni-kiel.de> Date: Sat, 14 Jun 2014 17:00:34 +0200 Subject: [PATCH] added performance test for method call with pipe --- ...odCallThoughputTimestampAnalysis2Test.java | 77 ++++++++++++ .../throughput/methodcall/AbstractStage.java | 48 ++++++++ .../throughput/methodcall/CollectorSink.java | 12 +- .../throughput/methodcall/InputPort.java | 16 +++ .../MethodCallThroughputAnalysis2.java | 110 ++++++++++++++++++ .../throughput/methodcall/NoopFilter.java | 8 +- .../throughput/methodcall/ObjectProducer.java | 24 +++- .../throughput/methodcall/OutputPort.java | 10 ++ .../examples/throughput/methodcall/Pipe.java | 27 +++++ .../throughput/methodcall/Pipeline.java | 71 +++++++++++ .../examples/throughput/methodcall/Stage.java | 12 ++ .../methodcall/StartTimestampFilter.java | 11 +- .../methodcall/StopTimestampFilter.java | 11 +- 13 files changed, 429 insertions(+), 8 deletions(-) create mode 100644 src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis2Test.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/AbstractStage.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/InputPort.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis2.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/OutputPort.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/Pipe.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/Pipeline.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/Stage.java diff --git a/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis2Test.java b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis2Test.java new file mode 100644 index 00000000..07086663 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis2Test.java @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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.examples.throughput; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import org.junit.Before; +import org.junit.Test; + +import teetime.examples.throughput.methodcall.MethodCallThroughputAnalysis2; +import teetime.util.StatisticsUtil; +import teetime.util.StopWatch; + +import kieker.common.logging.LogFactory; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThoughputTimestampAnalysis2Test { + + private static final int NUM_OBJECTS_TO_CREATE = 100000; + private static final int NUM_NOOP_FILTERS = 800; + + @Before + public void before() { + System.setProperty(LogFactory.CUSTOM_LOGGER_JVM, "NONE"); + } + + // 500 times faster than our new framework + // TODO check why + + @Test + public void testWithManyObjects() { + System.out.println("Testing teetime (mc) with NUM_OBJECTS_TO_CREATE=" + NUM_OBJECTS_TO_CREATE + ", NUM_NOOP_FILTERS=" + + NUM_NOOP_FILTERS + "..."); + final StopWatch stopWatch = new StopWatch(); + final List<TimestampObject> timestampObjects = new ArrayList<TimestampObject>(NUM_OBJECTS_TO_CREATE); + + final MethodCallThroughputAnalysis2 analysis = new MethodCallThroughputAnalysis2(); + analysis.setNumNoopFilters(NUM_NOOP_FILTERS); + analysis.setTimestampObjects(timestampObjects); + analysis.setInput(NUM_OBJECTS_TO_CREATE, new Callable<TimestampObject>() { + @Override + public TimestampObject call() throws Exception { + return new TimestampObject(); + } + }); + analysis.init(); + + stopWatch.start(); + try { + analysis.start(); + } finally { + stopWatch.end(); + } + + StatisticsUtil.printStatistics(stopWatch.getDurationInNs(), timestampObjects); + } + +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/AbstractStage.java b/src/test/java/teetime/examples/throughput/methodcall/AbstractStage.java new file mode 100644 index 00000000..9b8712eb --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/AbstractStage.java @@ -0,0 +1,48 @@ +package teetime.examples.throughput.methodcall; + +public abstract class AbstractStage<I, O> implements Stage<I, O> { + + Runnable inputPortIsUsed = new Runnable() { + @Override + public void run() { + // pass through the end signal + I element = AbstractStage.this.getInputPort().read(); + if (element == END_SIGNAL) { + AbstractStage.this.getOutputPort().send((O) END_SIGNAL); + return; + } + + AbstractStage.this.execute3(); + } + }; + + Runnable inputPortIsNotUsed = new Runnable() { + @Override + public void run() { + // do not check + + AbstractStage.this.execute3(); + } + }; + + private final InputPort<I> inputPort = new InputPort<I>(); + private final OutputPort<O> outputPort = new OutputPort<O>(); + protected Runnable endSignalCheck = this.inputPortIsUsed; + + @Override + public InputPort<I> getInputPort() { + return this.inputPort; + } + + @Override + public OutputPort<O> getOutputPort() { + return this.outputPort; + } + + @Override + public final void execute2() { + this.endSignalCheck.run(); + } + + protected abstract void execute3(); +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java b/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java index f88aefec..dcca4f35 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java +++ b/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java @@ -22,7 +22,7 @@ import java.util.List; * * @since 1.10 */ -public class CollectorSink<T> { +public class CollectorSink<T> extends AbstractStage<T, T> { private static final int THRESHOLD = 10000; @@ -41,4 +41,14 @@ public class CollectorSink<T> { System.out.println("size: " + this.elements.size()); } } + + @Override + public void execute3() { + T element = this.getInputPort().receive(); + + this.elements.add(element); + if ((this.elements.size() % THRESHOLD) == 0) { + System.out.println("size: " + this.elements.size()); + } + } } diff --git a/src/test/java/teetime/examples/throughput/methodcall/InputPort.java b/src/test/java/teetime/examples/throughput/methodcall/InputPort.java new file mode 100644 index 00000000..6f93eb3e --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/InputPort.java @@ -0,0 +1,16 @@ +package teetime.examples.throughput.methodcall; + +public class InputPort<T> { + + public Pipe<T> pipe; + + public T receive() { + T element = this.pipe.removeLast(); + return element; + } + + public T read() { + T element = this.pipe.readLast(); + return element; + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis2.java b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis2.java new file mode 100644 index 00000000..fd5794ec --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis2.java @@ -0,0 +1,110 @@ +/*************************************************************************** + * 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.examples.throughput.methodcall; + +import java.util.List; +import java.util.concurrent.Callable; + +import teetime.examples.throughput.TimestampObject; +import teetime.framework.core.Analysis; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThroughputAnalysis2 extends Analysis { + + private long numInputObjects; + private Callable<TimestampObject> inputObjectCreator; + private int numNoopFilters; + private List<TimestampObject> timestampObjects; + private Runnable runnable; + + @Override + public void init() { + super.init(); + this.runnable = this.buildPipeline(); + } + + /** + * @param numNoopFilters + * @since 1.10 + */ + private Runnable buildPipeline() { + @SuppressWarnings("unchecked") + final NoopFilter<TimestampObject>[] noopFilters = new NoopFilter[this.numNoopFilters]; + // create stages + final ObjectProducer<TimestampObject> objectProducer = new ObjectProducer<TimestampObject>(this.numInputObjects, this.inputObjectCreator); + 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>(this.timestampObjects); + + final Pipeline pipeline = new Pipeline(); + pipeline.setFirstStage(objectProducer); + pipeline.addIntermediateStage(startTimestampFilter); + pipeline.addIntermediateStages(noopFilters); + pipeline.addIntermediateStage(stopTimestampFilter); + pipeline.setLastStage(collectorSink); + + // pipeline.getInputPort().pipe = new Pipe<Void>(); + // pipeline.getInputPort().pipe.add(new Object()); + + pipeline.getOutputPort().pipe = new Pipe<Void>(); + + final Runnable runnable = new Runnable() { + @Override + public void run() { + pipeline.onStart(); + while (!(pipeline.getOutputPort().pipe.readLast() == Stage.END_SIGNAL)) { + pipeline.execute2(); + } + } + }; + + return runnable; + } + + @Override + public void start() { + super.start(); + this.runnable.run(); + } + + public void setInput(final int numInputObjects, final Callable<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<TimestampObject> getTimestampObjects() { + return this.timestampObjects; + } + + public void setTimestampObjects(final List<TimestampObject> timestampObjects) { + this.timestampObjects = timestampObjects; + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/NoopFilter.java b/src/test/java/teetime/examples/throughput/methodcall/NoopFilter.java index 647a3885..db6d09b8 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/NoopFilter.java +++ b/src/test/java/teetime/examples/throughput/methodcall/NoopFilter.java @@ -20,9 +20,15 @@ package teetime.examples.throughput.methodcall; * * @since 1.10 */ -public class NoopFilter<T> { +public class NoopFilter<T> extends AbstractStage<T, T> { public T execute(final T obj) { return obj; } + + @Override + public void execute3() { + T element = this.getInputPort().receive(); + this.getOutputPort().send(element); + } } diff --git a/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java b/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java index eebed235..bcb19d0f 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java +++ b/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java @@ -22,7 +22,7 @@ import java.util.concurrent.Callable; * * @since 1.10 */ -public class ObjectProducer<T> { +public class ObjectProducer<T> extends AbstractStage<Void, T> { private long numInputObjects; private Callable<T> inputObjectCreator; @@ -33,6 +33,8 @@ public class ObjectProducer<T> { public ObjectProducer(final long numInputObjects, final Callable<T> inputObjectCreator) { this.numInputObjects = numInputObjects; this.inputObjectCreator = inputObjectCreator; + + this.endSignalCheck = this.inputPortIsNotUsed; } public T execute() { @@ -46,7 +48,7 @@ public class ObjectProducer<T> { return newObject; } catch (final Exception e) { - throw new IllegalStateException(); + throw new IllegalStateException(e); } } @@ -65,4 +67,22 @@ public class ObjectProducer<T> { public void setInputObjectCreator(final Callable<T> inputObjectCreator) { this.inputObjectCreator = inputObjectCreator; } + + @Override + protected void execute3() { + if (this.numInputObjects == 0) { + this.getOutputPort().send((T) END_SIGNAL); + return; + } + + try { + final T newObject = this.inputObjectCreator.call(); + this.numInputObjects--; + + this.getOutputPort().send(newObject); + } catch (final Exception e) { + throw new IllegalStateException(e); + } + } + } diff --git a/src/test/java/teetime/examples/throughput/methodcall/OutputPort.java b/src/test/java/teetime/examples/throughput/methodcall/OutputPort.java new file mode 100644 index 00000000..41c4b0d2 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/OutputPort.java @@ -0,0 +1,10 @@ +package teetime.examples.throughput.methodcall; + +public class OutputPort<T> { + + public Pipe<T> pipe; + + public void send(final T element) { + this.pipe.add(element); + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/Pipe.java b/src/test/java/teetime/examples/throughput/methodcall/Pipe.java new file mode 100644 index 00000000..0ce187c7 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/Pipe.java @@ -0,0 +1,27 @@ +package teetime.examples.throughput.methodcall; + +import teetime.util.list.CommittableResizableArrayQueue; + +public class Pipe<T> { + + private final CommittableResizableArrayQueue<T> elements = new CommittableResizableArrayQueue<T>(null, 4); + + public void add(final T element) { + this.elements.addToTailUncommitted(element); + this.elements.commit(); + } + + public T removeLast() { + T element = this.elements.removeFromHeadUncommitted(); + this.elements.commit(); + return element; + } + + public boolean isEmpty() { + return this.elements.isEmpty(); + } + + public T readLast() { + return this.elements.getTail(); + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/Pipeline.java b/src/test/java/teetime/examples/throughput/methodcall/Pipeline.java new file mode 100644 index 00000000..3a1df2f0 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/Pipeline.java @@ -0,0 +1,71 @@ +package teetime.examples.throughput.methodcall; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +public class Pipeline implements Stage { + + private Stage firstStage; + private final List<Stage> intermediateStages = new LinkedList<Stage>(); + private Stage lastStage; + + void setFirstStage(final Stage stage) { + this.firstStage = stage; + } + + void addIntermediateStages(final Stage... stages) { + this.intermediateStages.addAll(Arrays.asList(stages)); + } + + void addIntermediateStage(final Stage stage) { + this.intermediateStages.add(stage); + } + + void setLastStage(final Stage stage) { + this.lastStage = stage; + } + + @Override + public void execute2() { + this.firstStage.execute2(); + for (Stage<?, ?> stage : this.intermediateStages) { + stage.execute2(); + } + this.lastStage.execute2(); + } + + void onStart() { + // Pipe pipe = new Pipe(); + // this.outputPort.pipe = pipe; + // this.firstStage.getInputPort().pipe = pipe; + + Pipe pipe = new Pipe(); + this.firstStage.getOutputPort().pipe = pipe; + this.intermediateStages.get(0).getInputPort().pipe = pipe; + + for (int i = 0; i < this.intermediateStages.size() - 1; i++) { + Stage left = this.intermediateStages.get(i); + Stage right = this.intermediateStages.get(i + 1); + + pipe = new Pipe(); + left.getOutputPort().pipe = pipe; + right.getInputPort().pipe = pipe; + } + + pipe = new Pipe(); + this.intermediateStages.get(this.intermediateStages.size() - 1).getOutputPort().pipe = pipe; + this.lastStage.getInputPort().pipe = pipe; + } + + @Override + public InputPort getInputPort() { + return this.firstStage.getInputPort(); + } + + @Override + public OutputPort getOutputPort() { + return this.lastStage.getOutputPort(); + } + +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/Stage.java b/src/test/java/teetime/examples/throughput/methodcall/Stage.java new file mode 100644 index 00000000..d5d604c8 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/Stage.java @@ -0,0 +1,12 @@ +package teetime.examples.throughput.methodcall; + +public interface Stage<I, O> { + + public static final Object END_SIGNAL = new Object(); + + void execute2(); + + InputPort<I> getInputPort(); + + OutputPort<O> getOutputPort(); +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java b/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java index 6087b710..afa6721b 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java +++ b/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java @@ -19,13 +19,20 @@ import teetime.examples.throughput.TimestampObject; /** * @author Christian Wulf - * + * * @since 1.10 */ -public class StartTimestampFilter { +public class StartTimestampFilter extends AbstractStage<TimestampObject, TimestampObject> { public TimestampObject execute(final TimestampObject obj) { obj.setStartTimestamp(System.nanoTime()); return obj; } + + @Override + public void execute3() { + TimestampObject element = this.getInputPort().receive(); + element.setStartTimestamp(System.nanoTime()); + this.getOutputPort().send(element); + } } diff --git a/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java b/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java index d6ddc9e2..e7919047 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java +++ b/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java @@ -19,13 +19,20 @@ import teetime.examples.throughput.TimestampObject; /** * @author Christian Wulf - * + * * @since 1.10 */ -public class StopTimestampFilter { +public class StopTimestampFilter extends AbstractStage<TimestampObject, TimestampObject> { public TimestampObject execute(final TimestampObject obj) { obj.setStopTimestamp(System.nanoTime()); return obj; } + + @Override + public void execute3() { + TimestampObject element = this.getInputPort().receive(); + element.setStopTimestamp(System.nanoTime()); + this.getOutputPort().send(element); + } } -- GitLab