From 872d2f292f27e7f5d7ca9f09f491243aef4da1b8 Mon Sep 17 00:00:00 2001
From: Reiner Jung <reiner.jung@email.uni-kiel.de>
Date: Fri, 20 Nov 2020 22:52:39 +0100
Subject: [PATCH] Added Kieker/TeeTime based record receiver.

---
 benchmark/build.gradle                        |  4 +-
 .../moobench/benchmark/BenchmarkMain.java     | 48 +++++++++---------
 .../benchmark/BenchmarkParameter.java         | 28 +++++------
 frameworks/Kieker/scripts/benchmark.sh        | 27 +++++-----
 frameworks/Kieker/scripts/common-functions    |  1 +
 frameworks/Kieker/scripts/config              | 12 ++---
 frameworks/Kieker/scripts/run-benchmark.sh    | 49 ++++++++++++++++++-
 .../MooBench/r => scripts}/stats.csv.r        |  0
 settings.gradle                               |  7 +--
 tools/receiver/build.gradle                   | 15 ++++++
 .../tools/receiver/ReceiverConfiguration.java | 15 ++++++
 .../tools/receiver/RecordReceiver.java        | 21 ++++++++
 12 files changed, 159 insertions(+), 68 deletions(-)
 mode change 100644 => 100755 frameworks/Kieker/scripts/run-benchmark.sh
 rename frameworks/Kieker/{OverheadEvaluationMicrobenchmark/MooBench/r => scripts}/stats.csv.r (100%)
 create mode 100644 tools/receiver/build.gradle
 create mode 100644 tools/receiver/src/main/java/moobench/tools/receiver/ReceiverConfiguration.java
 create mode 100644 tools/receiver/src/main/java/moobench/tools/receiver/RecordReceiver.java

