blob: f652bb651e7d08f95424c5064a3eb1d35fdf97f0 [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#ifndef AOS_EVENTS_EVENT_LOOP_TMPL_H_
2#define AOS_EVENTS_EVENT_LOOP_TMPL_H_
3
4#include <type_traits>
5#include "aos/events/event_loop.h"
6#include "glog/logging.h"
7
8namespace aos {
9
10// From a watch functor, this will extract the message type of the argument.
11// This is the template forward declaration, and it extracts the call operator
12// as a PTMF to be used by the following specialization.
13template <class T>
14struct watch_message_type_trait
15 : watch_message_type_trait<decltype(&T::operator())> {};
16
17// From a watch functor, this will extract the message type of the argument.
18// This is the template specialization.
19template <class ClassType, class ReturnType, class A1>
20struct watch_message_type_trait<ReturnType (ClassType::*)(A1) const> {
21 using message_type = typename std::decay<A1>::type;
22};
23
24template <typename T>
25typename Sender<T>::Builder Sender<T>::MakeBuilder() {
26 return Builder(sender_.get(), sender_->data(), sender_->size());
27}
28
29template <typename Watch>
James Kuszmaul3ae42262019-11-08 12:33:41 -080030void EventLoop::MakeWatcher(const std::string_view channel_name, Watch &&w) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070031 using T = typename watch_message_type_trait<Watch>::message_type;
32 const Channel *channel = configuration::GetChannel(
33 configuration_, channel_name, T::GetFullyQualifiedName(), name());
34
35 CHECK(channel != nullptr)
36 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
37 << T::GetFullyQualifiedName() << "\" } not found in config.";
38
39 return MakeRawWatcher(
40 channel, [this, w](const Context &context, const void *message) {
41 context_ = context;
42 w(*flatbuffers::GetRoot<T>(reinterpret_cast<const char *>(message)));
43 });
44}
45
Austin Schuh39788ff2019-12-01 18:22:57 -080046inline bool RawFetcher::FetchNext() {
47 const auto result = DoFetchNext();
48 if (result.first) {
49 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
50 const monotonic_clock::time_point monotonic_time = result.second;
51 const float latency =
52 std::chrono::duration_cast<std::chrono::duration<float>>(
53 monotonic_time - context_.monotonic_sent_time)
54 .count();
55 timing_.latency.Add(latency);
56 return true;
57 }
58 return false;
59}
60
61inline bool RawFetcher::Fetch() {
62 const auto result = DoFetch();
63 if (result.first) {
64 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
65 const monotonic_clock::time_point monotonic_time = result.second;
66 const float latency =
67 std::chrono::duration_cast<std::chrono::duration<float>>(
68 monotonic_time - context_.monotonic_sent_time)
69 .count();
70 timing_.latency.Add(latency);
71 return true;
72 }
73 return false;
74}
75
76inline bool RawSender::Send(size_t size) {
77 if (DoSend(size)) {
78 timing_.size.Add(size);
79 timing_.sender->mutate_count(timing_.sender->count() + 1);
80 return true;
81 }
82 return false;
83}
84
85inline bool RawSender::Send(const void *data, size_t size) {
86 if (DoSend(data, size)) {
87 timing_.size.Add(size);
88 timing_.sender->mutate_count(timing_.sender->count() + 1);
89 return true;
90 }
91 return false;
92}
93
94inline void TimerHandler::Call(
95 std::function<monotonic_clock::time_point()> get_time,
96 monotonic_clock::time_point event_time) {
97 CHECK_NOTNULL(timing_.timer);
98 const monotonic_clock::time_point monotonic_start_time = get_time();
99
100 event_loop_->context_.monotonic_sent_time = event_time;
101 event_loop_->context_.realtime_sent_time = realtime_clock::min_time;
102 event_loop_->context_.queue_index = 0xffffffffu;
103 event_loop_->context_.size = 0;
104 event_loop_->context_.data = nullptr;
105
106 {
107 const float start_latency =
108 std::chrono::duration_cast<std::chrono::duration<float>>(
109 monotonic_start_time - event_time)
110 .count();
111 timing_.wakeup_latency.Add(start_latency);
112 }
113 timing_.timer->mutate_count(timing_.timer->count() + 1);
114 fn_();
115
116 const monotonic_clock::time_point monotonic_end_time = get_time();
117
118 const float handler_latency =
119 std::chrono::duration_cast<std::chrono::duration<float>>(
120 monotonic_end_time - monotonic_start_time)
121 .count();
122 timing_.handler_time.Add(handler_latency);
123}
124
125inline void PhasedLoopHandler::Call(
126 std::function<monotonic_clock::time_point()> get_time,
127 std::function<void(monotonic_clock::time_point)> schedule) {
128 // Read time directly to save a vtable indirection...
129 const monotonic_clock::time_point monotonic_start_time = get_time();
130
131 // Update the context to hold the desired wakeup time.
132 event_loop_->context_.monotonic_sent_time = phased_loop_.sleep_time();
133 event_loop_->context_.realtime_sent_time = realtime_clock::min_time;
134 event_loop_->context_.queue_index = 0xffffffffu;
135 event_loop_->context_.size = 0;
136 event_loop_->context_.data = nullptr;
137
138 // Compute how many cycles elapsed and schedule the next wakeup.
139 Reschedule(schedule, monotonic_start_time);
140
141 {
142 const float start_latency =
143 std::chrono::duration_cast<std::chrono::duration<float>>(
144 monotonic_start_time - event_loop_->context_.monotonic_sent_time)
145 .count();
146 timing_.wakeup_latency.Add(start_latency);
147 }
148 timing_.timer->mutate_count(timing_.timer->count() + 1);
149
150 // Call the function with the elapsed cycles.
151 fn_(cycles_elapsed_);
152 cycles_elapsed_ = 0;
153
154 const monotonic_clock::time_point monotonic_end_time = get_time();
155
156 const float handler_latency =
157 std::chrono::duration_cast<std::chrono::duration<float>>(
158 monotonic_end_time - monotonic_start_time)
159 .count();
160 timing_.handler_time.Add(handler_latency);
161
162 // If the handler too too long so we blew by the previous deadline, we
163 // want to just try for the next deadline. Rescuedule.
164 if (monotonic_end_time > phased_loop_.sleep_time()) {
165 Reschedule(schedule, monotonic_end_time);
166 }
167}
168
169// Class to automate the timing report generation for watchers.
170class WatcherState {
171 public:
172 WatcherState(
173 EventLoop *event_loop, const Channel *channel,
174 std::function<void(const Context &context, const void *message)> fn)
175 : channel_index_(event_loop->ChannelIndex(channel)), fn_(std::move(fn)) {}
176
177 virtual ~WatcherState() {}
178
179 // Calls the callback, measuring time with get_time, with the provided
180 // context.
181 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
182 Context context) {
183 const monotonic_clock::time_point monotonic_start_time = get_time();
184 {
185 const float start_latency =
186 std::chrono::duration_cast<std::chrono::duration<float>>(
187 monotonic_start_time - context.monotonic_sent_time)
188 .count();
189 wakeup_latency_.Add(start_latency);
190 }
191 watcher_->mutate_count(watcher_->count() + 1);
192 fn_(context, context.data);
193
194 const monotonic_clock::time_point monotonic_end_time = get_time();
195
196 const float handler_latency =
197 std::chrono::duration_cast<std::chrono::duration<float>>(
198 monotonic_end_time - monotonic_start_time)
199 .count();
200 handler_time_.Add(handler_latency);
201 }
202
203 int channel_index() const { return channel_index_; }
204
205 void set_timing_report(timing::Watcher *watcher);
206 void ResetReport();
207
208 virtual void Startup(EventLoop *event_loop) = 0;
209
210 protected:
211 const int channel_index_;
212
213 std::function<void(const Context &context, const void *message)> fn_;
214
215 internal::TimingStatistic wakeup_latency_;
216 internal::TimingStatistic handler_time_;
217 timing::Watcher *watcher_ = nullptr;
218};
219
Alex Perrycb7da4b2019-08-28 19:35:56 -0700220} // namespace aos
221
222#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H