diff --git a/emper/io/IoContext.cpp b/emper/io/IoContext.cpp index 3e83d55bdf5e34ff08450a64ab210877fb6f70c5..d827a1a0dc43896a9bf745781cb392eecd162d01 100644 --- a/emper/io/IoContext.cpp +++ b/emper/io/IoContext.cpp @@ -163,6 +163,7 @@ auto IoContext::reapCompletions() -> std::vector<Fiber *> { // Should not be more than the uring_entries count. const unsigned CQE_BATCH_COUNT = EMPER_IO_WORKER_URING_ENTRIES; + unsigned reReapCount = 0; uint32_t maxRaceFreeCompleterAttempts = 1; using Completion = std::pair<uint32_t, void *>; @@ -306,8 +307,12 @@ reap_cqes: runtime.schedule(continuationFibers.begin(), continuationFibers.end()); continuationFibers.clear(); + reReapCount++; + goto reap_cqes; } + + stats.record_reReapCount(reReapCount); } return continuationFibers; diff --git a/emper/io/Stats.cpp b/emper/io/Stats.cpp index 42bb2921d8ef0c9173b4507f324dbe3868ce7851..a3e7feccb220f86fbc5b578d4e671602945eac4e 100644 --- a/emper/io/Stats.cpp +++ b/emper/io/Stats.cpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Fischer +// Copyright © 2020-2021 Florian Fischer, Florian Schmaus #include "io/Stats.hpp" #include <initializer_list> // for initializer_list @@ -107,6 +107,13 @@ auto operator<<(std::ostream& os, const Stats& s) -> std::ostream& { os << "global completer thread reaped completions " << s.completer_reap << " times reaping " << s.completer_reaped_completions << " completions in total" << std::endl; + os << "re-reap count average [count]: " << s.reReapCount_average << std::endl + << "re-reap count max: " << s.reReapCount_max << std::endl + << "re-reap last 10:"; + for (unsigned i : s.reReapCount_last) { + os << " " << std::to_string(i); + } + os << std::endl; return os; } diff --git a/emper/io/Stats.hpp b/emper/io/Stats.hpp index ad68f3f96dfe6777cae7bcf7587668c3dadf5d96..dbb15383729fc03f0493b4a6f616a213c7d83fe5 100644 --- a/emper/io/Stats.hpp +++ b/emper/io/Stats.hpp @@ -1,16 +1,19 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Fischer +// Copyright © 2020-2021 Florian Fischer, Florian Schmaus #pragma once #include <bits/types/struct_iovec.h> // for iovec #include <sys/types.h> // for ssize_t +#include <boost/circular_buffer.hpp> +#include <boost/core/pointer_traits.hpp> #include <chrono> // for nanoseconds #include <cstddef> // for size_t #include <cstdint> // for uint64_t, int32_t, uint32_t #include <cstdlib> // for abort #include <iostream> // for operator<<, basic_ostream, basi... #include <map> // for map, map<>::value_compare -#include <vector> // for vector +#include <string> +#include <vector> #include "CallerEnvironment.hpp" #include "Debug.hpp" // for LOGW @@ -115,9 +118,13 @@ class Stats { uint64_t worker_reap = 0; uint64_t worker_reaped_completions = 0; + math::RunningAverage<float> reReapCount_average; + unsigned reReapCount_max = 0; + boost::circular_buffer<unsigned> reReapCount_last; + static void printWorkerStats(); - Stats() { + Stats() : reReapCount_last(10) { if constexpr (emper::STATS) { workerStats.push_back(this); } @@ -216,6 +223,22 @@ class Stats { } } + void record_reReapCount(unsigned reReapCount) { + RETURN_IF_NO_STATS(); + + if (!reReapCount) { + return; + } + + reReapCount_average.update(reReapCount); + + if (reReapCount > reReapCount_max) { + reReapCount_max = reReapCount; + } + + reReapCount_last.push_back(reReapCount); + } + friend auto operator<<(std::ostream& os, const Stats& s) -> std::ostream&; friend auto operator<<(std::ostream& os, const Stats::CompletionType& t) -> std::ostream&; };