diff --git a/benchmark/build.gradle b/benchmark/build.gradle
index 1dbd5d6..514b30e 100644
--- a/benchmark/build.gradle
+++ b/benchmark/build.gradle
@@ -1,6 +1,6 @@
 plugins {
-	id 'java'
-	id 'application'
+    id 'java'
+    id 'application'
 }
 
 dependencies {
diff --git a/benchmark/src/main/java/moobench/benchmark/BenchmarkMain.java b/benchmark/src/main/java/moobench/benchmark/BenchmarkMain.java
index ff3eebb..e1c5a86 100644
--- a/benchmark/src/main/java/moobench/benchmark/BenchmarkMain.java
+++ b/benchmark/src/main/java/moobench/benchmark/BenchmarkMain.java
@@ -35,17 +35,11 @@ public final class BenchmarkMain {
 	private static final String ENCODING = "UTF-8";
 
 	private static PrintStream ps = null;
-	private static String outputFn = null;
-	private static int totalThreads = 0;
-	private static int totalCalls = 0;
-	private static long methodTime = 0;
-	private static int recursionDepth = 0;
-	private static boolean quickstart = false;
-	private static boolean forceTerminate = false;
-	private static MonitoredClass mc = null;
 
 	private static BenchmarkParameter parameter = new BenchmarkParameter();
 
+	private static MonitoredClass monitoredClass;
+
 	private BenchmarkMain() {
 	}
 
@@ -55,22 +49,22 @@ public final class BenchmarkMain {
 		BenchmarkMain.parseAndInitializeArguments(args);
 
 		System.out.println(" # Experiment run configuration:"); // NOPMD (System.out)
-		System.out.println(" # 1. Output filename " + BenchmarkMain.outputFn); // NOPMD (System.out)
-		System.out.println(" # 2. Recursion Depth " + BenchmarkMain.recursionDepth); // NOPMD (System.out)
-		System.out.println(" # 3. Threads " + BenchmarkMain.totalThreads); // NOPMD (System.out)
-		System.out.println(" # 4. Total-Calls " + BenchmarkMain.totalCalls); // NOPMD (System.out)
-		System.out.println(" # 5. Method-Time " + BenchmarkMain.methodTime); // NOPMD (System.out)
+		System.out.println(" # 1. Output filename " + parameter.getOutputFile().toPath().toString()); // NOPMD (System.out)
+		System.out.println(" # 2. Recursion Depth " + parameter.getRecursionDepth()); // NOPMD (System.out)
+		System.out.println(" # 3. Threads " + parameter.getTotalThreads()); // NOPMD (System.out)
+		System.out.println(" # 4. Total-Calls " + parameter.getTotalCalls()); // NOPMD (System.out)
+		System.out.println(" # 5. Method-Time " + parameter.getMethodTime()); // NOPMD (System.out)
 
 		// 2. Initialize Threads and Classes
-		final CountDownLatch doneSignal = new CountDownLatch(BenchmarkMain.totalThreads);
-		final BenchmarkingThread[] benchmarkingThreads = new BenchmarkingThread[BenchmarkMain.totalThreads];
-		final Thread[] threads = new Thread[BenchmarkMain.totalThreads];
-		for (int i = 0; i < BenchmarkMain.totalThreads; i++) {
-			benchmarkingThreads[i] = new BenchmarkingThreadNano(BenchmarkMain.mc, BenchmarkMain.totalCalls,
-					BenchmarkMain.methodTime, BenchmarkMain.recursionDepth, doneSignal);
+		final CountDownLatch doneSignal = new CountDownLatch(parameter.getTotalThreads());
+		final BenchmarkingThread[] benchmarkingThreads = new BenchmarkingThread[parameter.getTotalThreads()];
+		final Thread[] threads = new Thread[parameter.getTotalThreads()];
+		for (int i = 0; i < parameter.getTotalThreads(); i++) {
+			benchmarkingThreads[i] = new BenchmarkingThreadNano(BenchmarkMain.monitoredClass, parameter.getTotalCalls(),
+					parameter.getMethodTime(), parameter.getRecursionDepth(), doneSignal);
 			threads[i] = new Thread(benchmarkingThreads[i], String.valueOf(i + 1));
 		}
-		if (!quickstart) {
+		if (!parameter.isQuickstart()) {
 			for (int l = 0; l < 4; l++) {
 				{ // NOCS (reserve mem only within the block)
 					final long freeMemChunks = Runtime.getRuntime().freeMemory() >> 27;
@@ -91,7 +85,7 @@ public final class BenchmarkMain {
 		final long startTime = System.currentTimeMillis();
 		System.out.println(" # 6. Starting benchmark ..."); // NOPMD (System.out)
 		// 3. Starting Threads
-		for (int i = 0; i < BenchmarkMain.totalThreads; i++) {
+		for (int i = 0; i < parameter.getTotalThreads(); i++) {
 			threads[i].start();
 		}
 
@@ -109,9 +103,9 @@ public final class BenchmarkMain {
 		// 5. Print experiment statistics
 		System.out.print(" # 7. Writing results ... "); // NOPMD (System.out)
 		// CSV Format: configuration;order_index;Thread-ID;duration_nsec
-		for (int h = 0; h < BenchmarkMain.totalThreads; h++) {
+		for (int h = 0; h < parameter.getTotalThreads(); h++) {
 			final BenchmarkingThread thread = benchmarkingThreads[h];
-			for (int i = 0; i < BenchmarkMain.totalCalls; i++) {
+			for (int i = 0; i < parameter.getTotalCalls(); i++) {
 				final String line = threads[h].getName() + ";" + thread.print(i, ";");
 				BenchmarkMain.ps.println(line);
 			}
@@ -121,7 +115,7 @@ public final class BenchmarkMain {
 		System.out.println("done"); // NOPMD (System.out)
 		System.out.println(" # "); // NOPMD (System.out)
 
-		if (forceTerminate) {
+		if (parameter.isForceTerminate()) {
 			System.exit(0);
 		}
 	}
@@ -136,9 +130,9 @@ public final class BenchmarkMain {
 					new BufferedOutputStream(Files.newOutputStream(parameter.getOutputFile().toPath()), 8192 * 8),
 					false, BenchmarkMain.ENCODING);
 			if (null != parameter.getApplicationClassname()) {
-				mc = ((MonitoredClass) Class.forName(parameter.getApplicationClassname()).newInstance());
+				monitoredClass = ((MonitoredClass) Class.forName(parameter.getApplicationClassname()).newInstance());
 			} else {
-				mc = new MonitoredClassThreaded();
+				monitoredClass = new MonitoredClassThreaded();
 			}
 			if (null != parameter.getRunnableClassname()) {
 				((Runnable) Class.forName(parameter.getRunnableClassname()).newInstance()).run();
@@ -146,6 +140,8 @@ public final class BenchmarkMain {
 		} catch (ParameterException ex) {
 			if (commander != null)
 				commander.usage();
+			System.out.println(ex.getLocalizedMessage());
+			System.exit(-1);
 		} catch (final Exception ex) { // NOCS (e.g., IOException, ParseException,
 										// NumberFormatException)
 			if (commander != null) {
diff --git a/benchmark/src/main/java/moobench/benchmark/BenchmarkParameter.java b/benchmark/src/main/java/moobench/benchmark/BenchmarkParameter.java
index 5ffe44f..05eaccd 100644
--- a/benchmark/src/main/java/moobench/benchmark/BenchmarkParameter.java
+++ b/benchmark/src/main/java/moobench/benchmark/BenchmarkParameter.java
@@ -14,17 +14,17 @@ import com.beust.jcommander.converters.FileConverter;
  */
 public class BenchmarkParameter {
 	
-	@Parameter(names = { "--totalCalls", "-c" }, required = true, description = "Number of total method calls performed.")
-	long totalCalls;
+	@Parameter(names = { "--total-calls", "-c" }, required = true, description = "Number of total method calls performed.")
+	int totalCalls;
 	
-	@Parameter(names = { "--methodtime", "-m" }, required = true, description = "Time a method call takes.")
-	long methodTime;
+	@Parameter(names = { "--method-time", "-m" }, required = true, description = "Time a method call takes.")
+	int methodTime;
 	
-	@Parameter(names = { "--totalthreads", "-t" }, required = true, description = "Number of threads started.")
-	long totalThreads;
+	@Parameter(names = { "--total-threads", "-t" }, required = true, description = "Number of threads started.")
+	int totalThreads;
 			
-	@Parameter(names = { "--recursiondepth", "-d" }, required = true, description = "Depth of recursion performed.")
-	long recursionDepth;
+	@Parameter(names = { "--recursion-depth", "-d" }, required = true, description = "Depth of recursion performed.")
+	int recursionDepth;
 
 	@Parameter(names = { "--output-filename", "-o" }, required = true, converter = FileConverter.class, 
 			description = "Filename of results file. Output is appended if file exists.")
@@ -33,7 +33,7 @@ public class BenchmarkParameter {
 	@Parameter(names = { "--quickstart", "-q" }, required = false, description = "Skips initial garbage collection.")
 	boolean quickstart;
 	
-	@Parameter(names = { "--forceTerminate", "-f" }, required = false, description = "Forces a termination at the end of the benchmark.")
+	@Parameter(names = { "--force-terminate", "-f" }, required = false, description = "Forces a termination at the end of the benchmark.")
 	boolean forceTerminate;
     
 	@Parameter(names = { "--runnable", "-r" }, required = false,
@@ -43,22 +43,22 @@ public class BenchmarkParameter {
     @Parameter(names = { "--application", "-a" }, required = false, description = "Class implementing the MonitoredClass interface.")
     String applicationClassname;
     
-    @Parameter(names = { "--benchmarkthread", "-b" }, required = false, description = "Class implementing the BenchmarkingThread interface.")
+    @Parameter(names = { "--benchmark-thread", "-b" }, required = false, description = "Class implementing the BenchmarkingThread interface.")
     String benchmarkClassname;
 
-	public long getTotalCalls() {
+	public int getTotalCalls() {
 		return totalCalls;
 	}
 
-	public long getMethodTime() {
+	public int getMethodTime() {
 		return methodTime;
 	}
 
-	public long getTotalThreads() {
+	public int getTotalThreads() {
 		return totalThreads;
 	}
 
-	public long getRecursionDepth() {
+	public int getRecursionDepth() {
 		return recursionDepth;
 	}
 
diff --git a/frameworks/Kieker/scripts/benchmark.sh b/frameworks/Kieker/scripts/benchmark.sh
index 990204c..abc670b 100755
--- a/frameworks/Kieker/scripts/benchmark.sh
+++ b/frameworks/Kieker/scripts/benchmark.sh
@@ -36,13 +36,13 @@ else
 fi
 
 # test input parameters and configuration
-checkFile R-script "${RSCRIPT_PATH}"
+#checkFile R-script "${RSCRIPT_PATH}"
 checkDirectory DATA_DIR "${DATA_DIR}" create
 
 PARENT=`dirname "${RESULTS_DIR}"`
 checkDirectory result-base "$PARENT"
 checkFile ApsectJ-Agent "${AGENT}"
-checkFile moobench "${MOOBENCH}"
+checkFile moobench "${BENCHMARK}"
 
 information "----------------------------------"
 information "Running benchmark..."
@@ -67,13 +67,13 @@ JAVA_ARGS="-server"
 JAVA_ARGS="${JAVA_ARGS} -d64"
 JAVA_ARGS="${JAVA_ARGS} -Xms1G -Xmx4G"
 
-JAVA_PROGRAM="-jar ${MOOBENCH} ${FIXED_PARAMETERS}"
+JAVA_OPTS="${FIXED_PARAMETERS}"
 
 LTW_ARGS="-javaagent:${AGENT} -Dorg.aspectj.weaver.showWeaveInfo=false -Daj.weaving.verbose=false -Dkieker.monitoring.skipDefaultAOPConfiguration=true -Dorg.aspectj.weaver.loadtime.configuration=${AOP}"
 
 KIEKER_ARGS="-Dlog4j.configuration=log4j.cfg -Dkieker.monitoring.name=KIEKER-BENCHMARK -Dkieker.monitoring.adaptiveMonitoring.enabled=false -Dkieker.monitoring.periodicSensorsExecutorPoolSize=0"
 
-# JAVAARGS used to configure and setup a specific writer
+# JAVA_ARGS used to configure and setup a specific writer
 declare -a WRITER_CONFIG
 # Receiver setup if necessary
 declare -a RECEIVER
@@ -96,11 +96,10 @@ WRITER_CONFIG[3]="-Dkieker.monitoring.enabled=true -Dkieker.monitoring.writer=ki
 TITLE[4]="Logging (Generic Bin)"
 WRITER_CONFIG[4]="-Dkieker.monitoring.enabled=true -Dkieker.monitoring.writer=kieker.monitoring.writer.filesystem.FileWriter -Dkieker.monitoring.writer.filesystem.FileWriter.logStreamHandler=kieker.monitoring.writer.filesystem.BinaryLogStreamHandler -Dkieker.monitoring.writer.filesystem.FileWriter.bufferSize=8192 -Dkieker.monitoring.writer.filesystem.FileWriter.customStoragePath=${DATA_DIR}/"
 
-TITLE[6]="Logging (Single TCP)"
-WRITER_CONFIG[6]="-Dkieker.monitoring.writer=kieker.monitoring.writer.tcp.SingleSocketTcpWriter -Dkieker.monitoring.writer.tcp.SingleSocketTcpWriter.port=2345"
-RECEIVER[6]="${BASE_DIR}/collector-2.0/bin/collector -p 2345"
-
-export COLLECTOR_OPTS="-Dlog4j.configuration=file://${BASE_DIR}/log4j.cfg"
+TITLE[5]="Logging (Single TCP)"
+WRITER_CONFIG[5]="-Dkieker.monitoring.writer=kieker.monitoring.writer.tcp.SingleSocketTcpWriter -Dkieker.monitoring.writer.tcp.SingleSocketTcpWriter.port=2345"
+#RECEIVER[5]="${BASE_DIR}/collector-2.0/bin/collector -p 2345"
+RECEIVER[5]="${BASE_DIR}/receiver/bin/receiver 2345"
 
 # Create R labels
 LABELS=""
@@ -115,9 +114,9 @@ done
 
 ## Write configuration
 uname -a >${RESULTS_DIR}/configuration.txt
-${JAVA_BIN} ${JAVAARGS} -version 2>>${RESULTS_DIR}/configuration.txt
+${JAVA_BIN} ${JAVA_ARGS} -version 2>>${RESULTS_DIR}/configuration.txt
 cat << EOF >>${RESULTS_DIR}/configuration.txt
-JAVAARGS: ${JAVAARGS}
+JAVA_ARGS: ${JAVA_ARGS}
 
 Runtime: circa ${TIME} seconds
 
@@ -149,12 +148,12 @@ function execute-experiment() {
     echo " # ${loop}.${recursion}.${index} ${title}" >> ${DATA_DIR}/kieker.log
 
     if [  "${kieker_parameters}" = "" ] ; then
-       COMPLETE_ARGS=${JAVA_ARGS}
+       BENCHMARK_OPTS=${JAVA_ARGS}
     else
-       COMPLETE_ARGS="${JAVA_ARGS} ${LTW_ARGS} ${KIEKER_ARGS} ${kieker_parameters}"
+       BENCHMARK_OPTS="${JAVA_ARGS} ${LTW_ARGS} ${KIEKER_ARGS} ${kieker_parameters}"
     fi
 
-    ${JAVA_BIN} ${COMPLETE_ARGS} ${JAVA_PROGRAM} \
+    ${BENCHMARK} \
         --output-filename ${RAWFN}-${loop}-${recursion}-${index}.csv \
         --total-calls ${TOTAL_NUM_OF_CALLS} \
         --method-time ${METHOD_TIME} \
diff --git a/frameworks/Kieker/scripts/common-functions b/frameworks/Kieker/scripts/common-functions
index 3d5d389..0ae54df 100644
--- a/frameworks/Kieker/scripts/common-functions
+++ b/frameworks/Kieker/scripts/common-functions
@@ -53,6 +53,7 @@ function checkDirectory() {
 	if [ ! -d "$2" ] ; then
 		if [ "$3" == "create" ] ; then
 			information "$1: directory does not exist, creating it"
+			mkdir $2
 		else
 			error "$1: directory $2 does not exist."
 			exit 1
diff --git a/frameworks/Kieker/scripts/config b/frameworks/Kieker/scripts/config
index 9d0cf7b..e26891f 100644
--- a/frameworks/Kieker/scripts/config
+++ b/frameworks/Kieker/scripts/config
@@ -4,21 +4,21 @@
 # path setup
 JAVA_BIN="java"
 
-RSCRIPT_PATH="${BASE_DIR}/r/stats.csv.r"
+RSCRIPT_PATH="${BASE_DIR}/stats.csv.r"
 
 DATA_DIR="${BASE_DIR}/data"
 RESULTS_DIR="${BASE_DIR}/results-kieker"
-AGENT="${BASE_DIR}/lib/kieker-1.15-SNAPSHOT-aspectj.jar"
-MOOBENCH="${BASE_DIR}/moobench-2.0-all.jar"
+AGENT="${BASE_DIR}/kieker-1.15-SNAPSHOT-aspectj.jar"
+BENCHMARK="${BASE_DIR}/benchmark/bin/benchmark"
 
 # in-jar locations
 AOP="kieker.aop.xml"
 
 # execution parameter
 SLEEP_TIME=30                   ## 30
-NUM_OF_LOOPS=10                 ## 10
+NUM_OF_LOOPS=3                 ## 10
 RECURSION_DEPTH=10              ## 10
-TOTAL_NUM_OF_CALLS=2000000      ## 2 000 000
-METHOD_TIME=500                 ## 500000
+TOTAL_NUM_OF_CALLS=200 #0000      ## 2 000 000
+METHOD_TIME=5 #00                 ## 500000
 
 # end
diff --git a/frameworks/Kieker/scripts/run-benchmark.sh b/frameworks/Kieker/scripts/run-benchmark.sh
old mode 100644
new mode 100755
index 5c130b4..3abad4b
--- a/frameworks/Kieker/scripts/run-benchmark.sh
+++ b/frameworks/Kieker/scripts/run-benchmark.sh
@@ -1,5 +1,52 @@
 #!/bin/bash
 
-echo "No benchmark"
+BASE_DIR=$(cd "$(dirname "$0")"; pwd)
+
+# load configuration and common functions
+if [ -f "${BASE_DIR}/config" ] ; then
+	. ${BASE_DIR}/config
+else
+	echo "Missing configuration: ${BASE_DIR}/config"
+	exit 1
+fi
+if [ -f "${BASE_DIR}/common-functions" ] ; then
+	. ${BASE_DIR}/common-functions
+else
+	echo "Missing configuration: ${BASE_DIR}/common-functions"
+	exit 1
+fi
+
+NUM_OF_REPEATS=1
+export RESULT_FILE="${BASE_DIR}/results-kieker/results-text.csv"
+COLLECTED_DATA_FILE="${BASE_DIR}/results.csv"
+BENCHMARK="${BASE_DIR}/benchmark.sh"
+
+## setup
+# install benchmark
+tar -xvpf ${BASE_DIR}/../../../benchmark/build/distributions/benchmark.tar
+# get agent
+curl "https://oss.sonatype.org/service/local/repositories/snapshots/content/net/kieker-monitoring/kieker/1.15-SNAPSHOT/kieker-1.15-20201102.131525-117-aspectj.jar" > "${AGENT}"
+# copy receiver
+tar -xvpf ${BASE_DIR}/../../../tools/receiver/build/distributions/receiver.tar
+
+mkdir -p ${BASE_DIR}/results-kieker
+
+rm -f ${COLLECTED_DATA_FILE}
+
+## run loop
+for ((v=1;v<=${NUM_OF_REPEATS};v+=1)); do
+	echo "++++++++++++++++++++++++++"
+	echo "Rerun $v"
+	echo "++++++++++++++++++++++++++"
+	${BENCHMARK} # > /dev/null 2>&1
+	HEAD=`head -1 $RESULT_FILE`
+	VALUE=`tail -1 $RESULT_FILE`
+	if [ -f "${COLLECTED_DATA_FILE}" ] ; then
+		echo "$VALUE" >> ${COLLECTED_DATA_FILE}
+	else
+		echo "$HEAD" > ${COLLECTED_DATA_FILE}
+                echo "$VALUE" >> ${COLLECTED_DATA_FILE}
+	fi
+done
 
 # end
diff --git a/frameworks/Kieker/OverheadEvaluationMicrobenchmark/MooBench/r/stats.csv.r b/frameworks/Kieker/scripts/stats.csv.r
similarity index 100%
rename from frameworks/Kieker/OverheadEvaluationMicrobenchmark/MooBench/r/stats.csv.r
rename to frameworks/Kieker/scripts/stats.csv.r
diff --git a/settings.gradle b/settings.gradle
index 36e1432..c132671 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -10,11 +10,8 @@
 rootProject.name = 'moobench'
 
 include 'benchmark'
+include 'tools:receiver'
 include 'frameworks:inspectIT'
-include 'frameworks:Kieker:application'
-include 'frameworks:Kieker:experiment-0'
-include 'frameworks:Kieker:experiment-1'
-include 'frameworks:Kieker:experiment-2'
-include 'frameworks:Kieker:experiment-3'
+include 'frameworks:Kieker'
 include 'frameworks:SPASSmeter'
 
diff --git a/tools/receiver/build.gradle b/tools/receiver/build.gradle
new file mode 100644
index 0000000..a25c25b
--- /dev/null
+++ b/tools/receiver/build.gradle
@@ -0,0 +1,15 @@
+plugins {
+    id 'java'
+    id 'application'
+}
+
+application {
+    mainClass = 'moobench.tools.receiver.RecordReceiver'
+}
+
+dependencies {
+    implementation 'net.kieker-monitoring:kieker:1.14'
+    implementation 'net.sourceforge.teetime:teetime:3.0'
+    implementation 'org.slf4j:slf4j-api:1.7.+'
+    implementation 'ch.qos.logback:logback-classic:1.2.3'  
+}
diff --git a/tools/receiver/src/main/java/moobench/tools/receiver/ReceiverConfiguration.java b/tools/receiver/src/main/java/moobench/tools/receiver/ReceiverConfiguration.java
new file mode 100644
index 0000000..4fb52f4
--- /dev/null
+++ b/tools/receiver/src/main/java/moobench/tools/receiver/ReceiverConfiguration.java
@@ -0,0 +1,15 @@
+package moobench.tools.receiver;
+
+import kieker.analysis.source.tcp.MultipleConnectionTcpSourceStage;
+import kieker.analysisteetime.plugin.filter.forward.CountingFilter;
+import teetime.framework.Configuration;
+
+public class ReceiverConfiguration extends Configuration {
+
+	public ReceiverConfiguration(int inputPort, int bufferSize) {
+		MultipleConnectionTcpSourceStage source = new MultipleConnectionTcpSourceStage(inputPort, bufferSize, null);
+		CountingFilter counting = new CountingFilter();
+		
+		connectPorts(source.getOutputPort(), counting.getInputPort());
+	}
+}
diff --git a/tools/receiver/src/main/java/moobench/tools/receiver/RecordReceiver.java b/tools/receiver/src/main/java/moobench/tools/receiver/RecordReceiver.java
new file mode 100644
index 0000000..fb48fa6
--- /dev/null
+++ b/tools/receiver/src/main/java/moobench/tools/receiver/RecordReceiver.java
@@ -0,0 +1,21 @@
+/**
+ * 
+ */
+package moobench.tools.receiver;
+
+import teetime.framework.Execution;
+
+/**
+ * @author reiner
+ *
+ */
+public class RecordReceiver {
+
+	private RecordReceiver() {}
+
+	public static void main(final String[] args) {
+		ReceiverConfiguration config = new ReceiverConfiguration(Integer.parseInt(args[0]), 8192);
+		Execution<ReceiverConfiguration> execution = new Execution<ReceiverConfiguration>(config);
+		execution.executeBlocking();
+	}
+}
-- 
GitLab