diff --git a/results/overhead-findings.txt b/results/overhead-findings.txt index 64e7d3a4bcceb21b75f79b7faeb5a4ec6f7fc3ff..f649f1f52ec49320d89c26179863b1afa0fea5f9 100644 --- a/results/overhead-findings.txt +++ b/results/overhead-findings.txt @@ -8,13 +8,16 @@ [irrelevant w.r.t. overhead] -foreach vs. index-based iteration -iterative vs. recursive execution +-null-check vs. NullObject - [analysis performance results (50%)] 2: 7400 ns -9: 9400 ns +8: 1200 ns (iterative; argument/return w/o pipe) +9: 9400 ns (queued pipe) 10: 4900 ns (single element pipe) 11: 7400 ns (fixed sized pipe) - \ No newline at end of file +12: 3300 ns (recursive; argument/return w/o pipe) +13: 3300 ns (recursive; argument/return w/o pipe; w/o pipeline class) diff --git a/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis12Test.java b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis12Test.java new file mode 100644 index 0000000000000000000000000000000000000000..fb060993ce0fe1f58c76b0b8222289d23010fc6c --- /dev/null +++ b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis12Test.java @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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.MethodCallThroughputAnalysis12; +import teetime.util.StatisticsUtil; +import teetime.util.StopWatch; + +import kieker.common.logging.LogFactory; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThoughputTimestampAnalysis12Test { + + 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"); + } + + @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 MethodCallThroughputAnalysis12 analysis = new MethodCallThroughputAnalysis12(); + 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/MethodCallThoughputTimestampAnalysis13Test.java b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis13Test.java new file mode 100644 index 0000000000000000000000000000000000000000..fe1aaf136cb79ecba79e1be4d616bd6d8fd72319 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysis13Test.java @@ -0,0 +1,74 @@ +/*************************************************************************** + * 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.MethodCallThroughputAnalysis13; +import teetime.util.StatisticsUtil; +import teetime.util.StopWatch; + +import kieker.common.logging.LogFactory; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThoughputTimestampAnalysis13Test { + + 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"); + } + + @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 MethodCallThroughputAnalysis13 analysis = new MethodCallThroughputAnalysis13(); + 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 index 03e99132e345709eb0e8402a1a24d31cd830280a..c615ba1c9d6a397b2b6b70a1b57ffbe377970eba 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/AbstractStage.java +++ b/src/test/java/teetime/examples/throughput/methodcall/AbstractStage.java @@ -22,6 +22,21 @@ abstract class AbstractStage<I, O> implements StageWithPort<I, O> { private boolean reschedulable; + @Override + public Object executeRecursively(final Object element) { + O result = this.execute(element); + if (result == null) { + return null; + } + StageWithPort next = this.next(); + // if (next != null) { + // return next.executeRecursively(result); + // } else { + // return result; + // } + return next.executeRecursively(result); + } + @Override public InputPort<I> getInputPort() { return this.inputPort; @@ -57,6 +72,16 @@ abstract class AbstractStage<I, O> implements StageWithPort<I, O> { return this.outputElements; } + // @Override + // public void executeWithPorts() { + // CommittableQueue execute; + // do { + // // execute = this.next().execute2(this.outputElements); + // // execute = this.next().execute2(this.getOutputPort().pipe.getElements()); + // this.next().executeWithPorts(); + // } while (this.next().isReschedulable()); + // } + protected abstract void execute4(CommittableQueue<I> elements); protected abstract void execute5(I element); diff --git a/src/test/java/teetime/examples/throughput/methodcall/ConsumerStage.java b/src/test/java/teetime/examples/throughput/methodcall/ConsumerStage.java index 7429195aeff26287ccc9894493a3c3fc160d0391..ffd3c99e82001cd00b4184a97c8b8c50000bb46c 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/ConsumerStage.java +++ b/src/test/java/teetime/examples/throughput/methodcall/ConsumerStage.java @@ -22,6 +22,12 @@ public abstract class ConsumerStage<I, O> extends AbstractStage<I, O> { public void executeWithPorts() { I element = this.getInputPort().receive(); this.execute5(element); + + // this.setReschedulable(!this.getOutputPort().pipe.isEmpty()); + + // if (!this.getOutputPort().pipe.isEmpty()) { + // super.executeWithPorts(); + // } } } diff --git a/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis12.java b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis12.java new file mode 100644 index 0000000000000000000000000000000000000000..afa57c29494c448fec7c6b0dc410a4f065d8567b --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis12.java @@ -0,0 +1,113 @@ +/*************************************************************************** + * 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.examples.throughput.methodcall.stage.CollectorSink; +import teetime.examples.throughput.methodcall.stage.NoopFilter; +import teetime.examples.throughput.methodcall.stage.ObjectProducer; +import teetime.examples.throughput.methodcall.stage.Pipeline; +import teetime.examples.throughput.methodcall.stage.StartTimestampFilter; +import teetime.examples.throughput.methodcall.stage.StopTimestampFilter; +import teetime.framework.core.Analysis; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThroughputAnalysis12 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<Void, Object> pipeline = new Pipeline<Void, Object>(); + pipeline.setFirstStage(objectProducer); + pipeline.addIntermediateStage(startTimestampFilter); + pipeline.addIntermediateStages(noopFilters); + pipeline.addIntermediateStage(stopTimestampFilter); + pipeline.setLastStage(collectorSink); + + pipeline.onStart(); + + final Runnable runnable = new Runnable() { + @Override + public void run() { + Object result; + do { + result = pipeline.executeRecursively(null); + } while (result != null); + } + }; + + 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/MethodCallThroughputAnalysis13.java b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis13.java new file mode 100644 index 0000000000000000000000000000000000000000..1fb71dbf819385998ae6f47e0866584e976b9c3b --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis13.java @@ -0,0 +1,137 @@ +/*************************************************************************** + * 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.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Callable; + +import teetime.examples.throughput.TimestampObject; +import teetime.examples.throughput.methodcall.stage.CollectorSink; +import teetime.examples.throughput.methodcall.stage.EndStage; +import teetime.examples.throughput.methodcall.stage.NoopFilter; +import teetime.examples.throughput.methodcall.stage.ObjectProducer; +import teetime.examples.throughput.methodcall.stage.StartTimestampFilter; +import teetime.examples.throughput.methodcall.stage.StopTimestampFilter; +import teetime.framework.core.Analysis; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class MethodCallThroughputAnalysis13 extends Analysis { + + public abstract class WrappingPipeline { + + public abstract boolean execute(); + + } + + 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 List<AbstractStage> stageList = new ArrayList<AbstractStage>(); + stageList.add(objectProducer); + stageList.add(startTimestampFilter); + stageList.addAll(Arrays.asList(noopFilters)); + stageList.add(stopTimestampFilter); + stageList.add(collectorSink); + + // using an array decreases the performance from 60ms to 200ms (by 3x) + final AbstractStage[] stages = stageList.toArray(new AbstractStage[0]); + + for (int i = 0; i < stages.length - 1; i++) { + StageWithPort<?, ?> stage = stages[i]; + stage.setSuccessor(stages[i + 1]); + } + stages[stages.length - 1].setSuccessor(new EndStage<Object>()); + + final WrappingPipeline pipeline = new WrappingPipeline() { + private int startIndex; + + @Override + public boolean execute() { + return stages[0].executeRecursively(null) != null; + } + + }; + + final Runnable runnable = new Runnable() { + @Override + public void run() { + boolean success; + do { + success = pipeline.execute(); + } while (success); + } + }; + 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/ProducerStage.java b/src/test/java/teetime/examples/throughput/methodcall/ProducerStage.java index 835b78a90f83203975e1afeca1564b5b07df330b..8ce842844cdf1a8406dfb0cc7c037dd09f5e2654 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/ProducerStage.java +++ b/src/test/java/teetime/examples/throughput/methodcall/ProducerStage.java @@ -23,6 +23,10 @@ public abstract class ProducerStage<I, O> extends AbstractStage<I, O> { @Override public void executeWithPorts() { this.execute5(null); + + // if (!this.getOutputPort().pipe.isEmpty()) { + // super.executeWithPorts(); + // } } } diff --git a/src/test/java/teetime/examples/throughput/methodcall/Stage.java b/src/test/java/teetime/examples/throughput/methodcall/Stage.java index f30063792029d1d4b62cbf93dd87178c628b0530..7ed18326641824d23cdb75e8714b47e04bb9a8cb 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/Stage.java +++ b/src/test/java/teetime/examples/throughput/methodcall/Stage.java @@ -6,6 +6,8 @@ public interface Stage<I, O> { public static final Object END_SIGNAL = new Object(); + Object executeRecursively(Object element); + O execute(Object element); // CommittableQueue<O> execute2(); @@ -25,4 +27,5 @@ public interface Stage<I, O> { void setSuccessor(Stage<?, ?> successor); boolean isReschedulable(); + } diff --git a/src/test/java/teetime/examples/throughput/methodcall/stage/CollectorSink.java b/src/test/java/teetime/examples/throughput/methodcall/stage/CollectorSink.java index 77a2ef04c72bc41538d4b6628fd1dd6afec77f2d..95963d8c7e9aae3a340f7319d64231b1d7b8aef0 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/stage/CollectorSink.java +++ b/src/test/java/teetime/examples/throughput/methodcall/stage/CollectorSink.java @@ -32,9 +32,6 @@ public class CollectorSink<T> extends ConsumerStage<T, Object> { private final List<T> elements; - /** - * @since 1.10 - */ public CollectorSink(final List<T> list) { this.elements = list; } diff --git a/src/test/java/teetime/examples/throughput/methodcall/stage/EndStage.java b/src/test/java/teetime/examples/throughput/methodcall/stage/EndStage.java new file mode 100644 index 0000000000000000000000000000000000000000..6f960eb892daef0ab051f972bbd6529f2d291fe4 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/stage/EndStage.java @@ -0,0 +1,95 @@ +package teetime.examples.throughput.methodcall.stage; + +import teetime.examples.throughput.methodcall.InputPort; +import teetime.examples.throughput.methodcall.OnDisableListener; +import teetime.examples.throughput.methodcall.OutputPort; +import teetime.examples.throughput.methodcall.SchedulingInformation; +import teetime.examples.throughput.methodcall.Stage; +import teetime.examples.throughput.methodcall.StageWithPort; +import teetime.util.list.CommittableQueue; + +public class EndStage<T> implements StageWithPort<T, T> { + + @Override + public Object executeRecursively(final Object element) { + return this.execute(element); + } + + @Override + public T execute(final Object element) { + return (T) element; + } + + @Override + public CommittableQueue<T> execute2(final CommittableQueue<T> elements) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SchedulingInformation getSchedulingInformation() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Stage getParentStage() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setParentStage(final Stage parentStage, final int index) { + // TODO Auto-generated method stub + + } + + @Override + public void setListener(final OnDisableListener listener) { + // TODO Auto-generated method stub + + } + + @Override + public Stage next() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setSuccessor(final Stage<?, ?> successor) { + // TODO Auto-generated method stub + + } + + @Override + public boolean isReschedulable() { + // TODO Auto-generated method stub + return false; + } + + @Override + public InputPort<T> getInputPort() { + // TODO Auto-generated method stub + return null; + } + + @Override + public OutputPort<T> getOutputPort() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void executeWithPorts() { + // TODO Auto-generated method stub + + } + + @Override + public void setSuccessor(final StageWithPort<?, ?> successor) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/stage/Pipeline.java b/src/test/java/teetime/examples/throughput/methodcall/stage/Pipeline.java index 10ca670c8d1a617d58d3ffc469968987dd70b467..4bb2d03a70d13eea3dc124367601895ba7ac1b2b 100644 --- a/src/test/java/teetime/examples/throughput/methodcall/stage/Pipeline.java +++ b/src/test/java/teetime/examples/throughput/methodcall/stage/Pipeline.java @@ -72,6 +72,11 @@ public class Pipeline<I, O> implements StageWithPort<I, O>, OnDisableListener { this.setReschedulable(this.stages[0].isReschedulable()); } + @Override + public Object executeRecursively(final Object element) { + return this.stages[0].executeRecursively(element); + } + public void onStart() { // Pipe pipe = new Pipe(); // this.outputPort.pipe = pipe; @@ -113,6 +118,7 @@ public class Pipeline<I, O> implements StageWithPort<I, O>, OnDisableListener { StageWithPort<?, ?> stage = this.stages[i]; stage.setSuccessor(this.stages[i + 1]); } + this.stages[this.stages.length - 1].setSuccessor(new EndStage<Object>()); } //