Skip to content
Snippets Groups Projects
SimpleLawsTest.cpp 3.27 KiB
Newer Older
  • Learn to ignore specific revisions
  • // SPDX-License-Identifier: LGPL-3.0-or-later
    
    // Copyright © 2020-2022 Florian Schmaus
    
    #include <atomic>
    #include <cstdint>
    #include <cstdlib>
    #include <cstring>
    #include <functional>
    #include <iostream>
    #include <random>
    
    #include "Common.hpp"										 // for ALIGN_TO_CACHE_LINE
    #include "CountingPrivateSemaphore.hpp"	 // for CPS
    #include "Fiber.hpp"										 // for Fiber, Fiber::NOT_AFFINE
    #include "Runtime.hpp"									 // for Runtime
    #include "emper-common.h"								 // for UNUSED_ARG, workeraffini...
    
    #include "strategies/laws/LawsStrategy.hpp"
    
    namespace tu = emper::lib::template_util;
    
    
    static const unsigned int ROUND_COUNT = 10;
    static const unsigned int FIBER_LOOPS = 10;
    static const unsigned int PAYLOAD_COUNT = 4096;
    
    using FiberData = struct ALIGN_TO_CACHE_LINE {
    
    	// 4096 * 8 byte (64 bit) = 32 KiB = L1 cache size of most systems
    
    	std::array<uint64_t, PAYLOAD_COUNT> payload;
    
    	CPS* cps;
    	unsigned int fiberNum;
    
    using AlignedWorkerAffinity = struct ALIGN_TO_CACHE_LINE { workeraffinity_t affinity; };
    
    
    static void fiberFun(void* voidFiberData) {
    
    	auto* fiberData = static_cast<FiberData*>(voidFiberData);
    
    
    	std::random_device randomDevice;
    	std::mt19937_64 randomGenerator(randomDevice());
    	std::uniform_int_distribution<unsigned long long> randomDistribution(0, UINT64_MAX);
    
    	for (unsigned int i = 0; i < FIBER_LOOPS; ++i) {
    
    		for (unsigned long& j : fiberData->payload) {
    
    			unsigned long long r = randomDistribution(randomGenerator);
    
    			j += r;
    
    		}
    	}
    
    	fiberData->cps->signalAndExit();
    }
    
    static void alphaFun() {
    	Runtime* runtime = Runtime::getRuntime();
    	const unsigned int FIBER_COUNT = runtime->getWorkerCount() + 3;
    
    
    	auto* affinities = new AlignedWorkerAffinity[FIBER_COUNT];
    	auto* fiberData = new FiberData[FIBER_COUNT];
    
    
    	for (unsigned int i = 0; i < FIBER_COUNT; ++i) {
    		FiberData& currentFiberData = fiberData[i];
    
    		auto& payload = currentFiberData.payload;
    		memset(payload.data(), 0, tu::getSize(payload));
    
    
    		currentFiberData.fiberNum = i;
    		currentFiberData.cps = nullptr;
    
    
    		affinities[i].affinity = Fiber::NOT_AFFINE;
    
    	}
    
    	for (unsigned int round = 0; round < ROUND_COUNT; ++round) {
    		CPS cps(FIBER_COUNT);
    		for (unsigned int i = 0; i < FIBER_COUNT; ++i) {
    			FiberData* myFiberData = &fiberData[i];
    			myFiberData->cps = &cps;
    
    			Fiber* fiber = Fiber::from(&fiberFun, myFiberData, &affinities[i].affinity);
    
    			runtime->schedule(*fiber);
    		}
    		cps.wait();
    	}
    
    	std::atomic<uint64_t> finalResult(0);
    	CPS cps(FIBER_COUNT);
    	for (unsigned int i = 0; i < FIBER_COUNT; ++i) {
    		FiberData* myFiberData = &fiberData[i];
    		myFiberData->cps = &cps;
    
    		Fiber* fiber = Fiber::from(
    				[myFiberData, &finalResult]() {
    					uint64_t mySum = 0;
    
    					for (unsigned long i : myFiberData->payload) {
    						mySum += i;
    
    					}
    					finalResult += mySum;
    
    					myFiberData->cps->signalAndExit();
    				},
    				&affinities[i].affinity);
    
    		runtime->schedule(*fiber);
    	}
    
    	delete[] fiberData;
    	delete[] affinities;
    
    
    	std::cerr << "Result: " << finalResult << std::endl;
    
    	exit(EXIT_SUCCESS);
    }
    
    
    auto main(UNUSED_ARG int args, UNUSED_ARG char* argv[]) -> int {
    
    	Runtime runtime(LawsStrategy::getFactory());
    
    
    	Fiber* alphaFiber = Fiber::from(&alphaFun);
    
    
    	runtime.scheduleFromAnywhere(*alphaFiber);
    
    
    	runtime.waitUntilFinished();