Commit e732f4a4 authored by Christian Wulf's avatar Christian Wulf

added checkstyle config file;

refactored package structure;
added correct and improved stage state management
parent c90c1c34
<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
<local-check-config name="Kieker Checkstyle" location="lib/static-analysis/checkstyle-5.6/cs-conf.xml" type="project" description="">
<additional-data name="protect-config-file" value="true"/>
<local-check-config name="Kieker Checkstyle" location="conf/cs-conf.xml" type="project" description="">
<additional-data name="protect-config-file" value="false"/>
</local-check-config>
<fileset name="all" enabled="true" check-config-name="Kieker Checkstyle" local="true">
<fileset name="all" enabled="true" check-config-name="Sun Checks" local="false">
<file-match-pattern match-pattern="." include-pattern="true"/>
</fileset>
<filter name="FilesFromPackage" enabled="true">
......@@ -16,5 +16,4 @@
<filter-data value="examples/userguide/appendix-Sigar/src"/>
<filter-data value="src-gen/analysis"/>
</filter>
<filter name="NonSrcDirs" enabled="true"/>
</fileset-config>
......@@ -12,6 +12,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="conf"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="maven.pomderived" value="true"/>
......
This diff is collapsed.
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Kieker - Profile
formatter_settings_version=12
org.eclipse.jdt.ui.ignorelowercasenames=true
org.eclipse.jdt.ui.importorder=java;javax;junit;org;com;kieker;kieker.test;
org.eclipse.jdt.ui.ondemandthreshold=99
org.eclipse.jdt.ui.staticondemandthreshold=99
sp_cleanup.add_default_serial_version_id=true
sp_cleanup.add_generated_serial_version_id=false
sp_cleanup.add_missing_annotations=true
sp_cleanup.add_missing_deprecated_annotations=true
sp_cleanup.add_missing_methods=false
sp_cleanup.add_missing_nls_tags=false
sp_cleanup.add_missing_override_annotations=true
sp_cleanup.add_missing_override_annotations_interface_methods=true
sp_cleanup.add_serial_version_id=false
sp_cleanup.always_use_blocks=true
sp_cleanup.always_use_parentheses_in_expressions=false
sp_cleanup.always_use_this_for_non_static_field_access=true
sp_cleanup.always_use_this_for_non_static_method_access=true
sp_cleanup.convert_to_enhanced_for_loop=false
sp_cleanup.correct_indentation=false
sp_cleanup.format_source_code=false
sp_cleanup.format_source_code_changes_only=false
sp_cleanup.make_local_variable_final=false
sp_cleanup.make_parameters_final=true
sp_cleanup.make_private_fields_final=true
sp_cleanup.make_type_abstract_if_missing_method=false
sp_cleanup.make_variable_declarations_final=true
sp_cleanup.never_use_blocks=false
sp_cleanup.never_use_parentheses_in_expressions=true
sp_cleanup.on_save_use_additional_actions=true
sp_cleanup.organize_imports=true
sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
sp_cleanup.remove_private_constructors=true
sp_cleanup.remove_trailing_whitespaces=true
sp_cleanup.remove_trailing_whitespaces_all=true
sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
sp_cleanup.remove_unnecessary_casts=true
sp_cleanup.remove_unnecessary_nls_tags=false
sp_cleanup.remove_unused_imports=true
sp_cleanup.remove_unused_local_variables=false
sp_cleanup.remove_unused_private_fields=true
sp_cleanup.remove_unused_private_members=false
sp_cleanup.remove_unused_private_methods=true
sp_cleanup.remove_unused_private_types=true
sp_cleanup.sort_members=false
sp_cleanup.sort_members_all=false
sp_cleanup.use_blocks=false
sp_cleanup.use_blocks_only_for_return_and_throw=false
sp_cleanup.use_parentheses_in_expressions=false
sp_cleanup.use_this_for_non_static_field_access=true
sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
sp_cleanup.use_this_for_non_static_method_access=true
sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=false
This diff is collapsed.
No preview for this file type
......@@ -17,7 +17,6 @@
package teetime.examples.countWords;
import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
......@@ -28,11 +27,13 @@ import teetime.framework.concurrent.StageTerminationPolicy;
import teetime.framework.concurrent.WorkerThread;
import teetime.framework.core.Analysis;
import teetime.framework.core.IInputPort;
import teetime.framework.core.IInputPort.PortState;
import teetime.framework.core.IOutputPort;
import teetime.framework.core.IPipeline;
import teetime.framework.core.ISink;
import teetime.framework.core.ISource;
import teetime.framework.core.IStage;
import teetime.framework.core.Pipeline;
import teetime.framework.sequential.MethodCallPipe;
import teetime.framework.sequential.QueuePipe;
import teetime.stage.basic.RepeaterSource;
......@@ -51,7 +52,7 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
private static final String START_DIRECTORY_NAME = ".";
private static final int SECONDS = 1000;
private static final int MAX_NUM_THREADS = 3;
private static final int MAX_NUM_THREADS = 2; // 1:2150, 2:1400, 3:~1400, 4:~1400
private WorkerThread[] ioThreads;
private WorkerThread[] nonIoThreads;
......@@ -82,6 +83,7 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
int numThreads = Runtime.getRuntime().availableProcessors();
numThreads = Math.min(MAX_NUM_THREADS, numThreads); // only for testing purposes
System.out.println("Using " + numThreads + " Threads.");
this.nonIoThreads = new WorkerThread[numThreads];
for (int i = 0; i < this.nonIoThreads.length; i++) {
......@@ -142,6 +144,9 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
distributor.setAccessesDeviceId(1);
// add each stage to a stage list
final List<IStage> startStages = new LinkedList<IStage>();
startStages.add(repeaterSource);
final List<IStage> stages = new LinkedList<IStage>();
stages.add(repeaterSource);
stages.add(directoryName2Files);
......@@ -152,34 +157,11 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
QueuePipe.connect(directoryName2Files.fileOutputPort, distributor.genericInputPort);
repeaterSource.START.setAssociatedPipe(new MethodCallPipe<Boolean>(Boolean.TRUE));
repeaterSource.START.setState(PortState.CLOSED);
final IPipeline pipeline = new IPipeline() {
@Override
@SuppressWarnings("unchecked")
public List<? extends IStage> getStartStages() {
return Arrays.asList(repeaterSource);
}
@Override
public List<IStage> getStages() {
return stages;
}
@Override
public void fireStartNotification() throws Exception {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStarts();
}
}
@Override
public void fireStopNotification() {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStops();
}
}
};
final Pipeline pipeline = new Pipeline();
pipeline.setStartStages(startStages);
pipeline.setStages(stages);
return pipeline;
}
......@@ -191,6 +173,9 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
final Merger<Pair<File, Integer>> merger = new Merger<Pair<File, Integer>>();
// add each stage to a stage list
final List<IStage> startStages = new LinkedList<IStage>();
startStages.add(distributor);
final List<IStage> stages = new LinkedList<IStage>();
stages.add(distributor);
stages.add(countWordsStage0);
......@@ -207,33 +192,9 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
SingleProducerSingleConsumerPipe.connect(merger.outputPort, printingMerger.getNewInputPort());
final IPipeline pipeline = new IPipeline() {
@Override
@SuppressWarnings("unchecked")
public List<? extends IStage> getStartStages() {
return Arrays.asList(distributor);
}
@Override
public List<IStage> getStages() {
return stages;
}
@Override
public void fireStartNotification() throws Exception {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStarts();
}
}
@Override
public void fireStopNotification() {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStops();
}
}
};
final Pipeline pipeline = new Pipeline();
pipeline.setStartStages(startStages);
pipeline.setStages(stages);
return pipeline;
}
......@@ -245,6 +206,9 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
outputWordsCountStage.setAccessesDeviceId(2);
// add each stage to a stage list
final List<IStage> startStages = new LinkedList<IStage>();
startStages.add(merger);
final List<IStage> stages = new LinkedList<IStage>();
stages.add(merger);
stages.add(outputWordsCountStage);
......@@ -252,33 +216,9 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
// connect stages by pipes
QueuePipe.connect(merger.outputPort, outputWordsCountStage.fileWordcountTupleInputPort);
final IPipeline pipeline = new IPipeline() {
@Override
@SuppressWarnings("unchecked")
public List<? extends IStage> getStartStages() {
return Arrays.asList(merger);
}
@Override
public List<IStage> getStages() {
return stages;
}
@Override
public void fireStartNotification() throws Exception {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStarts();
}
}
@Override
public void fireStopNotification() {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStops();
}
}
};
final Pipeline pipeline = new Pipeline();
pipeline.setStartStages(startStages);
pipeline.setStages(stages);
return pipeline;
}
......@@ -327,8 +267,8 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
System.out.println(stage); // NOPMD (Just for example purposes)
}
// final long durationInNs = thread.getDurationInNs();
// System.out.println(thread + " takes " + TimeUnit.NANOSECONDS.toMillis(durationInNs) + " ms");
// final long durationInNs = thread.getDurationInNs();
// System.out.println(thread + " takes " + TimeUnit.NANOSECONDS.toMillis(durationInNs) + " ms");
}
for (final WorkerThread thread : this.nonIoThreads) {
......@@ -337,16 +277,16 @@ public class ConcurrentCountWordsAnalysis extends Analysis {
System.out.println(stage); // NOPMD (Just for example purposes)
}
// final long durationInNs = thread.getDurationInNs();
// System.out.println(thread + " takes " + TimeUnit.NANOSECONDS.toMillis(durationInNs) + " ms");
// final long durationInNs = thread.getDurationInNs();
// System.out.println(thread + " takes " + TimeUnit.NANOSECONDS.toMillis(durationInNs) + " ms");
// if (durationInNs > maxDuration) {
// maxDuration = durationInNs;
// maxThread = thread;
// }
// if (durationInNs > maxDuration) {
// maxDuration = durationInNs;
// maxThread = thread;
// }
}
// System.out.println("maxThread: " + maxThread.toString() + " takes " + TimeUnit.NANOSECONDS.toMillis(maxDuration) + " ms"); // NOPMD (Just for example
// purposes)
// System.out.println("maxThread: " + maxThread.toString() + " takes " + TimeUnit.NANOSECONDS.toMillis(maxDuration) + " ms"); // NOPMD (Just for example
// purposes)
}
}
......@@ -17,14 +17,15 @@
package teetime.examples.countWords;
import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import teetime.framework.core.AbstractFilter;
import teetime.framework.core.Analysis;
import teetime.framework.core.IInputPort.PortState;
import teetime.framework.core.IPipeline;
import teetime.framework.core.IStage;
import teetime.framework.core.Pipeline;
import teetime.framework.sequential.MethodCallPipe;
import teetime.stage.basic.RepeaterSource;
import teetime.stage.basic.distributor.Distributor;
......@@ -79,6 +80,9 @@ public class CountWordsAnalysis extends Analysis {
final OutputWordsCountSink outputWordsCountStage = new OutputWordsCountSink();
// add each stage to a stage list
final List<IStage> startStages = new LinkedList<IStage>();
startStages.add(repeaterSource);
final List<IStage> stages = new LinkedList<IStage>();
stages.add(repeaterSource);
stages.add(findFilesStage);
......@@ -98,34 +102,11 @@ public class CountWordsAnalysis extends Analysis {
MethodCallPipe.connect(merger.outputPort, outputWordsCountStage.fileWordcountTupleInputPort);
repeaterSource.START.setAssociatedPipe(new MethodCallPipe<Boolean>(Boolean.TRUE));
repeaterSource.START.setState(PortState.CLOSED);
final IPipeline pipeline = new IPipeline() {
@Override
@SuppressWarnings("unchecked")
public List<? extends AbstractFilter<?>> getStartStages() {
return Arrays.asList(repeaterSource);
}
@Override
public List<IStage> getStages() {
return stages;
}
@Override
public void fireStartNotification() throws Exception {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStarts();
}
}
@Override
public void fireStopNotification() {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStops();
}
}
};
final Pipeline pipeline = new Pipeline();
pipeline.setStartStages(startStages);
pipeline.setStages(stages);
return pipeline;
}
......
......@@ -17,7 +17,6 @@
package teetime.examples.countWords;
import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
......@@ -25,8 +24,10 @@ import teetime.framework.concurrent.StageTerminationPolicy;
import teetime.framework.concurrent.WorkerThread;
import teetime.framework.core.AbstractFilter;
import teetime.framework.core.Analysis;
import teetime.framework.core.IInputPort.PortState;
import teetime.framework.core.IPipeline;
import teetime.framework.core.IStage;
import teetime.framework.core.Pipeline;
import teetime.framework.sequential.MethodCallPipe;
import teetime.framework.sequential.QueuePipe;
import teetime.stage.basic.RepeaterSource;
......@@ -81,6 +82,9 @@ public class QueuedCountWordsAnalysis extends Analysis {
final OutputWordsCountSink outputWordsCountStage = new OutputWordsCountSink();
// add each stage to a stage list
final List<IStage> startStages = new LinkedList<IStage>();
startStages.add(repeaterSource);
final List<IStage> stages = new LinkedList<IStage>();
stages.add(repeaterSource);
stages.add(findFilesStage);
......@@ -100,34 +104,11 @@ public class QueuedCountWordsAnalysis extends Analysis {
QueuePipe.connect(merger.outputPort, outputWordsCountStage.fileWordcountTupleInputPort);
repeaterSource.START.setAssociatedPipe(new MethodCallPipe<Boolean>(Boolean.TRUE));
repeaterSource.START.setState(PortState.CLOSED);
final IPipeline pipeline = new IPipeline() {
@Override
@SuppressWarnings("unchecked")
public List<? extends IStage> getStartStages() {
return Arrays.asList(repeaterSource);
}
@Override
public List<IStage> getStages() {
return stages;
}
@Override
public void fireStartNotification() throws Exception {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStarts();
}
}
@Override
public void fireStopNotification() {
for (final IStage stage : this.getStartStages()) {
stage.notifyPipelineStops();
}
}
};
final Pipeline pipeline = new Pipeline();
pipeline.setStartStages(startStages);
pipeline.setStages(stages);
return pipeline;
}
......
......@@ -15,21 +15,15 @@
***************************************************************************/
package teetime.framework.concurrent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import teetime.framework.core.IOutputPort;
import teetime.framework.core.IPipe;
import teetime.framework.core.IPipeCommand;
import teetime.framework.core.IPipeline;
import teetime.framework.core.IStage;
/**
* @author Christian Wulf
*
*
* @since 1.10
*/
public class StageWorkArrayList implements IStageWorkList {
......@@ -41,7 +35,6 @@ public class StageWorkArrayList implements IStageWorkList {
public int numToBeExecuted;
}
private final IPipeline pipeline;
private final int accessesDeviceId;
/** sorted array where the last stage has highest priority */
......@@ -53,75 +46,25 @@ public class StageWorkArrayList implements IStageWorkList {
* @since 1.10
*/
public StageWorkArrayList(final IPipeline pipeline, final int accessesDeviceId) {
this.pipeline = pipeline;
this.accessesDeviceId = accessesDeviceId;
final List<IStage> localStages = this.init();
this.stages = new SchedulableStage[localStages.size()];
for (int i = 0; i < localStages.size(); i++) {
this.stages = new SchedulableStage[pipeline.getStages().size()];
for (IStage stage : pipeline.getStages()) {
final SchedulableStage schedulableStage = new SchedulableStage();
schedulableStage.stage = localStages.get(i);
schedulableStage.stage = stage;
schedulableStage.numToBeExecuted = 0;
this.stages[i] = schedulableStage;
}
}
private List<IStage> init() {
this.setDepthForEachStage();
final List<IStage> stageList = new ArrayList<IStage>(this.pipeline.getStages());
final Comparator<? super IStage> depthComparator = new Comparator<IStage>() {
public int compare(final IStage o1, final IStage o2) {
if (o1.getDepth() == o2.getDepth()) {
return 0;
} else if (o1.getDepth() < o2.getDepth()) {
return -1;
} else {
return 1;
}
}
};
Collections.sort(stageList, depthComparator);
for (int i = 0; i < stageList.size(); i++) {
stageList.get(i).setSchedulingIndex(i);
}
return stageList;
}
private void setDepthForEachStage() {
final IPipeCommand setDepthCommand = new IPipeCommand() {
public void execute(final IPipe<?> pipe) throws Exception {
final IStage sourceStage = pipe.getSourcePort().getOwningStage();
final IStage owningStage = pipe.getTargetPort().getOwningStage();
if (owningStage.getDepth() == IStage.DEPTH_NOT_SET) {
owningStage.setDepth(sourceStage.getDepth() + 1);
owningStage.notifyOutputPipes(this);
}
}
};
for (final IStage startStage : this.pipeline.getStartStages()) {
startStage.setDepth(0);
}
for (final IStage startStage : this.pipeline.getStartStages()) {
try {
startStage.notifyOutputPipes(setDepthCommand);
} catch (final Exception e) {
throw new IllegalStateException("may not happen", e);
}
this.stages[stage.getSchedulingIndex()] = schedulableStage;
}
}
@Override
public void pushAll(final Collection<? extends IStage> stages) {
for (final IStage stage : stages) {
this.push(stage);
}
}
@Override
public void pushAll(final IOutputPort<?, ?>[] outputPorts) {
for (final IOutputPort<?, ?> outputPort : outputPorts) {
if (outputPort != null) {
......@@ -148,12 +91,12 @@ public class StageWorkArrayList implements IStageWorkList {
return isValid;
}
@Override
public IStage pop() {
final SchedulableStage schedulableStage = this.stages[this.lastIndex];
// schedulableStage.numToBeExecuted--;
schedulableStage.numToBeExecuted = 0;
cond:
if (schedulableStage.numToBeExecuted == 0)
cond: if (schedulableStage.numToBeExecuted == 0)
{
for (int i = this.lastIndex - 1; i >= this.firstIndex; i--) {
if (this.stages[i].numToBeExecuted > 0) {
......@@ -167,11 +110,13 @@ public class StageWorkArrayList implements IStageWorkList {
return schedulableStage.stage;
}
@Override
public IStage read() {
final SchedulableStage schedulableStage = this.stages[this.lastIndex];
return schedulableStage.stage;
}
@Override
public boolean isEmpty() {
return this.lastIndex == -1;
}
......
......@@ -16,11 +16,20 @@
package teetime.framework.concurrent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import teetime.framework.core.IInputPort;
import teetime.framework.core.IInputPort.PortState;
import teetime.framework.core.IPipe;
import teetime.framework.core.IPipeCommand;
import teetime.framework.core.IPipeline;
import teetime.framework.core.IStage;
import teetime.framework.scheduling.NextStageScheduler;
import teetime.framework.scheduling.StageStateManager;
import teetime.util.StopWatch;
/**
......@@ -30,8 +39,11 @@ import teetime.util.StopWatch;
*/
public class WorkerThread extends Thread {
private static final int NUM_ITERATIONS_TO_MEASURE = 10000;
private final IPipeline pipeline;
private IStageScheduler stageScheduler;
private StageStateManager stageStateManager;
private volatile StageTerminationPolicy terminationPolicy;
private volatile boolean shouldTerminate = false;
......@@ -40,15 +52,72 @@ public class WorkerThread extends Thread {
// statistics
private final StopWatch stopWatch = new StopWatch();
private final List<Long> durationPer10000IterationsInNs = new LinkedList<Long>();
private final List<Long> durationPerXIterationsInNs = new LinkedList<Long>();
private int iterations;
public WorkerThread(final IPipeline pipeline, final int accessesDeviceId) {
this.pipeline = pipeline;
this.accessesDeviceId = accessesDeviceId;
}
private void initStages(final IPipeline pipeline) {
for (final IStage stage : pipeline.getStages()) {
stage.setOwningThread(this);
}
this.accessesDeviceId = accessesDeviceId;
this.setDepthForEachStage(pipeline);
this.setSchedulingIndexForEachhStage(pipeline);
}
private void setDepthForEachStage(final IPipeline pipeline) {
final IPipeCommand setDepthCommand = new IPipeCommand() {
@Override
public void execute(final IPipe<?> pipe) throws Exception {
final IStage sourceStage = pipe.getSourcePort().getOwningStage();
final IStage owningStage = pipe.getTargetPort().getOwningStage();
if (owningStage.getDepth() == IStage.DEPTH_NOT_SET) {
owningStage.setDepth(sourceStage.getDepth() + 1);
owningStage.notifyOutputPipes(this);
}
}
};
for (final IStage startStage : pipeline.getStartStages()) {
startStage.setDepth(0);
}
for (final IStage startStage : pipeline.getStartStages()) {
try {
startStage.notifyOutputPipes(setDepthCommand);
} catch (final Exception e) {
throw new IllegalStateException("may not happen", e);
}
}
}
private List<IStage> setSchedulingIndexForEachhStage(final IPipeline pipeline) {
final List<IStage> stageList = new ArrayList<IStage>(pipeline.getStages());
final Comparator<? super IStage> depthComparator = new Comparator<IStage>() {
@Override
public int compare(final IStage o1, final IStage o2) {
if (o1.getDepth() == o2.getDepth()) {
return 0;
} else if (o1.getDepth() < o2.getDepth()) {
return -1;
} else {
return 1;
}
}
};
Collections.sort(stageList, depthComparator);
for (int i = 0; i < stageList.size(); i++) {
stageList.get(i).setSchedulingIndex(i);
}
return stageList;
}
@Override
......@@ -94,38 +163,37 @@ public class WorkerThread extends Thread {
// stageExecutionStopWatch.getDurationInNs(); //4952
// 6268 -> 5350 (w/o after) -> 4450 (w/o before) -> 3800 (w/o stage)
// final long schedulingOverhead = this.iterationStopWatch.getDurationInNs();
// final long schedulingOverhead = this.iterationStopWatch.getDurationInNs();
// final long schedulingOverhead = beforeStageExecutionStopWatch.getDurationInNs(); //327
// final long schedulingOverhead = stageExecutionStopWatch.getDurationInNs(); //1416
// final long schedulingOverhead = afterStageExecutionStopWatch.getDurationInNs(); //2450
// rest: ~2000 (measurement overhead?)