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 0000000000000000000000000000000000000000..07086663bc62a4d2fd9792d883e6f2e086df0506 --- /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 0000000000000000000000000000000000000000..9b8712eb3822ff803cfea3801f8826cd00343ace --- /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 f88aefeccb75c6225744a7156ea9c72e66291021..dcca4f35b0eb783f41709f0361eb55c9bb97e1c4 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 0000000000000000000000000000000000000000..6f93eb3e710e698d1da005fc6d7a8c5f2d85596b --- /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 0000000000000000000000000000000000000000..fd5794ec580cd941f318af8ccda03444d991cf6a --- /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 647a3885936b8b9cb9be1254e3ca3dbbdb186d5d..db6d09b870a833e38ac916d13f3e8f574fb4a191 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 eebed2354f5146f4a51cf069f96236e8485f458b..bcb19d0fdfd8e5f791a1f220ea157faad70e1745 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 0000000000000000000000000000000000000000..41c4b0d2d600ccefe81385ec6181fc65e69f2cd2 --- /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 0000000000000000000000000000000000000000..0ce187c77c2d10d5bc396b5dec6fa34dabb7aa4b --- /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 0000000000000000000000000000000000000000..3a1df2f0795f7fbeed8c546614b719c920442d88 --- /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 0000000000000000000000000000000000000000..d5d604c8c37143833f205c047a42d9e067fbc983 --- /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 6087b7109f7181f3ef19843731c95b356763b03a..afa6721b101ea2df38fd31d58008cb80f2533e0f 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 d6ddc9e2de94491060cb2be5212db9a0ae69beae..e791904744367feb970b3c84f5f06b754d5a7fdb 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); + } }