Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
Runner.cpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2021 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#include "Runner.hpp"
18
19#include "Reactor.hpp"
20
21#include <toolbox/sys/Log.hpp>
23
24namespace toolbox {
25inline namespace io {
26namespace {
27void run_reactor(Reactor& r, long busy_cycles, ThreadConfig config, const std::atomic<bool>& stop)
28{
29 // ==== KEEP IN SYNC WITH CHANGES IN run_metrics_reactor ====
31 try {
33 TOOLBOX_NOTICE << "started " << config.name << " thread";
34 long i{0};
35 while (!stop.load(std::memory_order_acquire)) {
36 // Busy-wait for "busy cycles" after work was done.
37 if (r.poll(CyclTime::now(), i++ < busy_cycles ? 0s : NoTimeout) > 0) {
38 // Reset counter when work has been done.
39 i = 0;
40 }
41 }
42 } catch (const std::exception& e) {
43 TOOLBOX_CRIT << "exception on " << config.name << " thread: " << e.what();
45 }
46 TOOLBOX_NOTICE << "stopping " << config.name << " thread";
47}
48
50{
51 // Record microseconds with 3sf and max expected value of one second.
52 return HistogramPtr{new Histogram{1, 1'000'000, 3}};
53}
54
56{
57 // Histogram is 100% accurate to 256, covering Reactor::MaxEvents of 128 work items.
58 return HistogramPtr{new Histogram{1, 1000, 2}};
59}
60
61void run_metrics_reactor(Reactor& r, long busy_cycles, ThreadConfig config,
62 const std::atomic<bool>& stop, MetricCallbackFunction metric_cb,
64{
65 constexpr std::chrono::seconds MetricInterval = 60s;
66
67 // ==== KEEP IN SYNC WITH CHANGES IN run_reactor ====
69 try {
71 TOOLBOX_NOTICE << "started " << config.name << " thread";
72
74 // 128 possible buffer slots in poll + high and low priority timers
76
77 long i{0};
78 auto metric_time = MonoClock::now() + MetricInterval;
79
80 PassInfo pass;
82 const auto end_pass = [&](MonoTime now) {
83 if (!is_zero(pass_mono)) {
84 pass.duration = now - pass_mono;
86 }
87 };
88
89 while (!stop.load(std::memory_order_acquire)) {
90 const auto start = CyclTime::now();
91 if (pass_slot) {
92 const auto mono{start.mono_time()};
93 const auto wall{start.wall_time()};
95 pass.start = wall;
97 }
98 // Busy-wait for "busy cycles" after work was done.
99 auto work = r.poll(start, i++ < busy_cycles ? 0s : NoTimeout);
100 pass.work = work;
101 const auto now = CyclTime::current();
102 if (work > 0) {
103 // Don't skew distribution with a lot of zero work.
104 const auto elapsed_us = std::chrono::duration_cast<std::chrono::microseconds>(
105 MonoClock::now() - now.mono_time());
106 if (elapsed_us.count() != 0) {
107 time_hist->record_value(elapsed_us.count());
108 work_hist->record_value(work);
109 }
110 // Reset counter when work has been done.
111 i = 0;
112 }
113 if (now.mono_time() >= metric_time) {
114 // Metric reporting.
115 metric_time = now.mono_time() + MetricInterval;
116 metric_cb(now, std::move(time_hist), std::move(work_hist));
119 }
120 }
121 end_pass(MonoClock::now());
122 } catch (const std::exception& e) {
123 TOOLBOX_CRIT << "exception on " << config.name << " thread: " << e.what();
124 kill(getpid(), SIGTERM);
125 }
126 TOOLBOX_NOTICE << "stopping " << config.name << " thread";
127}
128
129} // namespace
130
132: reactor_{r}
133, thread_{run_reactor, std::ref(r), busy_cycles, config, std::cref(stop_)}
134{
135}
136
142
150
152{
153 stop_.store(true, std::memory_order_release);
154 reactor_.wakeup();
155 thread_.join();
156}
157
158} // namespace io
159} // namespace toolbox
#define TOOLBOX_CRIT
Definition Log.hpp:92
#define TOOLBOX_NOTICE
Definition Log.hpp:96
ReactorRunner(Reactor &r, long busy_cycles, ThreadConfig config)
Definition Runner.cpp:131
void wakeup() noexcept
Definition Waker.hpp:40
STL namespace.
constexpr Duration NoTimeout
Definition Reactor.hpp:29
std::function< void(CyclTime now, HistogramPtr &&time_hist, HistogramPtr &&work_hist)> MetricCallbackFunction
MetricCallbackFunction implementer is responsible for deleting the Histogram.
Definition Runner.hpp:36
std::unique_ptr< Histogram > HistogramPtr
Definition Runner.hpp:32
BasicSlot< void(const PassInfo &)> PassSlot
PassSlot receives every pass of a runner's loop, on the runner's thread.
Definition Runner.hpp:46
constexpr bool is_zero(std::chrono::duration< RepT, PeriodT > d) noexcept
Definition Time.hpp:155
MonoClock::time_point MonoTime
Definition Time.hpp:112
void set_thread_attrs(const ThreadConfig &config)
Definition Thread.cpp:70
void sig_block_all()
Block all signals.
Definition Signal.cpp:82
constexpr auto bind() noexcept
Definition Slot.hpp:97
ThreadConfig holds the thread attributes.
Definition Thread.hpp:30