blob: 9e16d200800a726e1e3ec5d26fcb48dd4ced59b8 [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
Brian Silverman79ec7fc2020-06-08 20:11:22 -05004#include <inttypes.h>
5#include <stdint.h>
6
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include <type_traits>
Brian Silverman79ec7fc2020-06-08 20:11:22 -05008
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include "aos/events/event_loop.h"
10#include "glog/logging.h"
11
12namespace aos {
Brian Silverman454bc112020-03-05 14:21:25 -080013namespace event_loop_internal {
Alex Perrycb7da4b2019-08-28 19:35:56 -070014
Brian Silverman454bc112020-03-05 14:21:25 -080015// From a watch functor, specializations of this will extract the message type
16// of the template argument. If T is not a valid message type, there will be no
17// matching specialization.
18//
19// This is just the forward declaration, which will be used by one of the
20// following specializations to match valid argument types.
Alex Perrycb7da4b2019-08-28 19:35:56 -070021template <class T>
Brian Silverman454bc112020-03-05 14:21:25 -080022struct watch_message_type_trait;
Alex Perrycb7da4b2019-08-28 19:35:56 -070023
24// From a watch functor, this will extract the message type of the argument.
25// This is the template specialization.
26template <class ClassType, class ReturnType, class A1>
27struct watch_message_type_trait<ReturnType (ClassType::*)(A1) const> {
28 using message_type = typename std::decay<A1>::type;
29};
30
Brian Silverman454bc112020-03-05 14:21:25 -080031} // namespace event_loop_internal
32
Alex Perrycb7da4b2019-08-28 19:35:56 -070033template <typename T>
34typename Sender<T>::Builder Sender<T>::MakeBuilder() {
Brian Silvermana1652f32020-01-29 20:41:44 -080035 return Builder(sender_.get(), sender_->fbb_allocator());
Alex Perrycb7da4b2019-08-28 19:35:56 -070036}
37
38template <typename Watch>
James Kuszmaul3ae42262019-11-08 12:33:41 -080039void EventLoop::MakeWatcher(const std::string_view channel_name, Watch &&w) {
Brian Silverman454bc112020-03-05 14:21:25 -080040 using MessageType =
41 typename event_loop_internal::watch_message_type_trait<decltype(
42 &Watch::operator())>::message_type;
Alex Perrycb7da4b2019-08-28 19:35:56 -070043 const Channel *channel = configuration::GetChannel(
Brian Silverman454bc112020-03-05 14:21:25 -080044 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
45 name(), node());
Alex Perrycb7da4b2019-08-28 19:35:56 -070046
47 CHECK(channel != nullptr)
48 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
Brian Silverman454bc112020-03-05 14:21:25 -080049 << MessageType::GetFullyQualifiedName() << "\" } not found in config.";
Alex Perrycb7da4b2019-08-28 19:35:56 -070050
Brian Silverman454bc112020-03-05 14:21:25 -080051 MakeRawWatcher(channel,
52 [this, w](const Context &context, const void *message) {
53 context_ = context;
54 w(*flatbuffers::GetRoot<MessageType>(
55 reinterpret_cast<const char *>(message)));
56 });
57}
58
59template <typename MessageType>
60void EventLoop::MakeNoArgWatcher(const std::string_view channel_name,
61 std::function<void()> w) {
62 const Channel *channel = configuration::GetChannel(
63 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
64 name(), node());
65 CHECK(channel != nullptr)
66 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
67 << MessageType::GetFullyQualifiedName() << "\" } not found in config.";
68 MakeRawNoArgWatcher(channel, [this, w](const Context &context) {
69 context_ = context;
70 w();
71 });
Alex Perrycb7da4b2019-08-28 19:35:56 -070072}
73
Austin Schuh39788ff2019-12-01 18:22:57 -080074inline bool RawFetcher::FetchNext() {
75 const auto result = DoFetchNext();
76 if (result.first) {
77 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
78 const monotonic_clock::time_point monotonic_time = result.second;
Brian Silverman79ec7fc2020-06-08 20:11:22 -050079 ftrace_.FormatMessage(
80 "%.*s: fetch next: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
81 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
82 static_cast<int64_t>(monotonic_time.time_since_epoch().count()),
83 static_cast<int64_t>(
84 context_.monotonic_event_time.time_since_epoch().count()),
85 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -080086 const float latency =
87 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -080088 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080089 .count();
90 timing_.latency.Add(latency);
91 return true;
92 }
Brian Silverman79ec7fc2020-06-08 20:11:22 -050093 ftrace_.FormatMessage(
94 "%.*s: fetch next: still event=%" PRId64 " queue=%" PRIu32,
95 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
96 static_cast<int64_t>(
97 context_.monotonic_event_time.time_since_epoch().count()),
98 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -080099 return false;
100}
101
102inline bool RawFetcher::Fetch() {
103 const auto result = DoFetch();
104 if (result.first) {
105 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
106 const monotonic_clock::time_point monotonic_time = result.second;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500107 ftrace_.FormatMessage(
108 "%.*s: fetch latest: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
109 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
110 static_cast<int64_t>(monotonic_time.time_since_epoch().count()),
111 static_cast<int64_t>(
112 context_.monotonic_event_time.time_since_epoch().count()),
113 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800114 const float latency =
115 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800116 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800117 .count();
118 timing_.latency.Add(latency);
119 return true;
120 }
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500121 ftrace_.FormatMessage(
122 "%.*s: fetch latest: still event=%" PRId64 " queue=%" PRIu32,
123 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
124 static_cast<int64_t>(
125 context_.monotonic_event_time.time_since_epoch().count()),
126 context_.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800127 return false;
128}
129
Austin Schuhad154822019-12-27 15:45:13 -0800130inline bool RawSender::Send(
131 size_t size, aos::monotonic_clock::time_point monotonic_remote_time,
132 aos::realtime_clock::time_point realtime_remote_time,
133 uint32_t remote_queue_index) {
134 if (DoSend(size, monotonic_remote_time, realtime_remote_time,
135 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800136 timing_.size.Add(size);
137 timing_.sender->mutate_count(timing_.sender->count() + 1);
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500138 ftrace_.FormatMessage(
139 "%.*s: sent internal: event=%" PRId64 " queue=%" PRIu32,
140 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
141 static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
142 sent_queue_index());
Austin Schuh39788ff2019-12-01 18:22:57 -0800143 return true;
144 }
145 return false;
146}
147
Austin Schuhad154822019-12-27 15:45:13 -0800148inline bool RawSender::Send(
149 const void *data, size_t size,
150 aos::monotonic_clock::time_point monotonic_remote_time,
151 aos::realtime_clock::time_point realtime_remote_time,
152 uint32_t remote_queue_index) {
153 if (DoSend(data, size, monotonic_remote_time, realtime_remote_time,
154 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800155 timing_.size.Add(size);
156 timing_.sender->mutate_count(timing_.sender->count() + 1);
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500157 ftrace_.FormatMessage(
158 "%.*s: sent external: event=%" PRId64 " queue=%" PRIu32,
159 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
160 static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
161 sent_queue_index());
Austin Schuh39788ff2019-12-01 18:22:57 -0800162 return true;
163 }
164 return false;
165}
166
Austin Schuhcde39fd2020-02-22 20:58:24 -0800167inline monotonic_clock::time_point TimerHandler::Call(
Austin Schuh39788ff2019-12-01 18:22:57 -0800168 std::function<monotonic_clock::time_point()> get_time,
169 monotonic_clock::time_point event_time) {
170 CHECK_NOTNULL(timing_.timer);
171 const monotonic_clock::time_point monotonic_start_time = get_time();
172
Austin Schuhad154822019-12-27 15:45:13 -0800173 event_loop_->context_.monotonic_event_time = event_time;
174 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
175 event_loop_->context_.realtime_remote_time =
176 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800177 event_loop_->context_.queue_index = 0xffffffffu;
178 event_loop_->context_.size = 0;
179 event_loop_->context_.data = nullptr;
Brian Silverman4f4e0612020-08-12 19:54:41 -0700180 event_loop_->context_.buffer_index = -1;
Austin Schuh39788ff2019-12-01 18:22:57 -0800181
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500182 ftrace_.FormatMessage(
183 "timer: %.*s: start now=%" PRId64 " event=%" PRId64,
184 static_cast<int>(name_.size()), name_.data(),
185 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
186 static_cast<int64_t>(event_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800187 {
188 const float start_latency =
189 std::chrono::duration_cast<std::chrono::duration<float>>(
190 monotonic_start_time - event_time)
191 .count();
192 timing_.wakeup_latency.Add(start_latency);
193 }
194 timing_.timer->mutate_count(timing_.timer->count() + 1);
195 fn_();
196
197 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500198 ftrace_.FormatMessage(
199 "timer: %.*s: end now=%" PRId64, static_cast<int>(name_.size()),
200 name_.data(),
201 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800202
203 const float handler_latency =
204 std::chrono::duration_cast<std::chrono::duration<float>>(
205 monotonic_end_time - monotonic_start_time)
206 .count();
207 timing_.handler_time.Add(handler_latency);
Austin Schuhcde39fd2020-02-22 20:58:24 -0800208 return monotonic_start_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800209}
210
211inline void PhasedLoopHandler::Call(
212 std::function<monotonic_clock::time_point()> get_time,
213 std::function<void(monotonic_clock::time_point)> schedule) {
214 // Read time directly to save a vtable indirection...
215 const monotonic_clock::time_point monotonic_start_time = get_time();
216
217 // Update the context to hold the desired wakeup time.
Austin Schuhad154822019-12-27 15:45:13 -0800218 event_loop_->context_.monotonic_event_time = phased_loop_.sleep_time();
219 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
220 event_loop_->context_.realtime_remote_time =
221 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800222 event_loop_->context_.queue_index = 0xffffffffu;
223 event_loop_->context_.size = 0;
224 event_loop_->context_.data = nullptr;
Brian Silverman4f4e0612020-08-12 19:54:41 -0700225 event_loop_->context_.buffer_index = -1;
Austin Schuh39788ff2019-12-01 18:22:57 -0800226
227 // Compute how many cycles elapsed and schedule the next wakeup.
228 Reschedule(schedule, monotonic_start_time);
229
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500230 ftrace_.FormatMessage(
231 "phased: %.*s: start now=%" PRId64 " event=%" PRId64 " cycles=%d",
232 static_cast<int>(name_.size()), name_.data(),
233 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
234 static_cast<int64_t>(
235 phased_loop_.sleep_time().time_since_epoch().count()),
236 cycles_elapsed_);
Austin Schuh39788ff2019-12-01 18:22:57 -0800237 {
238 const float start_latency =
239 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800240 monotonic_start_time - event_loop_->context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800241 .count();
242 timing_.wakeup_latency.Add(start_latency);
243 }
244 timing_.timer->mutate_count(timing_.timer->count() + 1);
245
246 // Call the function with the elapsed cycles.
247 fn_(cycles_elapsed_);
248 cycles_elapsed_ = 0;
249
250 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500251 ftrace_.FormatMessage(
252 "phased: %.*s: end now=%" PRId64, static_cast<int>(name_.size()),
253 name_.data(),
254 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800255
256 const float handler_latency =
257 std::chrono::duration_cast<std::chrono::duration<float>>(
258 monotonic_end_time - monotonic_start_time)
259 .count();
260 timing_.handler_time.Add(handler_latency);
261
Brian Silvermanaf9a4d82020-10-06 15:10:58 -0700262 // If the handler took too long so we blew by the previous deadline, we
Austin Schuh91ba6392020-10-03 13:27:47 -0700263 // want to just try for the next deadline. Reschedule.
Austin Schuh39788ff2019-12-01 18:22:57 -0800264 if (monotonic_end_time > phased_loop_.sleep_time()) {
265 Reschedule(schedule, monotonic_end_time);
266 }
267}
268
269// Class to automate the timing report generation for watchers.
270class WatcherState {
271 public:
272 WatcherState(
273 EventLoop *event_loop, const Channel *channel,
274 std::function<void(const Context &context, const void *message)> fn)
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500275 : channel_index_(event_loop->ChannelIndex(channel)),
276 ftrace_prefix_(configuration::StrippedChannelToString(channel)),
277 fn_(std::move(fn)) {}
Austin Schuh39788ff2019-12-01 18:22:57 -0800278
279 virtual ~WatcherState() {}
280
281 // Calls the callback, measuring time with get_time, with the provided
282 // context.
283 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
284 Context context) {
Brian Silverman6b8a3c32020-03-06 11:26:14 -0800285 if (context.data) {
286 CheckChannelDataAlignment(context.data, context.size);
287 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800288 const monotonic_clock::time_point monotonic_start_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500289 ftrace_.FormatMessage(
290 "%.*s: watcher start: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
291 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
292 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
293 static_cast<int64_t>(
294 context.monotonic_event_time.time_since_epoch().count()),
295 context.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800296 {
297 const float start_latency =
298 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800299 monotonic_start_time - context.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800300 .count();
301 wakeup_latency_.Add(start_latency);
302 }
303 watcher_->mutate_count(watcher_->count() + 1);
304 fn_(context, context.data);
305
306 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500307 ftrace_.FormatMessage(
308 "%.*s: watcher end: now=%" PRId64,
309 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
310 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800311
312 const float handler_latency =
313 std::chrono::duration_cast<std::chrono::duration<float>>(
314 monotonic_end_time - monotonic_start_time)
315 .count();
316 handler_time_.Add(handler_latency);
317 }
318
319 int channel_index() const { return channel_index_; }
320
321 void set_timing_report(timing::Watcher *watcher);
322 void ResetReport();
323
324 virtual void Startup(EventLoop *event_loop) = 0;
325
326 protected:
327 const int channel_index_;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500328 const std::string ftrace_prefix_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800329
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500330 const std::function<void(const Context &context, const void *message)> fn_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800331
332 internal::TimingStatistic wakeup_latency_;
333 internal::TimingStatistic handler_time_;
334 timing::Watcher *watcher_ = nullptr;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500335
336 Ftrace ftrace_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800337};
338
Austin Schuha28cbc32019-12-27 16:28:04 -0800339template <typename T>
340bool Sender<T>::Send(const Flatbuffer<T> &flatbuffer) {
341 return sender_->Send(flatbuffer.data(), flatbuffer.size());
342}
343
Brian Silverman341b57e2020-06-23 16:23:18 -0700344template <typename T>
345bool Sender<T>::SendDetached(FlatbufferDetachedBuffer<T> detached) {
346 CHECK_EQ(
347 static_cast<void *>(detached.data() + detached.size() - sender_->size()),
348 sender_->data())
349 << ": May only send the buffer detached from this Sender";
350 return sender_->Send(detached.size());
351}
352
Alex Perrycb7da4b2019-08-28 19:35:56 -0700353} // namespace aos
354
355#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H