From 361914654c75bb355f44a5819651d6c30e57a4f5 Mon Sep 17 00:00:00 2001
From: Florian Schmaus <flow@cs.fau.de>
Date: Thu, 19 Jul 2018 10:39:34 +0200
Subject: [PATCH] Add Locality eval

---
 eval/CMakeLists.txt |   3 +
 eval/Locality.cpp   | 167 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+)
 create mode 100644 eval/Locality.cpp

diff --git a/eval/CMakeLists.txt b/eval/CMakeLists.txt
index 0d509b0c..d6c2ef0e 100644
--- a/eval/CMakeLists.txt
+++ b/eval/CMakeLists.txt
@@ -3,3 +3,6 @@ target_link_libraries(time_to_spawn Threads::Threads emper)
 
 add_executable(spawn_a_lot SpawnALot.cpp)
 target_link_libraries(spawn_a_lot Threads::Threads emper)
+
+add_executable(locality Locality.cpp)
+target_link_libraries(locality Threads::Threads emper)
diff --git a/eval/Locality.cpp b/eval/Locality.cpp
new file mode 100644
index 00000000..aabca56b
--- /dev/null
+++ b/eval/Locality.cpp
@@ -0,0 +1,167 @@
+#include "Fiber.hpp"
+#include "Runtime.hpp"
+#include "PrivateSemaphore.hpp"
+#include "CountingPrivateSemaphore.hpp"
+#include "LawsStrategy.hpp"
+#include "DebugUtil.hpp"
+
+#include <algorithm>
+#include <random>
+#include <cstdint>
+#include <thread>
+
+#define L1_CACHE_LINE_SIZE 64      // 64 Bytes
+
+#define L1_DCACHE_SIZE (32*1024)   // 32 KiB
+#define L2_DCACHE_SIZE (256*1024)  // 256 KiB
+#define L3_DCACHE_SIZE (4096*1024) // 4 MiB
+
+static std::uniform_int_distribution<> UINT8_UNIFORM_DISTRIBUTION(0, UINT8_MAX);
+
+struct State {
+	const unsigned int fiberCount;
+	const unsigned int bytesPerFiber;
+	const unsigned int rounds;
+
+	Runtime& runtime;
+	std::mt19937 randomGenerator;
+	// TODO: Should the affinities in the affinity array be cache line
+	// aligned to avoid false sharing?
+	workeraffinity_t* affinity;
+	uint8_t* data;
+
+	State(Runtime& runtime,
+		  unsigned int fiberCount,
+		  unsigned int bytesPerFiber,
+		  unsigned int rounds,
+		  unsigned int seed) :
+		fiberCount(fiberCount) ,
+		bytesPerFiber(bytesPerFiber) ,
+		rounds(rounds) ,
+		runtime(runtime) {
+		randomGenerator = std::mt19937(seed);
+		affinity = new workeraffinity_t[fiberCount]();
+		data = new uint8_t[fiberCount * bytesPerFiber];
+
+		std::generate(data, data + fiberCount, [this] { return getNextRandom(); });
+	}
+
+	~State() {
+		delete [] affinity;
+		delete [] data;
+	}
+
+	uint8_t getNextRandom() {
+		return UINT8_UNIFORM_DISTRIBUTION(randomGenerator);
+	}
+};
+
+struct FiberArgs {
+	uint8_t* fiberData;
+	uint8_t roundData;
+	PS* ps;
+	// TODO: Check if this member is still needed
+	State* state;
+
+};
+
+static void performRound(State& state) {
+	uint8_t roundData = state.getNextRandom();
+	CPS cps(state.fiberCount);
+
+	FiberArgs* fiberArgs = new FiberArgs[state.fiberCount];
+
+	for (unsigned int i = 0; i < state.fiberCount; ++i) {
+		fiberArgs[i].fiberData = state.data + (i * state.bytesPerFiber);
+		fiberArgs[i].roundData = roundData;
+		fiberArgs[i].ps = &cps;
+		fiberArgs[i].state = &state;
+
+		Fiber* fiber = Fiber::from([](void* fiberArgsPtr) {
+				FiberArgs* fiberArgs = (FiberArgs*) fiberArgsPtr;
+
+				uint8_t* fiberData = fiberArgs->fiberData;
+				unsigned int bytesPerFiber = fiberArgs->state->bytesPerFiber;
+				// 75% Chance that this fiber will do work.
+				if (fiberData[0] < 192) {
+					for (unsigned int i = 0; i < bytesPerFiber; i++) {
+						fiberData[i] += fiberArgs->roundData;
+						if (fiberData[i] < 128) {
+							fiberData[i] += fiberArgs->roundData / 2;
+						}
+						if (fiberData[i] > 192) {
+							fiberData[i] -= (fiberArgs->roundData * 4);
+						}
+					}
+				}
+
+				fiberArgs->ps->signal();
+			}, (void*) (fiberArgs + i), state.affinity + i);
+
+		state.runtime.schedule(*fiber);
+	}
+
+	cps.wait();
+
+	delete [] fiberArgs;
+}
+
+
+static void run(Runtime& runtime,
+				unsigned int fiberCount,
+				unsigned int bytesPerFiber,
+				unsigned int rounds,
+				unsigned int seed) {
+
+	runtime.executeAndWait([&] {
+			State state(runtime, fiberCount, bytesPerFiber, rounds, seed);
+			for (unsigned int i = 0; i < state.rounds; ++i) {
+				performRound(state);
+			}
+		});
+}
+
+int main(UNUSED_ARG int argc, UNUSED_ARG char *argv[]) {
+	enableStacktraceOnAborts();
+
+	const unsigned int coreCount = 4;
+	const unsigned int bytesPerFiber = L1_DCACHE_SIZE / 4;
+	const unsigned int fiberCount = coreCount * 6;
+	const unsigned int rounds = 10;
+	const unsigned int seed = 42;
+
+	std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
+	std::chrono::microseconds diff;
+
+	{
+		Runtime runtime;
+
+		start = std::chrono::high_resolution_clock::now();
+		run(runtime, fiberCount, bytesPerFiber, rounds, seed);
+		end = std::chrono::high_resolution_clock::now();
+		diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
+		std::cout << "W/o Locality: "
+				  <<  diff.count() << " us"
+				  << std::endl;
+	}
+
+	{
+		using namespace std::chrono_literals;
+		std::cout << "Sleeping for 2s" << std::endl;
+		std::this_thread::sleep_for(2s);
+		std::cout << "Done sleeping" << std::endl;
+	}
+
+	{
+		RuntimeStrategy& lawsStrategy = LawsStrategy::INSTANCE;
+		Runtime runtime(lawsStrategy);
+
+		start = std::chrono::high_resolution_clock::now();
+		run(runtime, fiberCount, bytesPerFiber, rounds, seed);
+		end = std::chrono::high_resolution_clock::now();
+		diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
+		std::cout << "W   Locality: "
+				  <<  diff.count() << " us"
+				  << std::endl;
+	}
+}
-- 
GitLab