diff --git a/emper/Common.hpp b/emper/Common.hpp index c404def401bf4619a7fc466e468748b47155efdb..351a194b89456494b41741a9008fe79c82b50d11 100644 --- a/emper/Common.hpp +++ b/emper/Common.hpp @@ -36,7 +36,7 @@ using func_t = std::function<void()>; using WORD = unsigned int; #ifdef EMPER_STATS -#include <chrono> +#include <chrono> // IWYU pragma: keep #define TIME_NS(code, record_func) \ auto _time_ns_start = std::chrono::high_resolution_clock::now(); \ code; \ diff --git a/emper/Emper.hpp b/emper/Emper.hpp index 2bfbf49f739dd04d5a0418db7f96a5490b6079e6..9c7e0664fa62e4adf249adfdfb2a0ae9392799ec 100644 --- a/emper/Emper.hpp +++ b/emper/Emper.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus +// Copyright © 2020-2021 Florian Schmaus #pragma once #include <string> @@ -16,6 +16,13 @@ static const bool STATS = #endif ; +template <typename C> +void statsIncr(C& counter) { + if constexpr (STATS) { + counter++; + } +} + static const bool WORKER_SLEEP = #ifdef EMPER_WORKER_SLEEP true diff --git a/emper/Runtime.cpp b/emper/Runtime.cpp index 9969fcc03453f7ea3251fd65deda234b6450b507..d604ceb826beecd4d3384ede40d6932cc6343ef7 100644 --- a/emper/Runtime.cpp +++ b/emper/Runtime.cpp @@ -11,8 +11,8 @@ #include <cstdlib> // for rand, srand, abort #include <cstring> +#include <iostream> #include <memory> // for __shared_ptr_access, shared_ptr -#include <ostream> #include <string> // for string #include <thread> @@ -67,7 +67,8 @@ using emper::io::IoContext; Runtime::Runtime(workerid_t workerCount, RuntimeStrategyFactory& strategyFactory, unsigned int seed) : workerCount(workerCount), workerLatch(workerCount), - workerThreadExitLatch(workerCount), + firstWorkerThreadExitLatch(workerCount), + secondWorkerThreadExitLatch(workerCount), strategy(strategyFactory.constructRuntimeStrategy(*this)), scheduler(strategy->getScheduler()), dispatcher(strategy->getDispatcher()), @@ -236,7 +237,14 @@ auto Runtime::workerLoop(Worker* worker) -> void* { // it would be possible that one thread is work-stealing, // potentially accessing a work stealing queue of an worker thread // that already exited, causing an invalid access. - workerThreadExitLatch.count_down_and_wait(); + firstWorkerThreadExitLatch.count_down_and_wait(); + + if (worker->getWorkerId() == 0) { + // Obtain stats when all workers reached the first latch but before they exit. + strategyLastStats = strategy->getStats(); + } + + secondWorkerThreadExitLatch.count_down_and_wait(); return nullptr; } @@ -312,8 +320,31 @@ void Runtime::initiateAndWaitUntilTermination() { } void Runtime::printStats() { - auto runtimeStrategyStats = strategy->getStats(); - runtimeStrategyStats->print(); + if constexpr (!emper::STATS) { + std::cout << "printStats(): EMPER stats disabled by static configuration" << std::endl; + return; + } + + std::shared_ptr<RuntimeStrategyStats> stats; + if (terminateWorkers) { + // The runtime was already requested to shut down. We can not + // obtain stats as it is not guranteed that the worker threads are + // still running in this case. We can however check + // strategyLastStats and print that. + + if (strategyLastStats) { + stats = strategyLastStats; + } else { + std::cerr << "printStats(): worker threads have already been scheduled for termination, but " + "not last stats recored yet." + << std::endl; + return; + } + } else { + stats = strategy->getStats(); + } + + stats->print(); } void Runtime::printLastRuntimeStats() { diff --git a/emper/Runtime.hpp b/emper/Runtime.hpp index 621eda413c7a46cd1121d1845b6e25646b873ecf..993bd24f177af0c553180229190d3ffca27f7d60 100644 --- a/emper/Runtime.hpp +++ b/emper/Runtime.hpp @@ -9,7 +9,8 @@ #include <cstdint> // for intptr_t #include <cstdlib> // for abort #include <functional> // for function -#include <mutex> // for mutex, lock_guard, unique_lock +#include <memory> +#include <mutex> #include <random> #include <vector> // for vector @@ -31,6 +32,7 @@ class Dispatcher; class Fiber; class RuntimeStrategy; class RuntimeStrategyFactory; +class RuntimeStrategyStats; namespace emper::io { class GlobalIoContext; @@ -51,7 +53,8 @@ class Runtime : public Logger<LogSubsystem::RUNTI> { std::vector<std::function<void(workerid_t)>> newWorkerHooks; Latch workerLatch; - Latch workerThreadExitLatch; + Latch firstWorkerThreadExitLatch; + Latch secondWorkerThreadExitLatch; RuntimeStrategy* const strategy; Scheduler& scheduler; @@ -70,6 +73,8 @@ class Runtime : public Logger<LogSubsystem::RUNTI> { bool threadsRunning = false; + std::shared_ptr<RuntimeStrategyStats> strategyLastStats; + auto workerLoop(Worker* worker) -> void*; ALIGN_TO_CACHE_LINE WorkerWakeupSemaphore wakeupSem; @@ -221,4 +226,6 @@ class Runtime : public Logger<LogSubsystem::RUNTI> { friend IoContext; template <typename T, intptr_t WS_QUEUE_SIZE, size_t WORKER_EXCLUSIVE_QUEUE_SIZE> friend class MemoryManager; + template <typename> + friend class WorkerLocalData; }; diff --git a/emper/WorkerLocalData.hpp b/emper/WorkerLocalData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a1adbb602845393170328f4554001e483cc8a928 --- /dev/null +++ b/emper/WorkerLocalData.hpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Schmaus +#pragma once + +#include <functional> + +#include "Runtime.hpp" + +template <typename D> +class WorkerLocalData { + private: + std::function<D*(void)> getWorkerLocalPtrCallback; + std::vector<D*> workerLocalData; + + public: + WorkerLocalData(std::function<D*(void)> getWorkerLocalPtrCallback, Runtime& runtime) + : getWorkerLocalPtrCallback(getWorkerLocalPtrCallback) { + auto workerCount = runtime.getWorkerCount(); + workerLocalData = std::vector<D*>(workerCount); + runtime.addNewWorkerHook([this, getWorkerLocalPtrCallback](workerid_t workerId) { + D* workerLocalDataPtr = getWorkerLocalPtrCallback(); + this->workerLocalData.at(workerId) = workerLocalDataPtr; + }); + } + + auto getSnapshot() -> std::vector<D> { + std::vector<D> res; + for (D* data : workerLocalData) { + res.emplace_back(*data); + } + return res; + } + + void forEach(std::function<void(D*)> callback) { + for (D* data : workerLocalData) { + callback(data); + } + } +}; diff --git a/emper/strategies/AbstractWorkStealingScheduler.cpp b/emper/strategies/AbstractWorkStealingScheduler.cpp index d78614a68ef0fe2d8e39977af8acf645536b12e2..7ca3722796e8608d64b33f41a2bbd59ce4457c32 100644 --- a/emper/strategies/AbstractWorkStealingScheduler.cpp +++ b/emper/strategies/AbstractWorkStealingScheduler.cpp @@ -2,7 +2,6 @@ // Copyright © 2021 Florian Schmaus #include "AbstractWorkStealingScheduler.hpp" -#include <atomic> #include <ostream> // for operator<<, basic_ostream<>::__ostream_type #include "Common.hpp" // for unlikely, likely @@ -12,15 +11,17 @@ #include "Runtime.hpp" // for Runtime #include "emper-common.h" // for workerid_t #include "strategies/AbstractWorkStealingStrategy.hpp" +#include "strategies/AbstractWorkStealingWorkerStats.hpp" class Fiber; +using awss = AbstractWorkStealingStrategy; + thread_local AbstractWorkStealingScheduler::WsQueue<AbstractWorkStealingScheduler::QUEUE_SIZE> AbstractWorkStealingScheduler::queue; -AbstractWorkStealingScheduler::AbstractWorkStealingScheduler( - Runtime& runtime, AbstractWorkStealingStrategy& abstractWorkStealingStrategy) - : Scheduler(runtime), abstractWorkStealingStrategy(abstractWorkStealingStrategy) { +AbstractWorkStealingScheduler::AbstractWorkStealingScheduler(Runtime& runtime) + : Scheduler(runtime) { const workerid_t workerCount = runtime.getWorkerCount(); queues = new AbstractWorkStealingScheduler::WsQueue<QUEUE_SIZE>*[workerCount]; @@ -34,17 +35,12 @@ void AbstractWorkStealingScheduler::scheduleViaWorkStealing(Fiber& fiber) { if constexpr (emper::OVERFLOW_QUEUE) { enqueueInAnywhereQueue(fiber); - if constexpr (emper::STATS) { - // TODO: Use template magic so that this becomes - // incrementRelaxed(abstractWorkStealingStrategy.scheduledFibersToLocal) - abstractWorkStealingStrategy.scheduledFibersToOverflowQueue.fetch_add( - 1, std::memory_order_relaxed); - } + emper::statsIncr(awss::stats.scheduledFibersToOverflowQueue); } else { ABORT("Could not push fiber " << &fiber << " into queue"); } } else if constexpr (emper::STATS) { - abstractWorkStealingStrategy.scheduledFibersToLocal.fetch_add(1, std::memory_order_relaxed); + awss::stats.scheduledFibersToLocal++; } // Classes using this method are supposed to always invoke this @@ -58,9 +54,7 @@ auto AbstractWorkStealingScheduler::nextFiberViaWorkStealing() -> std::pair<Fibe bool poped = queue.popBottom(&fiber); if (likely(poped)) { - if constexpr (emper::STATS) { - abstractWorkStealingStrategy.nextFiberFromLocal.fetch_add(1, std::memory_order_relaxed); - } + emper::statsIncr(awss::stats.nextFiberFromLocal); goto out; } @@ -78,9 +72,7 @@ auto AbstractWorkStealingScheduler::nextFiberViaWorkStealing() -> std::pair<Fibe poped = queues[victim]->popTop(&fiber); if (poped) { - if constexpr (emper::STATS) { - abstractWorkStealingStrategy.nextFiberStolen.fetch_add(1, std::memory_order_relaxed); - } + emper::statsIncr(awss::stats.nextFiberStolen); fiberSource = FiberSource::stolen; goto out; @@ -91,10 +83,7 @@ auto AbstractWorkStealingScheduler::nextFiberViaWorkStealing() -> std::pair<Fibe // Try the "scheduled from anywhere" queue to get work as last resort. fiber = dequeueFiberFromAnywhereQueue(); if (fiber) { - if constexpr (emper::STATS) { - abstractWorkStealingStrategy.nextFiberFromAnywhereQueue.fetch_add(1, - std::memory_order_relaxed); - } + emper::statsIncr(awss::stats.nextFiberFromAnywhereQueue); fiberSource = FiberSource::anywhereQueue; } diff --git a/emper/strategies/AbstractWorkStealingScheduler.hpp b/emper/strategies/AbstractWorkStealingScheduler.hpp index ce0d378da7666a863242cd1d64233cd130e7b205..64071b71c28f8572aac2c7165bbd18711f50b5f1 100644 --- a/emper/strategies/AbstractWorkStealingScheduler.hpp +++ b/emper/strategies/AbstractWorkStealingScheduler.hpp @@ -8,7 +8,6 @@ #include "NextFiberResult.hpp" #include "Scheduler.hpp" -#include "emper-common.h" #ifdef EMPER_LOCKED_WS_QUEUE #include "lib/adt/LockedQueue.hpp" @@ -18,7 +17,6 @@ class Fiber; class Runtime; -class AbstractWorkStealingStrategy; class AbstractWorkStealingScheduler : public Scheduler { template <size_t SIZE> @@ -28,16 +26,6 @@ class AbstractWorkStealingScheduler : public Scheduler { using WsQueue = adt::WsClQueue<Fiber*, SIZE>; #endif - private: -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" - AbstractWorkStealingStrategy& abstractWorkStealingStrategy -#ifndef EMPER_STATS - ATTR_UNUSED -#endif - ; -#pragma GCC diagnostic pop - public: static const int QUEUE_SIZE = 1024; @@ -58,6 +46,5 @@ class AbstractWorkStealingScheduler : public Scheduler { auto nextFiberResultViaWorkStealing() -> NextFiberResult; public: - AbstractWorkStealingScheduler(Runtime& runtime, - AbstractWorkStealingStrategy& abstractWorkStealingStrategy); + AbstractWorkStealingScheduler(Runtime& runtime); }; diff --git a/emper/strategies/AbstractWorkStealingStats.cpp b/emper/strategies/AbstractWorkStealingStats.cpp index 7d6c5860f859925eeb53937cf3d28d10b540506f..a8e833eebb641485b69a61799a8e7adcfe09ff5d 100644 --- a/emper/strategies/AbstractWorkStealingStats.cpp +++ b/emper/strategies/AbstractWorkStealingStats.cpp @@ -2,23 +2,28 @@ // Copyright © 2021 Florian Schmaus #include "strategies/AbstractWorkStealingStats.hpp" -#include <atomic> #include <iostream> +#include <string> +#include "WorkerLocalData.hpp" #include "strategies/AbstractWorkStealingStrategy.hpp" AbstractWorkStealingStats::AbstractWorkStealingStats(AbstractWorkStealingStrategy& strategy) - : scheduledFibersToLocal(strategy.scheduledFibersToLocal), - scheduledFibersToOverflowQueue(strategy.scheduledFibersToOverflowQueue), - nextFiberFromLocal(strategy.nextFiberFromLocal), - nextFiberStolen(strategy.nextFiberStolen), - nextFiberFromAnywhereQueue(strategy.nextFiberFromAnywhereQueue) {} + : workerStats(strategy.allWorkerStats.getSnapshot()) { + for (auto& workerStat : workerStats) { + comulatedWorkerStats += workerStat; + } +} void AbstractWorkStealingStats::print() { - std::cout << "AbstractWorkStealingStats" - << " scheduledFibersToLocal:" << scheduledFibersToLocal - << " scheduledFibersToOverflowQueue:" << scheduledFibersToOverflowQueue - << " nextFiberFromLocal:" << nextFiberFromLocal - << " nextFiberStolen:" << nextFiberStolen - << " nextFiberFromAnywhereQueue:" << nextFiberFromAnywhereQueue << std::endl; + std::cout << "total-scheduled-fibers-to-local: " + << std::to_string(comulatedWorkerStats.scheduledFibersToLocal) << std::endl + << "total-scheduled-fibers-to-overflow-queue: " + << std::to_string(comulatedWorkerStats.scheduledFibersToOverflowQueue) << std::endl + << "total-next-fiber-from-local: " + << std::to_string(comulatedWorkerStats.nextFiberFromLocal) << std::endl + << "total-next-fiber-stolen: " << std::to_string(comulatedWorkerStats.nextFiberStolen) + << std::endl + << "total-next-fiber-from-anywhere-queue: " + << std::to_string(comulatedWorkerStats.nextFiberFromAnywhereQueue) << std::endl; } diff --git a/emper/strategies/AbstractWorkStealingStats.hpp b/emper/strategies/AbstractWorkStealingStats.hpp index a5f86150edfea1d88e5967c2b4061ffd6c9fecd1..f8d19002993b517860908451ea91db41838e2418 100644 --- a/emper/strategies/AbstractWorkStealingStats.hpp +++ b/emper/strategies/AbstractWorkStealingStats.hpp @@ -2,19 +2,17 @@ // Copyright © 2021 Florian Schmaus #pragma once -#include <cstdint> +#include <vector> #include "RuntimeStrategyStats.hpp" +#include "strategies/AbstractWorkStealingWorkerStats.hpp" class AbstractWorkStealingStrategy; class AbstractWorkStealingStats : public RuntimeStrategyStats { public: - const uint64_t scheduledFibersToLocal; - const uint64_t scheduledFibersToOverflowQueue; - const uint64_t nextFiberFromLocal; - const uint64_t nextFiberStolen; - const uint64_t nextFiberFromAnywhereQueue; + std::vector<AbstractWorkStealingWorkerStats> workerStats; + AbstractWorkStealingWorkerStats comulatedWorkerStats; AbstractWorkStealingStats(AbstractWorkStealingStrategy &strategy); diff --git a/emper/strategies/AbstractWorkStealingStrategy.cpp b/emper/strategies/AbstractWorkStealingStrategy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee866d13211dba27a2daa883b10f5e489db95851 --- /dev/null +++ b/emper/strategies/AbstractWorkStealingStrategy.cpp @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021 Florian Schmaus +#include "strategies/AbstractWorkStealingStrategy.hpp" + +#include "strategies/AbstractWorkStealingWorkerStats.hpp" + +thread_local AbstractWorkStealingWorkerStats AbstractWorkStealingStrategy::stats; diff --git a/emper/strategies/AbstractWorkStealingStrategy.hpp b/emper/strategies/AbstractWorkStealingStrategy.hpp index 090b7ffb48706e2428bd0ac1a1e62e1cfd25122d..597ab09b6061eaae9488d0612b03a37e33a1982d 100644 --- a/emper/strategies/AbstractWorkStealingStrategy.hpp +++ b/emper/strategies/AbstractWorkStealingStrategy.hpp @@ -1,25 +1,26 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus +// Copyright © 2020-2021 Florian Schmaus #pragma once -#include <atomic> -#include <cstdint> -#include <memory> +#include <functional> #include "RuntimeStrategy.hpp" +#include "WorkerLocalData.hpp" class AbstractWorkStealingScheduler; class AbstractWorkStealingStats; +class Runtime; +struct AbstractWorkStealingWorkerStats; class AbstractWorkStealingStrategy : public RuntimeStrategy { + public: private: - std::atomic<std::uint64_t> scheduledFibersToLocal; - std::atomic<std::uint64_t> scheduledFibersToOverflowQueue; - std::atomic<std::uint64_t> nextFiberFromLocal; - std::atomic<std::uint64_t> nextFiberStolen; - std::atomic<std::uint64_t> nextFiberFromAnywhereQueue; + static thread_local AbstractWorkStealingWorkerStats stats; + + WorkerLocalData<AbstractWorkStealingWorkerStats> allWorkerStats; protected: + AbstractWorkStealingStrategy(Runtime& runtime) : allWorkerStats([] { return &stats; }, runtime) {} ~AbstractWorkStealingStrategy() override = default; friend AbstractWorkStealingScheduler; diff --git a/emper/strategies/AbstractWorkStealingWorkerStats.hpp b/emper/strategies/AbstractWorkStealingWorkerStats.hpp new file mode 100644 index 0000000000000000000000000000000000000000..19394a5addc712609dcafae4ad4eef1bc63019c9 --- /dev/null +++ b/emper/strategies/AbstractWorkStealingWorkerStats.hpp @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2020-2021 Florian Schmaus +#pragma once + +#include <cstdint> + +struct AbstractWorkStealingWorkerStats { + uint64_t scheduledFibersToLocal = 0; + uint64_t scheduledFibersToOverflowQueue = 0; + uint64_t nextFiberFromLocal = 0; + uint64_t nextFiberStolen = 0; + uint64_t nextFiberFromAnywhereQueue = 0; + + auto operator+=(const AbstractWorkStealingWorkerStats& other) + -> AbstractWorkStealingWorkerStats& { + scheduledFibersToLocal += other.scheduledFibersToLocal; + scheduledFibersToOverflowQueue += other.scheduledFibersToOverflowQueue; + nextFiberFromLocal += other.nextFiberFromLocal; + nextFiberStolen += other.nextFiberStolen; + nextFiberFromAnywhereQueue = other.nextFiberFromAnywhereQueue; + return *this; + } +}; diff --git a/emper/strategies/laws/LawsDispatcher.cpp b/emper/strategies/laws/LawsDispatcher.cpp index 0edaa1536afccb75f53f5c365046ecc418b5c83d..8044fb404423b1f5bb0725c2d7d6f0eddc60ff73 100644 --- a/emper/strategies/laws/LawsDispatcher.cpp +++ b/emper/strategies/laws/LawsDispatcher.cpp @@ -2,13 +2,13 @@ // Copyright © 2020-2021 Florian Schmaus #include "LawsDispatcher.hpp" -#include <atomic> // for atomic, memory_order_relaxed - #include "Common.hpp" // for DIE_MSG #include "Emper.hpp" #include "LawsStrategy.hpp" // for LawsStrategy, LawsStrategy::FiberSource #include "NextFiberResult.hpp" #include "Runtime.hpp" +#include "emper-common.h" +#include "strategies/laws/LawsWorkerStats.hpp" void LawsDispatcher::recycle(Fiber* fiber) { // If the ref count has not reached zero yet, do not recycle the @@ -36,16 +36,16 @@ void LawsDispatcher::dispatchLoop() { auto fiberSource = static_cast<LawsStrategy::FiberSource>(next.metadata); switch (fiberSource) { case LawsStrategy::FiberSource::fromPriority: - lawsStrategy.dispatchedFiberFromPriority.fetch_add(1, std::memory_order_relaxed); + LawsStrategy::stats.dispatchedFibersFromPriority++; break; case LawsStrategy::FiberSource::local: - lawsStrategy.dispatchedFiberFromLocal.fetch_add(1, std::memory_order_relaxed); + LawsStrategy::stats.dispatchedFibersFromLocal++; break; case LawsStrategy::FiberSource::stolen: - lawsStrategy.dispatchedFiberStolen.fetch_add(1, std::memory_order_relaxed); + LawsStrategy::stats.dispatchedFibersStolen++; break; case LawsStrategy::FiberSource::anywhereQueue: - lawsStrategy.dispatchedFiberFromAnywhere.fetch_add(1, std::memory_order_relaxed); + LawsStrategy::stats.dispatchedFibersFromAnywhereQueue++; break; default: DIE_MSG("Unknown fiber source: " << next.metadata); diff --git a/emper/strategies/laws/LawsDispatcher.hpp b/emper/strategies/laws/LawsDispatcher.hpp index fec816a19903205450c0060f3d37987c97d59bc4..d10b856c71b85b1f518532fc767e0eeced8e8365 100644 --- a/emper/strategies/laws/LawsDispatcher.hpp +++ b/emper/strategies/laws/LawsDispatcher.hpp @@ -1,30 +1,18 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus +// Copyright © 2020-2021 Florian Schmaus #pragma once #include "Dispatcher.hpp" -#include "emper-common.h" class Fiber; -class LawsStrategy; class Runtime; class LawsDispatcher : public Dispatcher { private: -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" - LawsStrategy& lawsStrategy -#ifndef EMPER_STATS - ATTR_UNUSED -#endif - ; -#pragma GCC diagnostic pop - void recycle(Fiber* fiber) override; public: - LawsDispatcher(Runtime& runtime, LawsStrategy& lawsStrategy) - : Dispatcher(runtime), lawsStrategy(lawsStrategy) {} + LawsDispatcher(Runtime& runtime) : Dispatcher(runtime) {} void dispatchLoop() override; }; diff --git a/emper/strategies/laws/LawsScheduler.cpp b/emper/strategies/laws/LawsScheduler.cpp index d05f9c624fafb6821342e35ab899ff38248cceb0..6ea84c23fef24c9f9ad52be0b17303c2718039df 100644 --- a/emper/strategies/laws/LawsScheduler.cpp +++ b/emper/strategies/laws/LawsScheduler.cpp @@ -2,7 +2,6 @@ // Copyright © 2020-2021 Florian Schmaus #include "LawsScheduler.hpp" -#include <atomic> // for atomic, memory_order_relaxed #include <cstdint> #include "Emper.hpp" @@ -10,11 +9,11 @@ #include "NextFiberResult.hpp" #include "Runtime.hpp" #include "emper-common.h" +#include "strategies/laws/LawsWorkerStats.hpp" thread_local LawsScheduler::LawsMpscQueue LawsScheduler::priorityQueue; -LawsScheduler::LawsScheduler(Runtime& runtime, LawsStrategy& lawsStrategy) - : AbstractWorkStealingScheduler(runtime, lawsStrategy), lawsStrategy(lawsStrategy) { +LawsScheduler::LawsScheduler(Runtime& runtime) : AbstractWorkStealingScheduler(runtime) { const workerid_t workerCount = runtime.getWorkerCount(); priorityQueues = new LawsScheduler::LawsMpscQueue*[workerCount]; @@ -38,9 +37,8 @@ void LawsScheduler::scheduleInternal(Fiber& fiber) { // We found a fiber to schedule on a remote prority queue. increaseRefCount(fiber); priorityQueues[affinity]->enqueue(&fiber); - if constexpr (emper::STATS) { - lawsStrategy.scheduledFibersToRemotePriority.fetch_add(1, std::memory_order_relaxed); - } + + emper::statsIncr(LawsStrategy::stats.scheduledFibersToPriority); } scheduleViaWorkStealing: diff --git a/emper/strategies/laws/LawsScheduler.hpp b/emper/strategies/laws/LawsScheduler.hpp index a2fd6184a9d69adca2ce1ddafd4b21479b6819f5..d95a4bf06146caaca0af83b35bfd0183108d4019 100644 --- a/emper/strategies/laws/LawsScheduler.hpp +++ b/emper/strategies/laws/LawsScheduler.hpp @@ -3,11 +3,9 @@ #pragma once #include "Fiber.hpp" -#include "emper-common.h" #include "lib/adt/MpscQueue.hpp" #include "strategies/AbstractWorkStealingScheduler.hpp" -class LawsStrategy; class Runtime; struct NextFiberResult; @@ -19,20 +17,11 @@ class LawsScheduler : public AbstractWorkStealingScheduler { static thread_local LawsMpscQueue priorityQueue; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" - LawsStrategy& lawsStrategy -#ifndef EMPER_STATS - ATTR_UNUSED -#endif - ; -#pragma GCC diagnostic pop - protected: void scheduleInternal(Fiber& fiber) override; public: - LawsScheduler(Runtime& runtime, LawsStrategy& lawsStrategy); + LawsScheduler(Runtime& runtime); auto nextFiber() -> NextFiberResult override; }; diff --git a/emper/strategies/laws/LawsStrategy.cpp b/emper/strategies/laws/LawsStrategy.cpp index 68bb821efe5b5a3b2eae815239c44829fa75225e..57116344cd124bab6f6a48d604cc7f97aacc6683 100644 --- a/emper/strategies/laws/LawsStrategy.cpp +++ b/emper/strategies/laws/LawsStrategy.cpp @@ -2,18 +2,20 @@ // Copyright © 2020-2021 Florian Schmaus #include "LawsStrategy.hpp" +#include <functional> + #include "strategies/laws/LawsDispatcher.hpp" // for LawsDispatcher #include "strategies/laws/LawsScheduler.hpp" // for LawsScheduler #include "strategies/laws/LawsStrategyStats.hpp" // for LawsStrategyStats +#include "strategies/laws/LawsWorkerStats.hpp" + +thread_local LawsWorkerStats LawsStrategy::stats; LawsStrategy::LawsStrategy(Runtime& runtime) - : scheduler(runtime, *this), - dispatcher(runtime, *this), - scheduledFibersToRemotePriority(0), - dispatchedFiberFromPriority(0), - dispatchedFiberFromLocal(0), - dispatchedFiberStolen(0), - dispatchedFiberFromAnywhere(0) {} + : AbstractWorkStealingStrategy(runtime), + scheduler(runtime), + dispatcher(runtime), + allWorkerStats([] { return &stats; }, runtime) {} auto LawsStrategy::getScheduler() -> LawsScheduler& { return scheduler; } diff --git a/emper/strategies/laws/LawsStrategy.hpp b/emper/strategies/laws/LawsStrategy.hpp index d06448689b0664c3d2d30c606ae2d1f5cc07ba20..113427d3df2d735d1e717315715fde2c1a6cbb6d 100644 --- a/emper/strategies/laws/LawsStrategy.hpp +++ b/emper/strategies/laws/LawsStrategy.hpp @@ -2,10 +2,10 @@ // Copyright © 2020-2021 Florian Schmaus #pragma once -#include <atomic> #include <cstdint> #include <memory> +#include "WorkerLocalData.hpp" #include "strategies/AbstractWorkStealingScheduler.hpp" #include "strategies/AbstractWorkStealingStrategy.hpp" #include "strategies/laws/LawsDispatcher.hpp" @@ -15,6 +15,7 @@ class LawsStrategyFactory; class LawsStrategyStats; class Runtime; class RuntimeStrategyStats; +struct LawsWorkerStats; class LawsStrategy : public AbstractWorkStealingStrategy { private: @@ -29,12 +30,9 @@ class LawsStrategy : public AbstractWorkStealingStrategy { LawsScheduler scheduler; LawsDispatcher dispatcher; - // TODO: Align those all to cache line! - std::atomic<std::uint64_t> scheduledFibersToRemotePriority; - std::atomic<std::uint64_t> dispatchedFiberFromPriority; - std::atomic<std::uint64_t> dispatchedFiberFromLocal; - std::atomic<std::uint64_t> dispatchedFiberStolen; - std::atomic<std::uint64_t> dispatchedFiberFromAnywhere; + static thread_local LawsWorkerStats stats; + + WorkerLocalData<LawsWorkerStats> allWorkerStats; LawsStrategy(Runtime& runtime); diff --git a/emper/strategies/laws/LawsStrategyStats.cpp b/emper/strategies/laws/LawsStrategyStats.cpp index 966c84c37f01f69b33379af3c1f020a2283ff276..451d112606b1043ad7d5774a7a04ccec21f7ed93 100644 --- a/emper/strategies/laws/LawsStrategyStats.cpp +++ b/emper/strategies/laws/LawsStrategyStats.cpp @@ -2,45 +2,31 @@ // Copyright © 2020-2021 Florian Schmaus #include "LawsStrategyStats.hpp" -#include <atomic> #include <iostream> +#include <string> #include "LawsStrategy.hpp" +#include "WorkerLocalData.hpp" LawsStrategyStats::LawsStrategyStats(LawsStrategy& lawsStrategy) : AbstractWorkStealingStats(lawsStrategy), - scheduledFibersToRemotePriority(lawsStrategy.scheduledFibersToRemotePriority), - dispatchedFiberFromPriority(lawsStrategy.dispatchedFiberFromPriority), - dispatchedFiberFromLocal(lawsStrategy.dispatchedFiberFromLocal), - dispatchedFiberStolen(lawsStrategy.dispatchedFiberStolen), - dispatchedFiberFromAnywhere(lawsStrategy.dispatchedFiberFromAnywhere) {} - -auto LawsStrategyStats::getScheduledFibersToRemotePriority() const -> uint64_t { - return scheduledFibersToRemotePriority; -} - -auto LawsStrategyStats::getDispatchedFiberFromPriority() const -> uint64_t { - return dispatchedFiberFromPriority; -} - -auto LawsStrategyStats::getDispatchedFiberFromLocal() const -> uint64_t { - return dispatchedFiberFromLocal; -} - -auto LawsStrategyStats::getDispatchedFiberStolen() const -> uint64_t { - return dispatchedFiberStolen; -} - -auto LawsStrategyStats::getDispatchedFiberFromAnywhere() const -> uint64_t { - return dispatchedFiberFromAnywhere; + workerStats(lawsStrategy.allWorkerStats.getSnapshot()) { + for (auto& workerStat : workerStats) { + comulatedWorkerStats += workerStat; + } } void LawsStrategyStats::print() { - // TODO: Print also the stats from AbstractWorkStealingStrategy. - std::cout << "LawsStrategyStats" - << " scheduledFibersToRemotePriority:" << scheduledFibersToRemotePriority - << " dispatchedFiberFromPriority:" << dispatchedFiberFromPriority - << " dispatchedFiberFromLocal:" << dispatchedFiberFromLocal - << " dispatchedFiberStolen:" << dispatchedFiberStolen - << " dispatchedFiberFromAnywhere:" << dispatchedFiberFromAnywhere << std::endl; + AbstractWorkStealingStats::print(); + + std::cout << "total-scheduled-fibers-to-priority: " + << std::to_string(comulatedWorkerStats.scheduledFibersToPriority) << std::endl + << "total-dispatched-fibers-from-priority: " + << std::to_string(comulatedWorkerStats.dispatchedFibersFromPriority) << std::endl + << "total-dispatched-fibers-from-local: " + << std::to_string(comulatedWorkerStats.dispatchedFibersFromLocal) << std::endl + << "total-dispatched-fibers-stolen: " + << std::to_string(comulatedWorkerStats.dispatchedFibersStolen) << std::endl + << "total-dispatched-fibers-from-anywhere-queue: " + << std::to_string(comulatedWorkerStats.dispatchedFibersFromAnywhereQueue) << std::endl; } diff --git a/emper/strategies/laws/LawsStrategyStats.hpp b/emper/strategies/laws/LawsStrategyStats.hpp index 2d4cff89c5d6021867009fcb595014bae4002461..35c30d9feb9297a5229efd1e3ed40ac069f2704a 100644 --- a/emper/strategies/laws/LawsStrategyStats.hpp +++ b/emper/strategies/laws/LawsStrategyStats.hpp @@ -2,28 +2,19 @@ // Copyright © 2020-2021 Florian Schmaus #pragma once -#include <cstdint> +#include <vector> #include "strategies/AbstractWorkStealingStats.hpp" +#include "strategies/laws/LawsWorkerStats.hpp" class LawsStrategy; class LawsStrategyStats : public AbstractWorkStealingStats { - private: - const uint64_t scheduledFibersToRemotePriority; - const uint64_t dispatchedFiberFromPriority; - const uint64_t dispatchedFiberFromLocal; - const uint64_t dispatchedFiberStolen; - const uint64_t dispatchedFiberFromAnywhere; - public: - LawsStrategyStats(LawsStrategy& lawsStrategy); + std::vector<LawsWorkerStats> workerStats; + LawsWorkerStats comulatedWorkerStats; - [[nodiscard]] auto getScheduledFibersToRemotePriority() const -> uint64_t; - [[nodiscard]] auto getDispatchedFiberFromPriority() const -> uint64_t; - [[nodiscard]] auto getDispatchedFiberFromLocal() const -> uint64_t; - [[nodiscard]] auto getDispatchedFiberStolen() const -> uint64_t; - [[nodiscard]] auto getDispatchedFiberFromAnywhere() const -> uint64_t; + LawsStrategyStats(LawsStrategy& lawsStrategy); void print() override; }; diff --git a/emper/strategies/laws/LawsWorkerStats.hpp b/emper/strategies/laws/LawsWorkerStats.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f60b211d1dbd96dda5319e7f2047a5c96d690e22 --- /dev/null +++ b/emper/strategies/laws/LawsWorkerStats.hpp @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2020-2021 Florian Schmaus +#pragma once + +#include <cstdint> + +struct LawsWorkerStats { + uint64_t scheduledFibersToPriority = 0; + uint64_t dispatchedFibersFromPriority = 0; + uint64_t dispatchedFibersFromLocal = 0; + uint64_t dispatchedFibersStolen = 0; + uint64_t dispatchedFibersFromAnywhereQueue = 0; + + auto operator+=(const LawsWorkerStats& other) -> LawsWorkerStats& { + scheduledFibersToPriority += other.scheduledFibersToPriority; + dispatchedFibersFromPriority += other.dispatchedFibersFromPriority; + dispatchedFibersFromLocal += other.dispatchedFibersFromLocal; + dispatchedFibersStolen += other.dispatchedFibersStolen; + dispatchedFibersFromAnywhereQueue += other.dispatchedFibersFromAnywhereQueue; + return *this; + } +}; diff --git a/emper/strategies/meson.build b/emper/strategies/meson.build index 2586f72a5ca36fb838db34ce2ea2e6808e341842..6858f902a1a8e6ad9295a9d8d25f012ef9bf44a9 100644 --- a/emper/strategies/meson.build +++ b/emper/strategies/meson.build @@ -1,6 +1,7 @@ emper_cpp_sources += files( 'AbstractWorkStealingScheduler.cpp', 'AbstractWorkStealingStats.cpp', + 'AbstractWorkStealingStrategy.cpp', ) subdir('ws') diff --git a/emper/strategies/ws/WsScheduler.cpp b/emper/strategies/ws/WsScheduler.cpp index 41c1b0a5b9ee876fb56b5101f5f1002637d185be..b57510cb6ec60bc7704a4c86d792d6e23c904a2d 100644 --- a/emper/strategies/ws/WsScheduler.cpp +++ b/emper/strategies/ws/WsScheduler.cpp @@ -1,8 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus +// Copyright © 2020-2021 Florian Schmaus #include "WsScheduler.hpp" -#include "strategies/ws/WsStrategy.hpp" - -WsScheduler::WsScheduler(Runtime& runtime, WsStrategy& wsStrategy) - : AbstractWorkStealingScheduler(runtime, wsStrategy), wsStrategy(wsStrategy) {} +WsScheduler::WsScheduler(Runtime& runtime) : AbstractWorkStealingScheduler(runtime) {} diff --git a/emper/strategies/ws/WsScheduler.hpp b/emper/strategies/ws/WsScheduler.hpp index 63a634d36b97761481f1c7170470b136ca869575..392b0aff0c7f9742be48efaff3ef94ef0d2784a4 100644 --- a/emper/strategies/ws/WsScheduler.hpp +++ b/emper/strategies/ws/WsScheduler.hpp @@ -3,28 +3,17 @@ #pragma once #include "NextFiberResult.hpp" -#include "emper-common.h" // for ATTR_UNUSED #include "strategies/AbstractWorkStealingScheduler.hpp" class Fiber; class Runtime; -class WsStrategy; class WsScheduler : public AbstractWorkStealingScheduler { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wattributes" - WsStrategy& wsStrategy -#ifndef EMPER_STATS - ATTR_UNUSED -#endif - ; -#pragma GCC diagnostic pop - protected: void scheduleInternal(Fiber& fiber) override { scheduleViaWorkStealing(fiber); } public: - WsScheduler(Runtime& runtime, WsStrategy& wsStrategy); + WsScheduler(Runtime& runtime); auto nextFiber() -> NextFiberResult override { return nextFiberResultViaWorkStealing(); }; }; diff --git a/emper/strategies/ws/WsStrategy.cpp b/emper/strategies/ws/WsStrategy.cpp index 72bc6fe4944c375132819e959d8d803fabc236aa..11fcd3d02223f41f793f0703dfc8c8f7822596a4 100644 --- a/emper/strategies/ws/WsStrategy.cpp +++ b/emper/strategies/ws/WsStrategy.cpp @@ -9,7 +9,8 @@ class Runtime; class RuntimeStrategyStats; -WsStrategy::WsStrategy(Runtime& runtime) : scheduler(runtime, *this), dispatcher(runtime) {} +WsStrategy::WsStrategy(Runtime& runtime) + : AbstractWorkStealingStrategy(runtime), scheduler(runtime), dispatcher(runtime) {} auto WsStrategy::getScheduler() -> WsScheduler& { return scheduler; } diff --git a/tests/SimpleFibTest.cpp b/tests/SimpleFibTest.cpp index 79bd1f725a7dcc0b2cf209b4ae341a977e71d886..ae3d698e9d4595938597d617f6ff298c0a06c5c8 100644 --- a/tests/SimpleFibTest.cpp +++ b/tests/SimpleFibTest.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus +// Copyright © 2020-2021 Florian Schmaus #include <cstdlib> // for exit, EXIT_FAILURE, EXIT_SUC... #include "BinaryPrivateSemaphore.hpp" // for BPS @@ -7,7 +7,6 @@ #include "Fiber.hpp" // for Fiber #include "PrivateSemaphore.hpp" // for PS #include "Runtime.hpp" // for Runtime -#include "emper-common.h" // for UNUSED_ARG using fibParams = struct { int n; @@ -52,31 +51,17 @@ static void fib(void* voidParams) { sem->signalAndExit(); } -auto main(UNUSED_ARG int argc, UNUSED_ARG char* argv[]) -> int { - Runtime runtime; +void emperTest() { + const int fibNum = 13; + int result; + BPS sem; + fibParams params = {fibNum, &result, &sem}; - Fiber* fibFiber = Fiber::from( - [](UNUSED_ARG void* arg) { - const int fibNum = 13; - int result; - BPS sem; - fibParams params = {fibNum, &result, &sem}; + fib(¶ms); - fib(¶ms); + sem.wait(); - sem.wait(); - - if (result != 233) { - exit(EXIT_FAILURE); - } - - exit(EXIT_SUCCESS); - }, - nullptr); - - runtime.scheduleFromAnywhere(*fibFiber); - - runtime.waitUntilFinished(); - - return EXIT_FAILURE; + if (result != 233) { + exit(EXIT_FAILURE); + } } diff --git a/tests/meson.build b/tests/meson.build index 723ba5fb3ec6f7e7666917b56c1b4d32156dba31..f2d4ef05966c34b216ebc1405d402d5efde34508 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -11,6 +11,7 @@ tests = [ 'source': files('SimpleFibTest.cpp'), 'name': 'SimpleFibTest', 'description': 'Simple test', + 'test_runner': 'emper', }, {