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