From 45084db2834fdb283a72b1090af7b20ba30427fb Mon Sep 17 00:00:00 2001 From: Christian Wulf <chw@informatik.uni-kiel.de> Date: Tue, 3 Jun 2014 21:33:29 +0200 Subject: [PATCH] completed migration --- results/evaluation.xlsx | Bin 10415 -> 10467 bytes src/main/java/experiment/Experiment1.java | 5 +- src/main/java/experiment/Experiment2.java | 5 +- .../stage/RecordFromTextLineCreator.java | 4 +- .../IllegalRecordFormatException.java | 32 ++ .../exception/MonitoringRecordException.java | 51 +++ .../exception/UnknownRecordTypeException.java | 37 +++ .../framework/core/AbstractFilter.java | 2 +- .../java/teetime/framework/core/IPipe.java | 2 +- src/main/java/teetime/stage/io/DbReader.java | 12 +- src/main/java/teetime/stage/io/TCPReader.java | 24 +- .../stage/kieker/File2RecordFilter.java | 8 +- .../kieker/MonitoringLogDirectory2Files.java | 10 +- .../fileToRecord/BinaryFile2RecordFilter.java | 8 +- .../fileToRecord/DatFile2RecordFilter.java | 4 +- .../fileToRecord/ZipFile2RecordFilter.java | 6 +- .../TextLine2MappingRegistryFilter.java | 4 +- .../textLine/TextLine2RecordFilter.java | 10 +- .../TraceReconstructionFilter.java | 12 +- .../predicate/IsIMonitoringRecordInRange.java | 5 +- .../IsOperationExecutionRecordInRange.java | 5 +- ...rationExecutionRecordTraceIdPredicate.java | 5 +- .../stringBuffer/StringBufferFilter.java | 4 +- .../handler/AbstractDataTypeHandler.java | 7 +- .../handler/IMonitoringRecordHandler.java | 9 +- .../stringBuffer/util/KiekerHashMap.java | 290 ++++++++++++++++++ .../CircularWorkStealingDeque.java | 37 +-- .../ExceptionalCircularWorkStealingDeque.java | 30 +- ...dExceptionalCircularWorkStealingDeque.java | 25 +- .../exception/DequeIsEmptyException.java | 5 + .../{ => exception}/DequePopException.java | 2 +- .../exception/OperationAbortedException.java | 5 + ...hodCallThoughputTimestampAnalysisTest.java | 3 +- .../throughput/methodcall/CollectorSink.java | 44 +++ .../MethodCallThroughputAnalysis.java | 105 +++++++ .../throughput/methodcall/NoopFilter.java | 28 ++ .../throughput/methodcall/ObjectProducer.java | 68 ++++ .../methodcall/StartTimestampFilter.java | 31 ++ .../methodcall/StopTimestampFilter.java | 31 ++ .../CircularWorkStealingDequeTest.java | 34 ++ ...ularWorkStealingDequeWithSentinelTest.java | 34 ++ ...alingDequeWithThreadLocalSentinelTest.java | 34 ++ ...eptionalCircularWorkStealingDequeTest.java | 39 +++ .../UntypedCircularWorkStealingDequeTest.java | 35 +++ ...eptionalCircularWorkStealingDequeTest.java | 42 +++ 45 files changed, 1064 insertions(+), 129 deletions(-) create mode 100644 src/main/java/kieker/common/exception/IllegalRecordFormatException.java create mode 100644 src/main/java/kieker/common/exception/MonitoringRecordException.java create mode 100644 src/main/java/kieker/common/exception/UnknownRecordTypeException.java create mode 100644 src/main/java/teetime/stage/stringBuffer/util/KiekerHashMap.java create mode 100644 src/main/java/teetime/util/concurrent/workstealing/exception/DequeIsEmptyException.java rename src/main/java/teetime/util/concurrent/workstealing/{ => exception}/DequePopException.java (75%) create mode 100644 src/main/java/teetime/util/concurrent/workstealing/exception/OperationAbortedException.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/NoopFilter.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java create mode 100644 src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java create mode 100644 src/test/java/teetime/util/concurrent/CircularWorkStealingDequeTest.java create mode 100644 src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithSentinelTest.java create mode 100644 src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithThreadLocalSentinelTest.java create mode 100644 src/test/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDequeTest.java create mode 100644 src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedCircularWorkStealingDequeTest.java create mode 100644 src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDequeTest.java diff --git a/results/evaluation.xlsx b/results/evaluation.xlsx index 2d32e884ec9f8629de80baca0fbb8a15e4f439db..237636274d109ea88dcd32de85ac7fe9c492c45b 100644 GIT binary patch delta 7392 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 delta 7474 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 bVa6l>Un_r>#rro|Bj_(?I#f=Ezk~k;AorvC diff --git a/src/main/java/experiment/Experiment1.java b/src/main/java/experiment/Experiment1.java index a6198533..043c29bc 100644 --- a/src/main/java/experiment/Experiment1.java +++ b/src/main/java/experiment/Experiment1.java @@ -24,12 +24,11 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; -import javax.security.auth.login.Configuration; - import kieker.analysis.AnalysisController; import kieker.analysis.IAnalysisController; import kieker.analysis.stage.EmptyPassOnFilter; import kieker.analysis.stage.ObjectProducer; +import kieker.common.configuration.Configuration; import teetime.framework.concurrent.StageTerminationPolicy; import teetime.framework.concurrent.WorkerThread; import teetime.framework.core.Analysis; @@ -41,7 +40,7 @@ import teetime.util.StatisticsUtil; /** * @author Nils Christian Ehmke - * + * * @since 1.10 */ public class Experiment1 { diff --git a/src/main/java/experiment/Experiment2.java b/src/main/java/experiment/Experiment2.java index 2c261806..c8147036 100644 --- a/src/main/java/experiment/Experiment2.java +++ b/src/main/java/experiment/Experiment2.java @@ -24,8 +24,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.Callable; -import javax.security.auth.login.Configuration; - import kieker.analysis.AnalysisController; import kieker.analysis.IAnalysisController; import kieker.analysis.stage.CollectorSink; @@ -33,6 +31,7 @@ import kieker.analysis.stage.EmptyPassOnFilter; import kieker.analysis.stage.ObjectProducer; import kieker.analysis.stage.StartTimestampFilter; import kieker.analysis.stage.StopTimestampFilter; +import kieker.common.configuration.Configuration; import teetime.examples.throughput.TimestampObject; import teetime.framework.concurrent.WorkerThread; import teetime.framework.core.Analysis; @@ -45,7 +44,7 @@ import teetime.util.StatisticsUtil; /** * @author Nils Christian Ehmke - * + * * @since 1.10 */ public class Experiment2 { diff --git a/src/main/java/kieker/analysis/stage/RecordFromTextLineCreator.java b/src/main/java/kieker/analysis/stage/RecordFromTextLineCreator.java index 50a9db46..61f9d20f 100644 --- a/src/main/java/kieker/analysis/stage/RecordFromTextLineCreator.java +++ b/src/main/java/kieker/analysis/stage/RecordFromTextLineCreator.java @@ -17,7 +17,9 @@ package kieker.analysis.stage; import java.io.File; +import kieker.common.exception.IllegalRecordFormatException; import kieker.common.exception.MonitoringRecordException; +import kieker.common.exception.UnknownRecordTypeException; import kieker.common.record.AbstractMonitoringRecord; import kieker.common.record.IMonitoringRecord; import kieker.common.record.controlflow.OperationExecutionRecord; @@ -27,7 +29,7 @@ import teetime.stage.kieker.className.ClassNameRegistryRepository; /** * @author Christian Wulf - * + * * @since 1.10 */ public class RecordFromTextLineCreator { diff --git a/src/main/java/kieker/common/exception/IllegalRecordFormatException.java b/src/main/java/kieker/common/exception/IllegalRecordFormatException.java new file mode 100644 index 00000000..034404fd --- /dev/null +++ b/src/main/java/kieker/common/exception/IllegalRecordFormatException.java @@ -0,0 +1,32 @@ +/*************************************************************************** + * 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 kieker.common.exception; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class IllegalRecordFormatException extends Exception { + + private static final long serialVersionUID = -6747714448544097075L; + + public IllegalRecordFormatException() { + // No code necessary + } + +} diff --git a/src/main/java/kieker/common/exception/MonitoringRecordException.java b/src/main/java/kieker/common/exception/MonitoringRecordException.java new file mode 100644 index 00000000..50cbaccb --- /dev/null +++ b/src/main/java/kieker/common/exception/MonitoringRecordException.java @@ -0,0 +1,51 @@ +/*************************************************************************** + * 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 kieker.common.exception; + +/** + * This exception can be used to show that something in context with a monitoring record failed. + * + * @author Jan Waller + * + * @since 1.0 + */ +public class MonitoringRecordException extends Exception { + + private static final long serialVersionUID = -619093518689867366L; + + /** + * Creates a new instance of this class using the given parameters. + * + * @param messString + * The message of this exception. + */ + public MonitoringRecordException(final String messString) { + super(messString); + } + + /** + * Creates a new instance of this class using the given parameters. + * + * @param messString + * The message of this exception. + * @param cause + * The cause of this exception. + */ + public MonitoringRecordException(final String messString, final Throwable cause) { + super(messString, cause); + } +} diff --git a/src/main/java/kieker/common/exception/UnknownRecordTypeException.java b/src/main/java/kieker/common/exception/UnknownRecordTypeException.java new file mode 100644 index 00000000..f365f75b --- /dev/null +++ b/src/main/java/kieker/common/exception/UnknownRecordTypeException.java @@ -0,0 +1,37 @@ +/*************************************************************************** + * 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 kieker.common.exception; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class UnknownRecordTypeException extends Exception { + + private static final long serialVersionUID = 3967732396720668295L; + private final String classname; + + public UnknownRecordTypeException(final String message, final String classname, final Throwable cause) { + super(message, cause); + this.classname = classname; + } + + public String getClassName() { + return this.classname; + } +} diff --git a/src/main/java/teetime/framework/core/AbstractFilter.java b/src/main/java/teetime/framework/core/AbstractFilter.java index 4b79473c..0de24159 100644 --- a/src/main/java/teetime/framework/core/AbstractFilter.java +++ b/src/main/java/teetime/framework/core/AbstractFilter.java @@ -23,7 +23,7 @@ import java.util.LinkedList; import java.util.List; import teetime.util.StopWatch; -import teetime.util.concurrent.workstealing.DequePopException; +import teetime.util.concurrent.workstealing.exception.DequePopException; /** * diff --git a/src/main/java/teetime/framework/core/IPipe.java b/src/main/java/teetime/framework/core/IPipe.java index 148e88f6..84a1a653 100644 --- a/src/main/java/teetime/framework/core/IPipe.java +++ b/src/main/java/teetime/framework/core/IPipe.java @@ -18,7 +18,7 @@ package teetime.framework.core; import java.util.List; -import teetime.util.concurrent.workstealing.DequePopException; +import teetime.util.concurrent.workstealing.exception.DequePopException; /** * diff --git a/src/main/java/teetime/stage/io/DbReader.java b/src/main/java/teetime/stage/io/DbReader.java index e252b7df..14847fa5 100644 --- a/src/main/java/teetime/stage/io/DbReader.java +++ b/src/main/java/teetime/stage/io/DbReader.java @@ -22,9 +22,9 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import teetime.common.exception.MonitoringRecordException; -import teetime.common.record.AbstractMonitoringRecord; -import teetime.common.record.IMonitoringRecord; +import kieker.common.exception.MonitoringRecordException; +import kieker.common.record.AbstractMonitoringRecord; +import kieker.common.record.IMonitoringRecord; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.Description; @@ -32,9 +32,9 @@ import teetime.framework.core.IOutputPort; /** * A very simple database reader that probably only works for small data sets. - * + * * @author Jan Waller, Nils Christian Ehmke - * + * * @since 1.10 */ @Description("A reader which reads records from a database") @@ -141,7 +141,7 @@ public class DbReader extends AbstractFilter<DbReader> { /** * This method uses the given table to read records and sends them to the output port. - * + * * @param connection * The connection to the database which will be used. * @param tablename diff --git a/src/main/java/teetime/stage/io/TCPReader.java b/src/main/java/teetime/stage/io/TCPReader.java index cac1c4fb..ad773d9f 100644 --- a/src/main/java/teetime/stage/io/TCPReader.java +++ b/src/main/java/teetime/stage/io/TCPReader.java @@ -22,23 +22,23 @@ import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; -import teetime.common.exception.MonitoringRecordException; -import teetime.common.logging.Log; -import teetime.common.logging.LogFactory; -import teetime.common.record.AbstractMonitoringRecord; -import teetime.common.record.IMonitoringRecord; -import teetime.common.record.misc.RegistryRecord; -import teetime.common.util.registry.ILookup; -import teetime.common.util.registry.Lookup; +import kieker.common.exception.MonitoringRecordException; +import kieker.common.logging.Log; +import kieker.common.logging.LogFactory; +import kieker.common.record.AbstractMonitoringRecord; +import kieker.common.record.IMonitoringRecord; +import kieker.common.record.misc.RegistryRecord; +import kieker.common.util.registry.ILookup; +import kieker.common.util.registry.Lookup; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IOutputPort; /** * This is a reader which reads the records from a TCP port. - * + * * @author Jan Waller, Nils Christian Ehmke - * + * * @since 1.10 */ public class TCPReader extends AbstractFilter<TCPReader> { @@ -143,9 +143,9 @@ public class TCPReader extends AbstractFilter<TCPReader> { } /** - * + * * @author Jan Waller - * + * * @since 1.8 */ class TCPStringReader extends Thread { diff --git a/src/main/java/teetime/stage/kieker/File2RecordFilter.java b/src/main/java/teetime/stage/kieker/File2RecordFilter.java index 00af24c6..0fc986d8 100644 --- a/src/main/java/teetime/stage/kieker/File2RecordFilter.java +++ b/src/main/java/teetime/stage/kieker/File2RecordFilter.java @@ -17,9 +17,9 @@ package teetime.stage.kieker; import java.io.File; -import teetime.common.record.IMonitoringRecord; -import teetime.common.util.filesystem.BinaryCompressionMethod; -import teetime.common.util.filesystem.FSUtil; +import kieker.common.record.IMonitoringRecord; +import kieker.common.util.filesystem.BinaryCompressionMethod; +import kieker.common.util.filesystem.FSUtil; import teetime.framework.concurrent.ConcurrentWorkStealingPipe; import teetime.framework.concurrent.ConcurrentWorkStealingPipeFactory; import teetime.framework.core.CompositeFilter; @@ -38,7 +38,7 @@ import teetime.stage.predicate.PredicateFilter; /** * @author Christian Wulf - * + * * @since 1.10 */ public class File2RecordFilter extends CompositeFilter { diff --git a/src/main/java/teetime/stage/kieker/MonitoringLogDirectory2Files.java b/src/main/java/teetime/stage/kieker/MonitoringLogDirectory2Files.java index 8d59f48a..e65c2588 100644 --- a/src/main/java/teetime/stage/kieker/MonitoringLogDirectory2Files.java +++ b/src/main/java/teetime/stage/kieker/MonitoringLogDirectory2Files.java @@ -19,15 +19,15 @@ import java.io.File; import java.io.FileFilter; import java.util.Comparator; -import teetime.common.util.filesystem.BinaryCompressionMethod; -import teetime.common.util.filesystem.FSUtil; +import kieker.common.util.filesystem.BinaryCompressionMethod; +import kieker.common.util.filesystem.FSUtil; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; import teetime.stage.io.Directory2FilesFilter; /** * @author Christian Wulf - * + * * @since 1.10 */ public class MonitoringLogDirectory2Files extends Directory2FilesFilter { @@ -36,12 +36,13 @@ public class MonitoringLogDirectory2Files extends Directory2FilesFilter { /** * @author Christian Wulf - * + * * @since 1.10 */ static class MonitoringLogFileFilter implements FileFilter { private String filePrefix; + @Override public boolean accept(final File pathname) { final String name = pathname.getName(); return pathname.isFile() @@ -59,6 +60,7 @@ public class MonitoringLogDirectory2Files extends Directory2FilesFilter { } private static final Comparator<File> FILE_COMPARATOR = new Comparator<File>() { + @Override public final int compare(final File f1, final File f2) { return f1.compareTo(f2); // simplified (we expect no dirs!) } diff --git a/src/main/java/teetime/stage/kieker/fileToRecord/BinaryFile2RecordFilter.java b/src/main/java/teetime/stage/kieker/fileToRecord/BinaryFile2RecordFilter.java index 175efeb7..cba76138 100644 --- a/src/main/java/teetime/stage/kieker/fileToRecord/BinaryFile2RecordFilter.java +++ b/src/main/java/teetime/stage/kieker/fileToRecord/BinaryFile2RecordFilter.java @@ -20,9 +20,9 @@ import java.io.File; import java.io.IOException; import kieker.analysis.stage.RecordFromBinaryFileCreator; -import teetime.common.exception.MonitoringRecordException; -import teetime.common.record.IMonitoringRecord; -import teetime.common.util.filesystem.BinaryCompressionMethod; +import kieker.common.exception.MonitoringRecordException; +import kieker.common.record.IMonitoringRecord; +import kieker.common.util.filesystem.BinaryCompressionMethod; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; @@ -31,7 +31,7 @@ import teetime.stage.kieker.className.ClassNameRegistryRepository; /** * @author Christian Wulf - * + * * @since 1.10 */ public class BinaryFile2RecordFilter extends AbstractFilter<BinaryFile2RecordFilter> { diff --git a/src/main/java/teetime/stage/kieker/fileToRecord/DatFile2RecordFilter.java b/src/main/java/teetime/stage/kieker/fileToRecord/DatFile2RecordFilter.java index ea9c0fd3..04c7ef6f 100644 --- a/src/main/java/teetime/stage/kieker/fileToRecord/DatFile2RecordFilter.java +++ b/src/main/java/teetime/stage/kieker/fileToRecord/DatFile2RecordFilter.java @@ -17,7 +17,7 @@ package teetime.stage.kieker.fileToRecord; import java.io.File; -import teetime.common.record.IMonitoringRecord; +import kieker.common.record.IMonitoringRecord; import teetime.framework.concurrent.ConcurrentWorkStealingPipe; import teetime.framework.concurrent.ConcurrentWorkStealingPipeFactory; import teetime.framework.core.CompositeFilter; @@ -30,7 +30,7 @@ import teetime.stage.util.TextLine; /** * @author Christian Wulf - * + * * @since 1.10 */ public class DatFile2RecordFilter extends CompositeFilter { diff --git a/src/main/java/teetime/stage/kieker/fileToRecord/ZipFile2RecordFilter.java b/src/main/java/teetime/stage/kieker/fileToRecord/ZipFile2RecordFilter.java index 12d274b8..e38b30fb 100644 --- a/src/main/java/teetime/stage/kieker/fileToRecord/ZipFile2RecordFilter.java +++ b/src/main/java/teetime/stage/kieker/fileToRecord/ZipFile2RecordFilter.java @@ -29,8 +29,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import kieker.analysis.stage.MappingFileParser; -import teetime.common.record.IMonitoringRecord; -import teetime.common.util.filesystem.FSUtil; +import kieker.common.record.IMonitoringRecord; +import kieker.common.util.filesystem.FSUtil; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; @@ -39,7 +39,7 @@ import teetime.stage.kieker.className.ClassNameRegistry; /** * @author Christian Wulf - * + * * @since 1.10 */ public class ZipFile2RecordFilter extends AbstractFilter<ZipFile2RecordFilter> { diff --git a/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2MappingRegistryFilter.java b/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2MappingRegistryFilter.java index dbaa1f06..ba77bf91 100644 --- a/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2MappingRegistryFilter.java +++ b/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2MappingRegistryFilter.java @@ -18,14 +18,14 @@ package teetime.stage.kieker.fileToRecord.textLine; import java.util.Map; -import teetime.common.util.filesystem.FSUtil; +import kieker.common.util.filesystem.FSUtil; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; /** * @author Christian Wulf - * + * * @since 1.10 */ public class TextLine2MappingRegistryFilter extends AbstractFilter<TextLine2MappingRegistryFilter> { diff --git a/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2RecordFilter.java b/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2RecordFilter.java index 9960a1fe..e0599e80 100644 --- a/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2RecordFilter.java +++ b/src/main/java/teetime/stage/kieker/fileToRecord/textLine/TextLine2RecordFilter.java @@ -20,10 +20,10 @@ import java.util.HashSet; import java.util.Set; import kieker.analysis.stage.RecordFromTextLineCreator; -import teetime.common.exception.IllegalRecordFormatException; -import teetime.common.exception.MonitoringRecordException; -import teetime.common.exception.UnknownRecordTypeException; -import teetime.common.record.IMonitoringRecord; +import kieker.common.exception.IllegalRecordFormatException; +import kieker.common.exception.MonitoringRecordException; +import kieker.common.exception.UnknownRecordTypeException; +import kieker.common.record.IMonitoringRecord; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; @@ -34,7 +34,7 @@ import teetime.stage.util.TextLine; /** * @author Christian Wulf - * + * * @since 1.10 */ public class TextLine2RecordFilter extends AbstractFilter<TextLine2RecordFilter> { diff --git a/src/main/java/teetime/stage/kieker/traceReconstruction/TraceReconstructionFilter.java b/src/main/java/teetime/stage/kieker/traceReconstruction/TraceReconstructionFilter.java index 360258d8..5514a5f6 100644 --- a/src/main/java/teetime/stage/kieker/traceReconstruction/TraceReconstructionFilter.java +++ b/src/main/java/teetime/stage/kieker/traceReconstruction/TraceReconstructionFilter.java @@ -20,20 +20,20 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; -import teetime.analysis.plugin.filter.flow.TraceEventRecords; -import teetime.analysis.plugin.filter.flow.reconstruction.TraceBuffer; -import teetime.common.record.flow.IFlowRecord; -import teetime.common.record.flow.trace.AbstractTraceEvent; -import teetime.common.record.flow.trace.TraceMetadata; +import kieker.analysis.plugin.filter.flow.TraceEventRecords; +import kieker.common.record.flow.IFlowRecord; +import kieker.common.record.flow.trace.AbstractTraceEvent; +import kieker.common.record.flow.trace.TraceMetadata; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; import teetime.framework.core.IOutputPort; import teetime.util.concurrent.hashmap.ConcurrentHashMapWithDefault; +import teetime.util.concurrent.hashmap.TraceBuffer; /** * @author Christian Wulf - * + * * @since 1.10 */ public class TraceReconstructionFilter extends AbstractFilter<TraceReconstructionFilter> { diff --git a/src/main/java/teetime/stage/predicate/IsIMonitoringRecordInRange.java b/src/main/java/teetime/stage/predicate/IsIMonitoringRecordInRange.java index 10adfe8e..8913146b 100644 --- a/src/main/java/teetime/stage/predicate/IsIMonitoringRecordInRange.java +++ b/src/main/java/teetime/stage/predicate/IsIMonitoringRecordInRange.java @@ -15,11 +15,12 @@ ***************************************************************************/ package teetime.stage.predicate; -import teetime.common.record.IMonitoringRecord; +import kieker.common.record.IMonitoringRecord; + /** * @author Christian Wulf - * + * * @since 1.10 */ public class IsIMonitoringRecordInRange extends IsTimestampInRange<IMonitoringRecord> { diff --git a/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordInRange.java b/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordInRange.java index d660cbcf..fcb6ed66 100644 --- a/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordInRange.java +++ b/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordInRange.java @@ -15,11 +15,12 @@ ***************************************************************************/ package teetime.stage.predicate; -import teetime.common.record.controlflow.OperationExecutionRecord; +import kieker.common.record.controlflow.OperationExecutionRecord; + /** * @author Christian Wulf - * + * * @since 1.10 */ public class IsOperationExecutionRecordInRange extends IsTimestampInRange<OperationExecutionRecord> { diff --git a/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordTraceIdPredicate.java b/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordTraceIdPredicate.java index fbd2bc6b..b59f5bcd 100644 --- a/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordTraceIdPredicate.java +++ b/src/main/java/teetime/stage/predicate/IsOperationExecutionRecordTraceIdPredicate.java @@ -17,11 +17,12 @@ package teetime.stage.predicate; import java.util.Set; -import teetime.common.record.controlflow.OperationExecutionRecord; +import kieker.common.record.controlflow.OperationExecutionRecord; + /** * @author Christian Wulf - * + * * @since 1.10 */ public class IsOperationExecutionRecordTraceIdPredicate extends IsTraceIdPredicate<OperationExecutionRecord> { diff --git a/src/main/java/teetime/stage/stringBuffer/StringBufferFilter.java b/src/main/java/teetime/stage/stringBuffer/StringBufferFilter.java index 81856327..1147d6e6 100644 --- a/src/main/java/teetime/stage/stringBuffer/StringBufferFilter.java +++ b/src/main/java/teetime/stage/stringBuffer/StringBufferFilter.java @@ -18,16 +18,16 @@ package teetime.stage.stringBuffer; import java.util.ArrayList; import java.util.Collection; -import teetime.analysis.plugin.filter.forward.util.KiekerHashMap; import teetime.framework.core.AbstractFilter; import teetime.framework.core.Context; import teetime.framework.core.IInputPort; import teetime.framework.core.IOutputPort; import teetime.stage.stringBuffer.handler.AbstractDataTypeHandler; +import teetime.stage.stringBuffer.util.KiekerHashMap; /** * @author Christian Wulf - * + * * @since 1.10 */ public class StringBufferFilter<T> extends AbstractFilter<StringBufferFilter<T>> { diff --git a/src/main/java/teetime/stage/stringBuffer/handler/AbstractDataTypeHandler.java b/src/main/java/teetime/stage/stringBuffer/handler/AbstractDataTypeHandler.java index 3752aa5e..4badc3aa 100644 --- a/src/main/java/teetime/stage/stringBuffer/handler/AbstractDataTypeHandler.java +++ b/src/main/java/teetime/stage/stringBuffer/handler/AbstractDataTypeHandler.java @@ -15,12 +15,13 @@ ***************************************************************************/ package teetime.stage.stringBuffer.handler; -import teetime.analysis.plugin.filter.forward.util.KiekerHashMap; -import teetime.common.logging.Log; +import teetime.stage.stringBuffer.util.KiekerHashMap; +import kieker.common.logging.Log; + /** * @author Christian Wulf - * + * * @since 1.10 */ public abstract class AbstractDataTypeHandler<T> { diff --git a/src/main/java/teetime/stage/stringBuffer/handler/IMonitoringRecordHandler.java b/src/main/java/teetime/stage/stringBuffer/handler/IMonitoringRecordHandler.java index 98de7481..ee345747 100644 --- a/src/main/java/teetime/stage/stringBuffer/handler/IMonitoringRecordHandler.java +++ b/src/main/java/teetime/stage/stringBuffer/handler/IMonitoringRecordHandler.java @@ -15,13 +15,14 @@ ***************************************************************************/ package teetime.stage.stringBuffer.handler; -import teetime.common.exception.MonitoringRecordException; -import teetime.common.record.AbstractMonitoringRecord; -import teetime.common.record.IMonitoringRecord; +import kieker.common.exception.MonitoringRecordException; +import kieker.common.record.AbstractMonitoringRecord; +import kieker.common.record.IMonitoringRecord; + /** * @author Christian Wulf - * + * * @since 1.10 */ public class IMonitoringRecordHandler extends AbstractDataTypeHandler<IMonitoringRecord> { diff --git a/src/main/java/teetime/stage/stringBuffer/util/KiekerHashMap.java b/src/main/java/teetime/stage/stringBuffer/util/KiekerHashMap.java new file mode 100644 index 00000000..f6a1939a --- /dev/null +++ b/src/main/java/teetime/stage/stringBuffer/util/KiekerHashMap.java @@ -0,0 +1,290 @@ +/*************************************************************************** + * 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.stage.stringBuffer.util; + +import java.lang.ref.SoftReference; +import java.util.concurrent.locks.ReentrantLock; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class KiekerHashMap { + + private static final int INITIAL_CAPACITY = 16; + private static final double LOAD_FACTOR = 0.75d; + private static final int CONCURRENCY_LEVEL = 16; + private static final int MAXIMUM_CAPACITY = 1 << 30; + + /** + * Mask value for indexing into segments. The upper bits of a key's hash code are used to choose the segment. + */ + private final int segmentMask; + + /** + * Shift value for indexing within segments. + */ + private final int segmentShift; + + /** + * The segments, each of which is a specialized hash table. + */ + private final Segment[] segments; + + /** + * @since 1.10 + */ + public KiekerHashMap() { + // Find power-of-two sizes best matching arguments + int sshift = 0; + int ssize = 1; + while (ssize < CONCURRENCY_LEVEL) { + ++sshift; + ssize <<= 1; + } + this.segmentShift = 32 - sshift; + this.segmentMask = ssize - 1; + this.segments = new Segment[ssize]; + int c = INITIAL_CAPACITY / ssize; + if ((c * ssize) < INITIAL_CAPACITY) { + ++c; + } + int cap = 1; + while (cap < c) { + cap <<= 1; + } + for (int i = 0; i < this.segments.length; ++i) { + this.segments[i] = new Segment(cap, LOAD_FACTOR); + } + } + + /** + * Applies a supplemental hash function to a given hashCode, which defends against poor quality hash functions. This is critical because ConcurrentHashMap uses + * power-of-two length hash tables, that otherwise encounter collisions for hashCodes that do not differ in lower or upper bits. + */ + private static final int hash(final String value) { + // Spread bits to regularize both segment and index locations, using variant of single-word Wang/Jenkins hash. + int h = value.hashCode(); + h += (h << 15) ^ 0xffffcd7d; + h ^= h >>> 10; + h += h << 3; + h ^= h >>> 6; + h += (h << 2) + (h << 14); + return h ^ (h >>> 16); + } + + public final String get(final String value) { + final int hash = KiekerHashMap.hash(value); + return this.segments[(hash >>> this.segmentShift) & this.segmentMask].get(value, hash); + } + + // ---------------- Inner Classes -------------- + + /** + * StringBuffer entry. + */ + private static final class HashEntry extends SoftReference<String> { + final int hash; // NOPMD NOCS (package visible for inner class) + final HashEntry next; // NOPMD NOCS (package visible for inner class) + + protected HashEntry(final String value, final int hash, final HashEntry next) { + super(value); + this.hash = hash; + this.next = next; + } + } + + /** + * Segments are specialized versions of hash tables. This subclasses from ReentrantLock opportunistically, just to simplify some locking and avoid separate + * construction. + * + * Segments maintain a table of entry lists that are ALWAYS kept in a consistent state, so can be read without locking. Next fields of nodes are immutable + * (final). All list additions are performed at the front of each bin. This makes it easy to check changes, and also fast to traverse. When nodes would + * otherwise be changed, new nodes are created to replace them. This works well for hash tables since the bin lists tend to be short. (The average length is + * less than two for the default load factor threshold.) + * + * Read operations can thus proceed without locking, but rely on selected uses of volatiles to ensure that completed write operations performed by other + * threads are noticed. For most purposes, the "count" field, tracking the number of elements, serves as that volatile variable ensuring visibility. This is + * convenient because this field needs to be read in many read operations anyway: + * + * - All (unsynchronized) read operations must first read the "count" field, and should not look at table entries if it is 0. + * + * - All (synchronized) write operations should write to the "count" field after structurally changing any bin. The operations must not take any action that + * could even momentarily cause a concurrent read operation to see inconsistent data. This is made easier by the nature of the read operations in Map. For + * example, no operation can reveal that the table has grown but the threshold has not yet been updated, so there are no atomicity requirements for this with + * respect to reads. + * + * As a guide, all critical volatile reads and writes to the count field are marked in code comments. + */ + private static final class Segment extends ReentrantLock { + + private static final long serialVersionUID = 1L; + + /** + * The number of elements in this segment's region. + */ + private volatile int count; + + /** + * The per-segment table. + */ + private HashEntry[] table; + + /** + * The table is rehashed when its size exceeds this threshold. (The value of this field is always <tt>(int)(capacity * loadFactor)</tt>.) + */ + private int threshold; + + protected Segment(final int initialCapacity, final double lf) { + this.table = new HashEntry[initialCapacity]; + this.threshold = (int) (initialCapacity * lf); + this.count = 0; + } + + protected final String get(final String value, final int hash) { + HashEntry e = null; + String cachedString; + if (this.count != 0) { // volatile read! search for entry without locking + final HashEntry[] tab = this.table; + final int index = hash & (tab.length - 1); + final HashEntry first = tab[index]; + e = first; + while (e != null) { + if (e.hash == hash) { + cachedString = e.get(); + if (value.equals(cachedString)) { + return cachedString; + } + } + e = e.next; + } + } + this.lock(); + try { + final int c = this.count + 1; + if (c >= this.threshold) { + this.cleanup(); + if (c >= this.threshold) { // if still full + this.rehash(); + } + this.count = c; // write volatile + } + final HashEntry[] tab = this.table; + final int index = hash & (tab.length - 1); + final HashEntry first = tab[index]; // the bin the value may be inside + e = first; + while (e != null) { + if (e.hash == hash) { + cachedString = e.get(); + if (value.equals(cachedString)) { + return cachedString; + } + } + e = e.next; + } + tab[index] = new HashEntry(value, hash, first); + this.count = c; // write-volatile + return value; // return now cached string + } finally { + this.unlock(); + } + } + + private final void cleanup() { + int c = this.count; + final HashEntry[] tab = this.table; + for (int index = 0; index < tab.length; index++) { + // find first remaining entry + HashEntry e = tab[index]; + while ((e != null) && (e.get() == null)) { + e = e.next; + c--; + } + if (e == null) { + tab[index] = null; + } else { + // find more existing entries and enqueue before this one + HashEntry first = new HashEntry(e.get(), e.hash, null); + e = e.next; + while (e != null) { + final String s = e.get(); + if (s != null) { + first = new HashEntry(s, e.hash, first); + } else { + c--; + } + e = e.next; + } + tab[index] = first; + } + } + c--; + this.count = c; // write-volatile + } + + /** + * Reclassify nodes in each list to new Map. Because we are using power-of-two expansion, the elements from each bin must either stay at same index, or + * move with a power of two offset. We eliminate unnecessary node creation by catching cases where old nodes can be reused because their next fields + * won't change. Statistically, at the default threshold, only about one-sixth of them need cloning when a table doubles. The nodes they replace will be + * garbage collectable as soon as they are no longer referenced by any reader thread that may be in the midst of traversing table right now. + */ + private final void rehash() { + final HashEntry[] oldTable = this.table; + final int oldCapacity = oldTable.length; + if (oldCapacity >= MAXIMUM_CAPACITY) { + return; + } + final HashEntry[] newTable = new HashEntry[oldCapacity << 1]; + this.threshold = (int) (newTable.length * LOAD_FACTOR); + final int sizeMask = newTable.length - 1; + for (int i = 0; i < oldCapacity; i++) { + // We need to guarantee that any existing reads of old Map can proceed. So we cannot yet null out each bin. + final HashEntry e = oldTable[i]; + + if (e != null) { + final HashEntry next = e.next; + final int idx = e.hash & sizeMask; + + // Single node on list + if (next == null) { + newTable[idx] = e; + } else { + // Reuse trailing consecutive sequence at same slot + HashEntry lastRun = e; + int lastIdx = idx; + for (HashEntry last = next; last != null; last = last.next) { // find end of bin + final int k = last.hash & sizeMask; + if (k != lastIdx) { // NOCS (nested if) + lastIdx = k; + lastRun = last; + } + } + newTable[lastIdx] = lastRun; + + // Clone all remaining nodes + for (HashEntry p = e; p != lastRun; p = p.next) { // NOPMD (no equals meant here) + final int k = p.hash & sizeMask; + final HashEntry n = newTable[k]; + newTable[k] = new HashEntry(p.get(), p.hash, n); + } + } + } + } + this.table = newTable; + } + } +} diff --git a/src/main/java/teetime/util/concurrent/workstealing/CircularWorkStealingDeque.java b/src/main/java/teetime/util/concurrent/workstealing/CircularWorkStealingDeque.java index 3be66870..62cca855 100644 --- a/src/main/java/teetime/util/concurrent/workstealing/CircularWorkStealingDeque.java +++ b/src/main/java/teetime/util/concurrent/workstealing/CircularWorkStealingDeque.java @@ -19,26 +19,21 @@ package teetime.util.concurrent.workstealing; import java.util.List; import java.util.concurrent.atomic.AtomicLong; +import teetime.util.concurrent.workstealing.exception.DequeIsEmptyException; +import teetime.util.concurrent.workstealing.exception.OperationAbortedException; + /** - * + * * @author Christian Wulf - * + * * @see "Dynamic Circular WorkStealing Deque" - * + * * @since 1.10 */ public class CircularWorkStealingDeque<T> { - public static class DequeIsEmptyException extends DequePopException { - private static final long serialVersionUID = -6685406255103741724L; - } - public static final DequeIsEmptyException DEQUE_IS_EMPTY_EXCEPTION = new DequeIsEmptyException(); - public static class OperationAbortedException extends DequePopException { - private static final long serialVersionUID = 2983001853326344073L; - } - public static final OperationAbortedException OPERATION_ABORTED_EXCEPTION = new OperationAbortedException(); private static final long LOG_INITIAL_SIZE = 10; @@ -52,7 +47,7 @@ public class CircularWorkStealingDeque<T> { } /** - * + * * @param o * a non-<code>null</code> element */ @@ -72,7 +67,7 @@ public class CircularWorkStealingDeque<T> { } /** - * + * * @param elements * a non-<code>null</code> list */ @@ -97,7 +92,7 @@ public class CircularWorkStealingDeque<T> { /** * Returns and removes the latest element from this deque. - * + * * @return * <ul> * <li><code>null</code> if the deque contains no elements, @@ -129,9 +124,9 @@ public class CircularWorkStealingDeque<T> { /** * Returns and removes the latest element from this deque. - * + * * @return <i>the latest element</i>, otherwise it throws a <code>DequeIsEmptyException</code> - * + * * @throws DequeIsEmptyException */ public T popBottomEx() { @@ -175,7 +170,7 @@ public class CircularWorkStealingDeque<T> { /** * Tries to steal (return & remove) the oldest element from this deque. - * + * * @return * <ul> * <li><code>null</code> if the deque contains no elements, @@ -208,9 +203,9 @@ public class CircularWorkStealingDeque<T> { /** * Tries to steal (return & remove) the oldest element from this deque. - * + * * @return <i>the oldest element</i>, otherwise it throws a <code>DequeIsEmptyException</code> or a <code>OperationAbortedException</code> - * + * * @throws DequeIsEmptyException * @throws OperationAbortedException */ @@ -260,7 +255,7 @@ public class CircularWorkStealingDeque<T> { /** * Returns but does not remove the latest element from this deque.<br> * <i>For debugging purposes</i> - * + * * @return <ul> * <li><code>null</code> if the deque contains no elements, * <li><i>the latest element</i> otherwise @@ -292,7 +287,7 @@ public class CircularWorkStealingDeque<T> { /** * For debugging purposes - * + * * @return the number of elements this deque contains */ public long size(final Object sourceStage) { diff --git a/src/main/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDeque.java b/src/main/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDeque.java index bb227e1c..5eae1d22 100644 --- a/src/main/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDeque.java +++ b/src/main/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDeque.java @@ -19,27 +19,21 @@ package teetime.util.concurrent.workstealing.alternative; import java.util.concurrent.atomic.AtomicLong; import teetime.util.concurrent.workstealing.CircularArray; +import teetime.util.concurrent.workstealing.exception.DequeIsEmptyException; +import teetime.util.concurrent.workstealing.exception.OperationAbortedException; /** - * + * * @author Christian Wulf - * + * * @see "Dynamic Circular WorkStealing Deque" - * + * * @since 1.10 */ public class ExceptionalCircularWorkStealingDeque<T> { - public static class DequeIsEmptyException extends Exception { - private static final long serialVersionUID = -6685406255103741724L; - } - public static final DequeIsEmptyException DEQUE_IS_EMPTY_EXCEPTION = new DequeIsEmptyException(); - public static class OperationAbortedException extends Exception { - private static final long serialVersionUID = 2983001853326344073L; - } - public static final OperationAbortedException OPERATION_ABORTED_EXCEPTION = new OperationAbortedException(); private static final long LOG_INITIAL_SIZE = 10; @@ -75,9 +69,8 @@ public class ExceptionalCircularWorkStealingDeque<T> { } /** - * - * @return - * <ul> + * + * @return <ul> * <li><code>EMPTY</code> if the deque contains no elements, * <li><i>the latest element</i> otherwise * </ul> @@ -125,9 +118,8 @@ public class ExceptionalCircularWorkStealingDeque<T> { /** * Tries to steal (return & remove) the oldest element from this deque. - * - * @return - * <ul> + * + * @return <ul> * <li><code>EMPTY</code> if the deque contains no elements, * <li><code>ABORT</code> if the deque is currently being stolen by another thread, * <li><i>the oldest element</i> otherwise @@ -160,7 +152,7 @@ public class ExceptionalCircularWorkStealingDeque<T> { /** * For debugging purposes - * + * * @return but does not remove the bottom element from this deque */ public T readBottom() { @@ -183,7 +175,7 @@ public class ExceptionalCircularWorkStealingDeque<T> { /** * For debugging purposes - * + * * @return the number of elements this deque contains */ public long size(final Object sourceStage) { diff --git a/src/main/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDeque.java b/src/main/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDeque.java index f72634b2..584fcc5e 100644 --- a/src/main/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDeque.java +++ b/src/main/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDeque.java @@ -19,27 +19,22 @@ package teetime.util.concurrent.workstealing.alternative; import java.util.concurrent.atomic.AtomicLong; import teetime.util.concurrent.workstealing.CircularArray; -import teetime.util.concurrent.workstealing.DequePopException; +import teetime.util.concurrent.workstealing.exception.DequeIsEmptyException; +import teetime.util.concurrent.workstealing.exception.DequePopException; +import teetime.util.concurrent.workstealing.exception.OperationAbortedException; /** - * + * * @author Christian Wulf - * + * * @see "Dynamic Circular WorkStealing Deque" - * + * * @since 1.10 */ public class UntypedExceptionalCircularWorkStealingDeque { - public static class DequeIsEmptyException extends DequePopException { - private static final long serialVersionUID = -6685406255103741724L; - } public static final DequeIsEmptyException DEQUE_IS_EMPTY_EXCEPTION = new DequeIsEmptyException(); - public static class OperationAbortedException extends DequePopException { - private static final long serialVersionUID = 2983001853326344073L; - } - public static final OperationAbortedException OPERATION_ABORTED_EXCEPTION = new OperationAbortedException(); private static final long LOG_INITIAL_SIZE = 10; @@ -75,7 +70,7 @@ public class UntypedExceptionalCircularWorkStealingDeque { } /** - * + * * @return * <ul> * <li><code>EMPTY</code> if the deque contains no elements, @@ -125,7 +120,7 @@ public class UntypedExceptionalCircularWorkStealingDeque { /** * Tries to steal (return & remove) the oldest element from this deque. - * + * * @return * <ul> * <li><code>EMPTY</code> if the deque contains no elements, @@ -159,7 +154,7 @@ public class UntypedExceptionalCircularWorkStealingDeque { /** * For debugging purposes - * + * * @return but does not remove the bottom element from this deque */ public Object readBottom() { @@ -182,7 +177,7 @@ public class UntypedExceptionalCircularWorkStealingDeque { /** * For debugging purposes - * + * * @return the number of elements this deque contains */ public long size(final Object sourceStage) { diff --git a/src/main/java/teetime/util/concurrent/workstealing/exception/DequeIsEmptyException.java b/src/main/java/teetime/util/concurrent/workstealing/exception/DequeIsEmptyException.java new file mode 100644 index 00000000..9aa4ecbc --- /dev/null +++ b/src/main/java/teetime/util/concurrent/workstealing/exception/DequeIsEmptyException.java @@ -0,0 +1,5 @@ +package teetime.util.concurrent.workstealing.exception; + +public class DequeIsEmptyException extends DequePopException { + private static final long serialVersionUID = -6685406255103741724L; +} \ No newline at end of file diff --git a/src/main/java/teetime/util/concurrent/workstealing/DequePopException.java b/src/main/java/teetime/util/concurrent/workstealing/exception/DequePopException.java similarity index 75% rename from src/main/java/teetime/util/concurrent/workstealing/DequePopException.java rename to src/main/java/teetime/util/concurrent/workstealing/exception/DequePopException.java index 11fc8b07..405ebe97 100644 --- a/src/main/java/teetime/util/concurrent/workstealing/DequePopException.java +++ b/src/main/java/teetime/util/concurrent/workstealing/exception/DequePopException.java @@ -1,4 +1,4 @@ -package teetime.util.concurrent.workstealing; +package teetime.util.concurrent.workstealing.exception; import teetime.util.StacklessException; diff --git a/src/main/java/teetime/util/concurrent/workstealing/exception/OperationAbortedException.java b/src/main/java/teetime/util/concurrent/workstealing/exception/OperationAbortedException.java new file mode 100644 index 00000000..c2fa61e3 --- /dev/null +++ b/src/main/java/teetime/util/concurrent/workstealing/exception/OperationAbortedException.java @@ -0,0 +1,5 @@ +package teetime.util.concurrent.workstealing.exception; + +public class OperationAbortedException extends DequePopException { + private static final long serialVersionUID = 2983001853326344073L; +} \ No newline at end of file diff --git a/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysisTest.java b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysisTest.java index 236baae7..b5dd36d6 100644 --- a/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysisTest.java +++ b/src/test/java/teetime/examples/throughput/MethodCallThoughputTimestampAnalysisTest.java @@ -24,12 +24,13 @@ import kieker.common.logging.LogFactory; import org.junit.Before; import org.junit.Test; +import teetime.examples.throughput.methodcall.MethodCallThroughputAnalysis; import teetime.util.StatisticsUtil; import teetime.util.StopWatch; /** * @author Christian Wulf - * + * * @since 1.10 */ public class MethodCallThoughputTimestampAnalysisTest { diff --git a/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java b/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java new file mode 100644 index 00000000..f88aefec --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/CollectorSink.java @@ -0,0 +1,44 @@ +/*************************************************************************** + * 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; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class CollectorSink<T> { + + private static final int THRESHOLD = 10000; + + private final List<T> elements; + + /** + * @since 1.10 + */ + public CollectorSink(final List<T> list) { + this.elements = list; + } + + public void execute(final T element) { + 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/MethodCallThroughputAnalysis.java b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis.java new file mode 100644 index 00000000..69713940 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/MethodCallThroughputAnalysis.java @@ -0,0 +1,105 @@ +/*************************************************************************** + * 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 MethodCallThroughputAnalysis 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 Runnable runnable = new Runnable() { + @Override + public void run() { + while (true) { + TimestampObject object = objectProducer.execute(); + if (object == null) { + return; + } + object = startTimestampFilter.execute(object); + for (final NoopFilter<TimestampObject> noopFilter : noopFilters) { + object = noopFilter.execute(object); + } + object = stopTimestampFilter.execute(object); + collectorSink.execute(object); + } + } + }; + 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 new file mode 100644 index 00000000..647a3885 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/NoopFilter.java @@ -0,0 +1,28 @@ +/*************************************************************************** + * 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; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class NoopFilter<T> { + + public T execute(final T obj) { + return obj; + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java b/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java new file mode 100644 index 00000000..eebed235 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/ObjectProducer.java @@ -0,0 +1,68 @@ +/*************************************************************************** + * 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.concurrent.Callable; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class ObjectProducer<T> { + + private long numInputObjects; + private Callable<T> inputObjectCreator; + + /** + * @since 1.10 + */ + public ObjectProducer(final long numInputObjects, final Callable<T> inputObjectCreator) { + this.numInputObjects = numInputObjects; + this.inputObjectCreator = inputObjectCreator; + } + + public T execute() { + if (this.numInputObjects == 0) { + return null; + } + + try { + final T newObject = this.inputObjectCreator.call(); + this.numInputObjects--; + + return newObject; + } catch (final Exception e) { + throw new IllegalStateException(); + } + } + + public long getNumInputObjects() { + return this.numInputObjects; + } + + public void setNumInputObjects(final long numInputObjects) { + this.numInputObjects = numInputObjects; + } + + public Callable<T> getInputObjectCreator() { + return this.inputObjectCreator; + } + + public void setInputObjectCreator(final Callable<T> inputObjectCreator) { + this.inputObjectCreator = inputObjectCreator; + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java b/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java new file mode 100644 index 00000000..6087b710 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/StartTimestampFilter.java @@ -0,0 +1,31 @@ +/*************************************************************************** + * 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 teetime.examples.throughput.TimestampObject; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class StartTimestampFilter { + + public TimestampObject execute(final TimestampObject obj) { + obj.setStartTimestamp(System.nanoTime()); + return obj; + } +} diff --git a/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java b/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java new file mode 100644 index 00000000..d6ddc9e2 --- /dev/null +++ b/src/test/java/teetime/examples/throughput/methodcall/StopTimestampFilter.java @@ -0,0 +1,31 @@ +/*************************************************************************** + * 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 teetime.examples.throughput.TimestampObject; + +/** + * @author Christian Wulf + * + * @since 1.10 + */ +public class StopTimestampFilter { + + public TimestampObject execute(final TimestampObject obj) { + obj.setStopTimestamp(System.nanoTime()); + return obj; + } +} diff --git a/src/test/java/teetime/util/concurrent/CircularWorkStealingDequeTest.java b/src/test/java/teetime/util/concurrent/CircularWorkStealingDequeTest.java new file mode 100644 index 00000000..ca0fc714 --- /dev/null +++ b/src/test/java/teetime/util/concurrent/CircularWorkStealingDequeTest.java @@ -0,0 +1,34 @@ +package teetime.util.concurrent; + +import org.hamcrest.number.OrderingComparison; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import teetime.util.StopWatch; +import teetime.util.concurrent.workstealing.CircularWorkStealingDeque; +import teetime.util.concurrent.workstealing.alternative.UntypedCircularWorkStealingDequeTest; + +public class CircularWorkStealingDequeTest { + private StopWatch stopWatch; + + @Before + public void before() { + this.stopWatch = new StopWatch(); + } + + @Test + public void measureManyEmptyPulls() { + final CircularWorkStealingDeque<Object> deque = new CircularWorkStealingDeque<Object>(); + + final int numIterations = UntypedCircularWorkStealingDequeTest.NUM_ITERATIONS; + this.stopWatch.start(); + for (int i = 0; i < numIterations; i++) { + deque.popBottom(); + } + this.stopWatch.end(); + + Assert.assertThat(this.stopWatch.getDuration(), + OrderingComparison.lessThan(UntypedCircularWorkStealingDequeTest.EXPECTED_DURATION)); + } +} diff --git a/src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithSentinelTest.java b/src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithSentinelTest.java new file mode 100644 index 00000000..896123f1 --- /dev/null +++ b/src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithSentinelTest.java @@ -0,0 +1,34 @@ +package teetime.util.concurrent.workstealing.alternative; + +import org.hamcrest.number.OrderingComparison; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import teetime.util.StopWatch; + +public class CircularWorkStealingDequeWithSentinelTest { + private StopWatch stopWatch; + + @Before + public void before() { + this.stopWatch = new StopWatch(); + } + + @Test + public void measureManyEmptyPulls() { + final CircularWorkStealingDequeWithSentinel<Object> deque = new CircularWorkStealingDequeWithSentinel<Object>(); + + final int numIterations = UntypedCircularWorkStealingDequeTest.NUM_ITERATIONS; + this.stopWatch.start(); + for (int i = 0; i < numIterations; i++) { + deque.popBottom(); + // if (returnValue.getState() != State.EMPTY) { + // returnValue.getValue(); + // } + } + this.stopWatch.end(); + + Assert.assertThat(this.stopWatch.getDuration(), OrderingComparison.lessThan(UntypedCircularWorkStealingDequeTest.EXPECTED_DURATION)); + } +} diff --git a/src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithThreadLocalSentinelTest.java b/src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithThreadLocalSentinelTest.java new file mode 100644 index 00000000..dc1a0cfb --- /dev/null +++ b/src/test/java/teetime/util/concurrent/workstealing/alternative/CircularWorkStealingDequeWithThreadLocalSentinelTest.java @@ -0,0 +1,34 @@ +package teetime.util.concurrent.workstealing.alternative; + +import org.hamcrest.number.OrderingComparison; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import teetime.util.StopWatch; + +public class CircularWorkStealingDequeWithThreadLocalSentinelTest { + private StopWatch stopWatch; + + @Before + public void before() { + this.stopWatch = new StopWatch(); + } + + @Test + public void measureManyEmptyPulls() { + final CircularWorkStealingDequeWithThreadLocalSentinel<Object> deque = new CircularWorkStealingDequeWithThreadLocalSentinel<Object>(); + + final int numIterations = UntypedCircularWorkStealingDequeTest.NUM_ITERATIONS; + this.stopWatch.start(); + for (int i = 0; i < numIterations; i++) { + deque.popBottom(); + // if (returnValue.getState() != State.EMPTY) { + // returnValue.getValue(); + // } + } + this.stopWatch.end(); + + Assert.assertThat(this.stopWatch.getDuration(), OrderingComparison.lessThan(UntypedCircularWorkStealingDequeTest.EXPECTED_DURATION)); + } +} diff --git a/src/test/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDequeTest.java b/src/test/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDequeTest.java new file mode 100644 index 00000000..89f5c97c --- /dev/null +++ b/src/test/java/teetime/util/concurrent/workstealing/alternative/ExceptionalCircularWorkStealingDequeTest.java @@ -0,0 +1,39 @@ +package teetime.util.concurrent.workstealing.alternative; + +import org.hamcrest.number.OrderingComparison; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import teetime.util.StopWatch; +import teetime.util.concurrent.workstealing.exception.DequeIsEmptyException; + +@Ignore +public class ExceptionalCircularWorkStealingDequeTest { + + private StopWatch stopWatch; + + @Before + public void before() { + this.stopWatch = new StopWatch(); + } + + @Test + public void measureManyEmptyPulls() { + final ExceptionalCircularWorkStealingDeque<String> deque = new ExceptionalCircularWorkStealingDeque<String>(); + + final int numIterations = UntypedCircularWorkStealingDequeTest.NUM_ITERATIONS; + this.stopWatch.start(); + for (int i = 0; i < numIterations; i++) { + try { + deque.popBottom(); + } catch (final DequeIsEmptyException e) { + // do not handle; we just want to compare the performance of throwing a preallocated exception vs. returning special values + } + } + this.stopWatch.end(); + + Assert.assertThat(this.stopWatch.getDuration(), OrderingComparison.lessThan(UntypedCircularWorkStealingDequeTest.EXPECTED_DURATION)); + } +} diff --git a/src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedCircularWorkStealingDequeTest.java b/src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedCircularWorkStealingDequeTest.java new file mode 100644 index 00000000..2f5bd5a5 --- /dev/null +++ b/src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedCircularWorkStealingDequeTest.java @@ -0,0 +1,35 @@ +package teetime.util.concurrent.workstealing.alternative; + +import org.hamcrest.number.OrderingComparison; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import teetime.util.StopWatch; + +public class UntypedCircularWorkStealingDequeTest { + + public static final int NUM_ITERATIONS = 100000000; + public static final long EXPECTED_DURATION = 1100; + + private StopWatch stopWatch; + + @Before + public void before() { + this.stopWatch = new StopWatch(); + } + + @Test + public void measureManyEmptyPulls() { + final UntypedCircularWorkStealingDeque deque = new UntypedCircularWorkStealingDeque(); + + final int numIterations = NUM_ITERATIONS; + this.stopWatch.start(); + for (int i = 0; i < numIterations; i++) { + deque.popBottom(); + } + this.stopWatch.end(); + + Assert.assertThat(this.stopWatch.getDuration(), OrderingComparison.lessThan(UntypedCircularWorkStealingDequeTest.EXPECTED_DURATION)); + } +} diff --git a/src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDequeTest.java b/src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDequeTest.java new file mode 100644 index 00000000..cc77fff3 --- /dev/null +++ b/src/test/java/teetime/util/concurrent/workstealing/alternative/UntypedExceptionalCircularWorkStealingDequeTest.java @@ -0,0 +1,42 @@ +package teetime.util.concurrent.workstealing.alternative; + +import org.hamcrest.number.OrderingComparison; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import teetime.util.StopWatch; +import teetime.util.concurrent.workstealing.exception.DequeIsEmptyException; + +public class UntypedExceptionalCircularWorkStealingDequeTest { + + private StopWatch stopWatch; + + @Before + public void before() { + this.stopWatch = new StopWatch(); + } + + @Test + public void measureManyEmptyPulls() { + final UntypedExceptionalCircularWorkStealingDeque deque = new UntypedExceptionalCircularWorkStealingDeque(); + System.out.println(UntypedExceptionalCircularWorkStealingDeque.DEQUE_IS_EMPTY_EXCEPTION); + System.out.println(UntypedExceptionalCircularWorkStealingDeque.OPERATION_ABORTED_EXCEPTION); + + int counter = 0; + final int numIterations = UntypedCircularWorkStealingDequeTest.NUM_ITERATIONS; + this.stopWatch.start(); + for (int i = 0; i < numIterations; i++) { + try { + deque.popBottom(); + } catch (final DequeIsEmptyException e) { + // do not handle; we just want to compare the performance of throwing a preallocated exception vs. returning special values + counter++; + } + } + this.stopWatch.end(); + + Assert.assertThat(this.stopWatch.getDuration(), OrderingComparison.lessThan(UntypedCircularWorkStealingDequeTest.EXPECTED_DURATION)); + Assert.assertThat(counter, OrderingComparison.comparesEqualTo(UntypedCircularWorkStealingDequeTest.NUM_ITERATIONS)); + } +} -- GitLab