Skip to content
Snippets Groups Projects
Locality.cpp 7.77 KiB
Newer Older
  • Learn to ignore specific revisions
  • // SPDX-License-Identifier: LGPL-3.0-or-later
    // Copyright © 2020 Florian Schmaus
    #include <unistd.h>	 // for getopt, optarg
    
    #include <algorithm>	// for generate
    #include <chrono>			// for microseconds, high_resol...
    #include <cstdint>		// for uint8_t, UINT8_MAX
    
    #include <cstdlib>		// for abort, exit, EXIT_SUCCESS
    
    #include <iostream>		// for operator<<, basic_ostream
    #include <random>			// for mt19937, uniform_int_dis...
    #include <string>			// for string, operator<<, oper...
    
    #include "CountingPrivateSemaphore.hpp"			 // for CPS
    #include "Debug.hpp"												 // for DBG
    #include "Fiber.hpp"												 // for Fiber, Fiber::NOT_AFFINE
    #include "PrivateSemaphore.hpp"							 // for PS
    #include "Runtime.hpp"											 // for Runtime
    #include "emper-common.h"										 // for workeraffinity_t, UNUSED...
    #include "lib/DebugUtil.hpp"								 // for enableStacktraceOnAborts
    #include "strategies/laws/LawsStrategy.hpp"	 // for LawsStrategy, LawsStrate...
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    
    #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
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    static std::uniform_int_distribution<> UINT8_UNIFORM_DISTRIBUTION(0, UINT8_MAX);
    
    
    struct FiberMetadata {
    	workerid_t workerId;
    	workeraffinity_t currentAffinity;
    	std::chrono::time_point<std::chrono::high_resolution_clock> start;
    	std::chrono::time_point<std::chrono::high_resolution_clock> end;
    };
    
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    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;
    
    	// std::map<unsigned int, std::vector<FiberMetadata>> fiberMetadata;
    
    
    	// NOLINTNEXTLINE(cert-msc32-c,cert-msc51-cpp)
    
    	State(Runtime& runtime, unsigned int fiberCount, unsigned int bytesPerFiber, unsigned int rounds,
    				unsigned int seed)
    			: fiberCount(fiberCount), bytesPerFiber(bytesPerFiber), rounds(rounds), runtime(runtime) {
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    		randomGenerator = std::mt19937(seed);
    
    		affinity = new workeraffinity_t[fiberCount];
    		for (unsigned int i = 0; i < fiberCount; ++i) {
    			affinity[i] = Fiber::NOT_AFFINE;
    		}
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    		data = new uint8_t[fiberCount * bytesPerFiber];
    
    #ifdef FIBER_METADATA
    		fiberMetadata = new FiberMetadata[fiberCount * rounds];
    #endif
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    		std::generate(data, data + fiberCount, [this] { return getNextRandom(); });
    	}
    
    	~State() {
    
    	auto getNextRandom() -> uint8_t { return UINT8_UNIFORM_DISTRIBUTION(randomGenerator); }
    
    	[[nodiscard]] auto getFiberMetadata(unsigned int fiberNum, unsigned int roundNum) const
    			-> FiberMetadata* {
    
    		return fiberMetadata + (fiberNum * fiberCount) + roundNum;
    	}
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    };
    
    struct FiberArgs {
    	uint8_t* fiberData;
    	uint8_t roundData;
    	PS* ps;
    	// TODO: Check if this member is still needed
    	State* state;
    
    #ifdef FIBER_METADATA
    	FiberMetadata* fiberMetadata;
    #endif
    
    static void performRound(State& state,
    #ifndef FIBER_METADATA
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	uint8_t roundData = state.getNextRandom();
    	CPS cps(state.fiberCount);
    
    
    	auto* fiberArgs = new FiberArgs[state.fiberCount];
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	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;
    
    #ifdef FIBER_METADATA
    		fiberArgs[i].fiberMetadata = state.getFiberMetadata(i, round);
    #endif
    
    		Fiber* fiber = Fiber::from(
    				[](void* fiberArgsPtr) {
    
    					auto* fiberArgs = (FiberArgs*)fiberArgsPtr;
    
    					FiberMetadata* fiberMetadata = fiberArgs->fiberMetadata;
    
    					fiberMetadata->start = std::chrono::high_resolution_clock::now();
    					fiberMetadata->workerId = Runtime::getWorkerId();
    					fiberMetadata->currentAffinity = Dispatcher::getCurrentFiber().getAffinity();
    
    					uint8_t* fiberData = fiberArgs->fiberData;
    					unsigned int bytesPerFiber = fiberArgs->state->bytesPerFiber;
    					for (unsigned int j = (bytesPerFiber - 1); j > (bytesPerFiber - 10); --j) {
    						for (unsigned int i = 0; i < bytesPerFiber; i++) {
    							unsigned int next = (i + L1_DCACHE_SIZE + fiberData[j]) % bytesPerFiber;
    							fiberData[i] -= fiberData[next];
    
    							fiberData[i] += fiberArgs->roundData;
    							/*
    							if (fiberData[i] < 128) {
    								fiberData[i] += fiberArgs->roundData / 2;
    							}
    							if (fiberData[i] > 192) {
    								fiberData[i] -= (fiberArgs->roundData * 4);
    							}
    
    							if (i == (bytesPerFiber * 0.75)) {
    								if (fiberData[i] < 128) {
    									break;
    								}
    							}
    							*/
    
    					fiberMetadata->end = std::chrono::high_resolution_clock::now();
    
    					fiberArgs->ps->signal();
    				},
    				(void*)(fiberArgs + i), state.affinity + i);
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    		state.runtime.schedule(*fiber);
    	}
    
    	cps.wait();
    
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    /*
    
    IGNORE_UNUSED_FUNCTION
    static void printState(State& state) {
    	std::ostream& ostream = std::cout;
    	for (unsigned int fiberNum = 0; fiberNum < state.fiberCount; ++fiberNum) {
    		for (unsigned int roundNum = 0; roundNum < state.rounds; ++roundNum) {
    			FiberMetadata* fiberMetadata = state.getFiberMetadata(fiberNum, roundNum);
    
    			ostream << fiberNum
    					<< ", " << roundNum
    					<< ", " << fiberMetadata->workerId
    					<< ", " << fiberMetadata->currentAffinity
    					<< ", " << fiberMetadata->start.time_since_epoch().count()
    					<< ", " << fiberMetadata->end.time_since_epoch().count()
    					<< std::endl;
    		}
    	}
    }
    POP_DIAGNOSTIC
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    */
    
    static void run(Runtime& runtime, unsigned int fiberCount, unsigned int bytesPerFiber,
    								unsigned int rounds, unsigned int seed) {
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	runtime.executeAndWait([&] {
    
    		State state(runtime, fiberCount, bytesPerFiber, rounds, seed);
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    
    		auto start = std::chrono::high_resolution_clock::now();
    		for (unsigned int i = 0; i < state.rounds; ++i) {
    			performRound(state, i);
    		}
    		auto end = std::chrono::high_resolution_clock::now();
    
    		auto diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    
    		std::cout << "Inner " << diff.count() << " us" << std::endl;
    		// printState(state);
    	});
    
    auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int {
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	enableStacktraceOnAborts();
    
    
    	RuntimeVariant runtimeVariant = ws;
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	unsigned int rounds = 10;
    
    	unsigned int seed = 4231;
    
    
    	int opt;
    	while ((opt = getopt(argc, argv, "m:")) != -1) {
    		std::string optargString;
    		switch (opt) {
    
    			case 'm':
    				optargString = std::string(optarg);
    				if (optargString == "ws") {
    					runtimeVariant = ws;
    				} else if (optargString == "wslh") {
    					runtimeVariant = wslh;
    				} else {
    					std::cerr << "Invalid -m argument " << optargString << std::endl;
    					abort();
    				}
    				break;
    			default:
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	unsigned int coreCount = 80;
    
    	unsigned int bytesPerFiber = L1_DCACHE_SIZE / 2;
    	unsigned int fiberCount = coreCount * 4;
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    
    	std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
    
    
    	Runtime* runtime;
    	switch (runtimeVariant) {
    
    		case ws:
    			runtime = new Runtime();
    			break;
    		case wslh:
    			runtime = new Runtime(LawsStrategy::INSTANCE);
    			break;
    
    	start = std::chrono::high_resolution_clock::now();
    	run(*runtime, fiberCount, bytesPerFiber, rounds, seed);
    	end = std::chrono::high_resolution_clock::now();
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    	auto diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    
    
    	std::string variantName;
    	switch (runtimeVariant) {
    
    		case ws:
    			variantName = "W/o Locality: ";
    			break;
    		case wslh:
    			variantName = "W   Locality: ";
    			break;
    
    	std::cout << variantName << diff.count() << " us" << std::endl;
    
    Florian Schmaus's avatar
    Florian Schmaus committed
    }