blob: 698191e935da54b1aa44100a73476e709fb03ffe [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
Tyler Chatowbf0609c2021-07-31 16:13:27 -07004#include <cinttypes>
5#include <cstdint>
Alex Perrycb7da4b2019-08-28 19:35:56 -07006#include <type_traits>
Brian Silverman79ec7fc2020-06-08 20:11:22 -05007
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "aos/events/event_loop.h"
9#include "glog/logging.h"
10
11namespace aos {
Brian Silverman454bc112020-03-05 14:21:25 -080012namespace event_loop_internal {
Alex Perrycb7da4b2019-08-28 19:35:56 -070013
Brian Silverman454bc112020-03-05 14:21:25 -080014// From a watch functor, specializations of this will extract the message type
15// of the template argument. If T is not a valid message type, there will be no
16// matching specialization.
17//
18// This is just the forward declaration, which will be used by one of the
19// following specializations to match valid argument types.
Alex Perrycb7da4b2019-08-28 19:35:56 -070020template <class T>
Brian Silverman454bc112020-03-05 14:21:25 -080021struct watch_message_type_trait;
Alex Perrycb7da4b2019-08-28 19:35:56 -070022
23// From a watch functor, this will extract the message type of the argument.
24// This is the template specialization.
25template <class ClassType, class ReturnType, class A1>
26struct watch_message_type_trait<ReturnType (ClassType::*)(A1) const> {
27 using message_type = typename std::decay<A1>::type;
28};
29
Brian Silverman454bc112020-03-05 14:21:25 -080030} // namespace event_loop_internal
31
Alex Perrycb7da4b2019-08-28 19:35:56 -070032template <typename T>
33typename Sender<T>::Builder Sender<T>::MakeBuilder() {
Brian Silvermana1652f32020-01-29 20:41:44 -080034 return Builder(sender_.get(), sender_->fbb_allocator());
Alex Perrycb7da4b2019-08-28 19:35:56 -070035}
36
37template <typename Watch>
James Kuszmaul3ae42262019-11-08 12:33:41 -080038void EventLoop::MakeWatcher(const std::string_view channel_name, Watch &&w) {
Tyler Chatowbf0609c2021-07-31 16:13:27 -070039 using MessageType = typename event_loop_internal::watch_message_type_trait<
40 decltype(&Watch::operator())>::message_type;
Alex Perrycb7da4b2019-08-28 19:35:56 -070041 const Channel *channel = configuration::GetChannel(
Brian Silverman454bc112020-03-05 14:21:25 -080042 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
43 name(), node());
Alex Perrycb7da4b2019-08-28 19:35:56 -070044
45 CHECK(channel != nullptr)
46 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
Austin Schuhc59a1de2021-02-20 14:47:39 -080047 << MessageType::GetFullyQualifiedName()
48 << "\" } not found in config for application " << name() << ".";
Alex Perrycb7da4b2019-08-28 19:35:56 -070049
Brian Silverman454bc112020-03-05 14:21:25 -080050 MakeRawWatcher(channel,
51 [this, w](const Context &context, const void *message) {
52 context_ = context;
53 w(*flatbuffers::GetRoot<MessageType>(
54 reinterpret_cast<const char *>(message)));
55 });
56}
57
58template <typename MessageType>
59void EventLoop::MakeNoArgWatcher(const std::string_view channel_name,
60 std::function<void()> w) {
61 const Channel *channel = configuration::GetChannel(
62 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
63 name(), node());
64 CHECK(channel != nullptr)
65 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
Austin Schuhc59a1de2021-02-20 14:47:39 -080066 << MessageType::GetFullyQualifiedName()
67 << "\" } not found in config for application " << name() << ".";
Brian Silverman454bc112020-03-05 14:21:25 -080068 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 Schuhb5c6f972021-03-14 21:53:07 -0700130inline bool RawSender::Send(size_t size) {
131 return Send(size, monotonic_clock::min_time, realtime_clock::min_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700132 0xffffffffu, event_loop_->boot_uuid());
Austin Schuhb5c6f972021-03-14 21:53:07 -0700133}
134
Austin Schuhad154822019-12-27 15:45:13 -0800135inline bool RawSender::Send(
136 size_t size, aos::monotonic_clock::time_point monotonic_remote_time,
137 aos::realtime_clock::time_point realtime_remote_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700138 uint32_t remote_queue_index, const UUID &uuid) {
Austin Schuhad154822019-12-27 15:45:13 -0800139 if (DoSend(size, monotonic_remote_time, realtime_remote_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700140 remote_queue_index, uuid)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800141 timing_.size.Add(size);
142 timing_.sender->mutate_count(timing_.sender->count() + 1);
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500143 ftrace_.FormatMessage(
144 "%.*s: sent internal: event=%" PRId64 " queue=%" PRIu32,
145 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
146 static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
147 sent_queue_index());
Austin Schuh39788ff2019-12-01 18:22:57 -0800148 return true;
149 }
150 return false;
151}
152
Austin Schuhb5c6f972021-03-14 21:53:07 -0700153inline bool RawSender::Send(const void *data, size_t size) {
154 return Send(data, size, monotonic_clock::min_time, realtime_clock::min_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700155 0xffffffffu, event_loop_->boot_uuid());
Austin Schuhb5c6f972021-03-14 21:53:07 -0700156}
157
Austin Schuhad154822019-12-27 15:45:13 -0800158inline bool RawSender::Send(
159 const void *data, size_t size,
160 aos::monotonic_clock::time_point monotonic_remote_time,
161 aos::realtime_clock::time_point realtime_remote_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700162 uint32_t remote_queue_index, const UUID &uuid) {
Austin Schuhad154822019-12-27 15:45:13 -0800163 if (DoSend(data, size, monotonic_remote_time, realtime_remote_time,
Austin Schuh8902fa52021-03-14 22:39:24 -0700164 remote_queue_index, uuid)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800165 timing_.size.Add(size);
166 timing_.sender->mutate_count(timing_.sender->count() + 1);
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500167 ftrace_.FormatMessage(
168 "%.*s: sent external: event=%" PRId64 " queue=%" PRIu32,
169 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
170 static_cast<int64_t>(monotonic_sent_time().time_since_epoch().count()),
171 sent_queue_index());
Austin Schuh39788ff2019-12-01 18:22:57 -0800172 return true;
173 }
174 return false;
175}
176
Austin Schuhcde39fd2020-02-22 20:58:24 -0800177inline monotonic_clock::time_point TimerHandler::Call(
Austin Schuh39788ff2019-12-01 18:22:57 -0800178 std::function<monotonic_clock::time_point()> get_time,
179 monotonic_clock::time_point event_time) {
180 CHECK_NOTNULL(timing_.timer);
181 const monotonic_clock::time_point monotonic_start_time = get_time();
182
Austin Schuha9012be2021-07-21 15:19:11 -0700183 event_loop_->SetTimerContext(event_time);
Austin Schuh39788ff2019-12-01 18:22:57 -0800184
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500185 ftrace_.FormatMessage(
186 "timer: %.*s: start now=%" PRId64 " event=%" PRId64,
187 static_cast<int>(name_.size()), name_.data(),
188 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
189 static_cast<int64_t>(event_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800190 {
191 const float start_latency =
192 std::chrono::duration_cast<std::chrono::duration<float>>(
193 monotonic_start_time - event_time)
194 .count();
195 timing_.wakeup_latency.Add(start_latency);
196 }
197 timing_.timer->mutate_count(timing_.timer->count() + 1);
198 fn_();
199
200 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500201 ftrace_.FormatMessage(
202 "timer: %.*s: end now=%" PRId64, static_cast<int>(name_.size()),
203 name_.data(),
204 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800205
206 const float handler_latency =
207 std::chrono::duration_cast<std::chrono::duration<float>>(
208 monotonic_end_time - monotonic_start_time)
209 .count();
210 timing_.handler_time.Add(handler_latency);
Austin Schuhcde39fd2020-02-22 20:58:24 -0800211 return monotonic_start_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800212}
213
214inline void PhasedLoopHandler::Call(
215 std::function<monotonic_clock::time_point()> get_time,
216 std::function<void(monotonic_clock::time_point)> schedule) {
217 // Read time directly to save a vtable indirection...
218 const monotonic_clock::time_point monotonic_start_time = get_time();
219
220 // Update the context to hold the desired wakeup time.
Austin Schuha9012be2021-07-21 15:19:11 -0700221 event_loop_->SetTimerContext(phased_loop_.sleep_time());
Austin Schuh39788ff2019-12-01 18:22:57 -0800222
Milind Upadhyay42589bb2021-05-19 20:05:16 -0700223 // Compute how many cycles elapsed
224 cycles_elapsed_ += phased_loop_.Iterate(monotonic_start_time);
Austin Schuh39788ff2019-12-01 18:22:57 -0800225
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500226 ftrace_.FormatMessage(
227 "phased: %.*s: start now=%" PRId64 " event=%" PRId64 " cycles=%d",
228 static_cast<int>(name_.size()), name_.data(),
229 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
230 static_cast<int64_t>(
231 phased_loop_.sleep_time().time_since_epoch().count()),
232 cycles_elapsed_);
Austin Schuh39788ff2019-12-01 18:22:57 -0800233 {
234 const float start_latency =
235 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800236 monotonic_start_time - event_loop_->context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800237 .count();
238 timing_.wakeup_latency.Add(start_latency);
239 }
240 timing_.timer->mutate_count(timing_.timer->count() + 1);
241
242 // Call the function with the elapsed cycles.
243 fn_(cycles_elapsed_);
244 cycles_elapsed_ = 0;
245
Milind Upadhyay42589bb2021-05-19 20:05:16 -0700246 // Schedule the next wakeup.
247 schedule(phased_loop_.sleep_time());
248
Austin Schuh39788ff2019-12-01 18:22:57 -0800249 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500250 ftrace_.FormatMessage(
251 "phased: %.*s: end now=%" PRId64, static_cast<int>(name_.size()),
252 name_.data(),
253 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800254
255 const float handler_latency =
256 std::chrono::duration_cast<std::chrono::duration<float>>(
257 monotonic_end_time - monotonic_start_time)
258 .count();
259 timing_.handler_time.Add(handler_latency);
260
Brian Silvermanaf9a4d82020-10-06 15:10:58 -0700261 // If the handler took too long so we blew by the previous deadline, we
Austin Schuh91ba6392020-10-03 13:27:47 -0700262 // want to just try for the next deadline. Reschedule.
Austin Schuh39788ff2019-12-01 18:22:57 -0800263 if (monotonic_end_time > phased_loop_.sleep_time()) {
264 Reschedule(schedule, monotonic_end_time);
265 }
266}
267
268// Class to automate the timing report generation for watchers.
269class WatcherState {
270 public:
271 WatcherState(
272 EventLoop *event_loop, const Channel *channel,
273 std::function<void(const Context &context, const void *message)> fn)
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500274 : channel_index_(event_loop->ChannelIndex(channel)),
275 ftrace_prefix_(configuration::StrippedChannelToString(channel)),
276 fn_(std::move(fn)) {}
Austin Schuh39788ff2019-12-01 18:22:57 -0800277
278 virtual ~WatcherState() {}
279
280 // Calls the callback, measuring time with get_time, with the provided
281 // context.
282 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
Austin Schuhc5dc98f2021-06-16 14:52:46 -0700283 Context context) noexcept {
Brian Silverman6b8a3c32020-03-06 11:26:14 -0800284 if (context.data) {
285 CheckChannelDataAlignment(context.data, context.size);
286 }
Austin Schuh39788ff2019-12-01 18:22:57 -0800287 const monotonic_clock::time_point monotonic_start_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500288 ftrace_.FormatMessage(
289 "%.*s: watcher start: now=%" PRId64 " event=%" PRId64 " queue=%" PRIu32,
290 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
291 static_cast<int64_t>(monotonic_start_time.time_since_epoch().count()),
292 static_cast<int64_t>(
293 context.monotonic_event_time.time_since_epoch().count()),
294 context.queue_index);
Austin Schuh39788ff2019-12-01 18:22:57 -0800295 {
296 const float start_latency =
297 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800298 monotonic_start_time - context.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800299 .count();
300 wakeup_latency_.Add(start_latency);
301 }
302 watcher_->mutate_count(watcher_->count() + 1);
303 fn_(context, context.data);
304
305 const monotonic_clock::time_point monotonic_end_time = get_time();
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500306 ftrace_.FormatMessage(
307 "%.*s: watcher end: now=%" PRId64,
308 static_cast<int>(ftrace_prefix_.size()), ftrace_prefix_.data(),
309 static_cast<int64_t>(monotonic_end_time.time_since_epoch().count()));
Austin Schuh39788ff2019-12-01 18:22:57 -0800310
311 const float handler_latency =
312 std::chrono::duration_cast<std::chrono::duration<float>>(
313 monotonic_end_time - monotonic_start_time)
314 .count();
315 handler_time_.Add(handler_latency);
316 }
317
318 int channel_index() const { return channel_index_; }
319
320 void set_timing_report(timing::Watcher *watcher);
321 void ResetReport();
322
323 virtual void Startup(EventLoop *event_loop) = 0;
324
325 protected:
326 const int channel_index_;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500327 const std::string ftrace_prefix_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800328
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500329 const std::function<void(const Context &context, const void *message)> fn_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800330
331 internal::TimingStatistic wakeup_latency_;
332 internal::TimingStatistic handler_time_;
333 timing::Watcher *watcher_ = nullptr;
Brian Silverman79ec7fc2020-06-08 20:11:22 -0500334
335 Ftrace ftrace_;
Austin Schuh39788ff2019-12-01 18:22:57 -0800336};
337
Austin Schuha28cbc32019-12-27 16:28:04 -0800338template <typename T>
Austin Schuhadd6eb32020-11-09 21:24:26 -0800339bool Sender<T>::Send(const NonSizePrefixedFlatbuffer<T> &flatbuffer) {
340 return sender_->Send(flatbuffer.span().data(), flatbuffer.span().size());
Austin Schuha28cbc32019-12-27 16:28:04 -0800341}
342
Brian Silverman341b57e2020-06-23 16:23:18 -0700343template <typename T>
344bool Sender<T>::SendDetached(FlatbufferDetachedBuffer<T> detached) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800345 CHECK_EQ(static_cast<void *>(detached.span().data() + detached.span().size() -
346 sender_->size()),
347 sender_->data())
Brian Silverman341b57e2020-06-23 16:23:18 -0700348 << ": May only send the buffer detached from this Sender";
Austin Schuhadd6eb32020-11-09 21:24:26 -0800349 return sender_->Send(detached.span().size());
Brian Silverman341b57e2020-06-23 16:23:18 -0700350}
351
Alex Perrycb7da4b2019-08-28 19:35:56 -0700352} // namespace aos
353
354#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H