diff --git a/results/evaluation.xlsx b/results/evaluation.xlsx index 2d32e884ec9f8629de80baca0fbb8a15e4f439db..237636274d109ea88dcd32de85ac7fe9c492c45b 100644 Binary files a/results/evaluation.xlsx and b/results/evaluation.xlsx differ diff --git a/src/main/java/experiment/Experiment1.java b/src/main/java/experiment/Experiment1.java index a6198533ac93c2773232be119bc188228331dab7..043c29bc8132db3d3f8270494dea897ebe04f40c 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 2c261806a4ff2804b925a980402d58ef6b2bffcd..c81470364d7c661e4160ffe48603e3f92b975732 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 50a9db463d10ddfd43accd251f2914707b125fd0..61f9d20f757857b4bdafca9fe162314445cd533a 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 0000000000000000000000000000000000000000..034404fd43df0fba57903eaca38791662b903f02 --- /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 0000000000000000000000000000000000000000..50cbaccb08e937aa47f26154a9bef8a382fa9aca --- /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 0000000000000000000000000000000000000000..f365f75be7b2f88e0f379e0d0c27ec9cc94b4578 --- /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 4b79473cb7e4c024c5b1871bc37062f6e95c9ee7..0de24159328a81a87d4a03c9a7cf6873c655f544 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 148e88f6b29a094a1f7a41a0017f0ec6550d4c4d..84a1a6535045d7a0e1af4447e55c403913d6960e 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 e252b7dfe7658d52c8d55665b66285b181d29925..14847fa5b7dd5fd12cc2cea10ea20c77d1836d7e 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 cac1c4fb597d87729f1e2a5bafacdc2fa182fde8..ad773d9f26c85ab44b18b0ba2332731a5b0f7a5d 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 00af24c6bd6af962e1b92b2eee732fbad215d3f5..0fc986d8d3ac9758de475d5d81fcce7b87ba3ce6 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 8d59f48ad22eaaecd4820d00bf9d3ae816332410..e65c258848b70d2049f4c3c47c512e98e25374e4 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 175efeb7ba545ef0add1b27e6ed1b0b350323b5d..cba76138e4618e8ed28e4f861ec7d96ba48e2a27 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 ea9c0fd3213a319a8bc52044940d076b91900d2f..04c7ef6f4b807563d704b07a0d1eccb14ca50389 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 12d274b8dbe92f5c261b135b327fdc3f626120f6..e38b30fb5a18cceef5291f982035a9513bb4390c 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 dbaa1f0645a60549920ca430e61d9c3a0cdbfd53..ba77bf916f9dee7b450ca29ea35fcd9d286a9c38 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 9960a1fe400033ba618d66009b77bfd75ddeb9a2..e0599e802df9b7b50b5d5dbe7e7c3110c35987ce 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 360258d810eb7e218c87b146b9966dee82522980..5514a5f6b2eb59e1888a319c33a8056cb84ca993 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 10adfe8e8265980b11c08dd2456ebbfcc82421e6..8913146b0672b609d4eaa3079ea0b3b025a6419d 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 d660cbcf98f84df5c571d13dcd82c3fc140fb583..fcb6ed66e499db618a20980d030defc9773f362e 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 fbd2bc6b23905e2fd1f5b0240eeeb921b605dcae..b59f5bcddb5c25327446a2b3d6e8c203cecbaae8 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 8185632760e6f735288fe0265f93b8064cab3bcc..1147d6e6a145f40e13af56d359149c848eb82f80 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 3752aa5e63f2a4d599a88b350c3d4d8a9cb889e0..4badc3aadf8fd35d467626a612a9ebbe6a26fdbd 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 98de7481e1ecfbd0d82cb3838c64a9f17a5f8049..ee345747f9ab70a1ec5e9f8ce26524fec8dd2e4d 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 0000000000000000000000000000000000000000..f6a1939a48f4f5c8b87ffc44abf40374ddea3209 --- /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 3be668703c53149c0fca2a81cdfa6565ccadb788..62cca855112a631550ef575cc6c79855e68951db 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 bb227e1c48050a59810068dbddfa5787d53512e2..5eae1d222713841b1098ac9940f0ab1a0129b4f8 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 f72634b28874ffe2609e7898455bcf7e8203a1e0..584fcc5e87f3b94c6ec089e2977d2171a1aeec7d 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 0000000000000000000000000000000000000000..9aa4ecbcb066bb582a04ef9642e063ea108d523d --- /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 11fc8b079dd1b87bf4f814b208aa761fc7f713fe..405ebe97b12378c69fea05024f6892272fd59bc8 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 0000000000000000000000000000000000000000..c2fa61e340f34d71557c1f08aadc1e55a402e46c --- /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 236baae79c24dfc248a22a6f65051963893c433f..b5dd36d650166837f5011097c81a14096b9d9b41 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 0000000000000000000000000000000000000000..f88aefeccb75c6225744a7156ea9c72e66291021 --- /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 0000000000000000000000000000000000000000..6971394015cc52c6f4dfa80436894331e0e898b7 --- /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 0000000000000000000000000000000000000000..647a3885936b8b9cb9be1254e3ca3dbbdb186d5d --- /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 0000000000000000000000000000000000000000..eebed2354f5146f4a51cf069f96236e8485f458b --- /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 0000000000000000000000000000000000000000..6087b7109f7181f3ef19843731c95b356763b03a --- /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 0000000000000000000000000000000000000000..d6ddc9e2de94491060cb2be5212db9a0ae69beae --- /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 0000000000000000000000000000000000000000..ca0fc714726656955e878e2db577d2f4d8d1b72a --- /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 0000000000000000000000000000000000000000..896123f185cfddebac8c401f371254212d0766f3 --- /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 0000000000000000000000000000000000000000..dc1a0cfb9273d9039fe649ab938d5b19a132c1c2 --- /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 0000000000000000000000000000000000000000..89f5c97c77aa89f39b6098ed3eae4c591db71193 --- /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 0000000000000000000000000000000000000000..2f5bd5a556bbcc975fe030daf998c6986e676160 --- /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 0000000000000000000000000000000000000000..cc77fff3f46471851ebd8a5b57160b64a05d47b2 --- /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)); + } +}