blob: 6c3944ccbc2c762145da0cc4198a495f1c1a1405 [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 {
Brian Silverman454bc112020-03-05 14:21:25 -08009namespace event_loop_internal {
Alex Perrycb7da4b2019-08-28 19:35:56 -070010
Brian Silverman454bc112020-03-05 14:21:25 -080011// From a watch functor, specializations of this will extract the message type
12// of the template argument. If T is not a valid message type, there will be no
13// matching specialization.
14//
15// This is just the forward declaration, which will be used by one of the
16// following specializations to match valid argument types.
Alex Perrycb7da4b2019-08-28 19:35:56 -070017template <class T>
Brian Silverman454bc112020-03-05 14:21:25 -080018struct watch_message_type_trait;
Alex Perrycb7da4b2019-08-28 19:35:56 -070019
20// From a watch functor, this will extract the message type of the argument.
21// This is the template specialization.
22template <class ClassType, class ReturnType, class A1>
23struct watch_message_type_trait<ReturnType (ClassType::*)(A1) const> {
24 using message_type = typename std::decay<A1>::type;
25};
26
Brian Silverman454bc112020-03-05 14:21:25 -080027} // namespace event_loop_internal
28
Alex Perrycb7da4b2019-08-28 19:35:56 -070029template <typename T>
30typename Sender<T>::Builder Sender<T>::MakeBuilder() {
Brian Silvermana1652f32020-01-29 20:41:44 -080031 return Builder(sender_.get(), sender_->fbb_allocator());
Alex Perrycb7da4b2019-08-28 19:35:56 -070032}
33
34template <typename Watch>
James Kuszmaul3ae42262019-11-08 12:33:41 -080035void EventLoop::MakeWatcher(const std::string_view channel_name, Watch &&w) {
Brian Silverman454bc112020-03-05 14:21:25 -080036 using MessageType =
37 typename event_loop_internal::watch_message_type_trait<decltype(
38 &Watch::operator())>::message_type;
Alex Perrycb7da4b2019-08-28 19:35:56 -070039 const Channel *channel = configuration::GetChannel(
Brian Silverman454bc112020-03-05 14:21:25 -080040 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
41 name(), node());
Alex Perrycb7da4b2019-08-28 19:35:56 -070042
43 CHECK(channel != nullptr)
44 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
Brian Silverman454bc112020-03-05 14:21:25 -080045 << MessageType::GetFullyQualifiedName() << "\" } not found in config.";
Alex Perrycb7da4b2019-08-28 19:35:56 -070046
Brian Silverman454bc112020-03-05 14:21:25 -080047 MakeRawWatcher(channel,
48 [this, w](const Context &context, const void *message) {
49 context_ = context;
50 w(*flatbuffers::GetRoot<MessageType>(
51 reinterpret_cast<const char *>(message)));
52 });
53}
54
55template <typename MessageType>
56void EventLoop::MakeNoArgWatcher(const std::string_view channel_name,
57 std::function<void()> w) {
58 const Channel *channel = configuration::GetChannel(
59 configuration_, channel_name, MessageType::GetFullyQualifiedName(),
60 name(), node());
61 CHECK(channel != nullptr)
62 << ": Channel { \"name\": \"" << channel_name << "\", \"type\": \""
63 << MessageType::GetFullyQualifiedName() << "\" } not found in config.";
64 MakeRawNoArgWatcher(channel, [this, w](const Context &context) {
65 context_ = context;
66 w();
67 });
Alex Perrycb7da4b2019-08-28 19:35:56 -070068}
69
Austin Schuh39788ff2019-12-01 18:22:57 -080070inline bool RawFetcher::FetchNext() {
71 const auto result = DoFetchNext();
72 if (result.first) {
73 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
74 const monotonic_clock::time_point monotonic_time = result.second;
75 const float latency =
76 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -080077 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080078 .count();
79 timing_.latency.Add(latency);
80 return true;
81 }
82 return false;
83}
84
85inline bool RawFetcher::Fetch() {
86 const auto result = DoFetch();
87 if (result.first) {
88 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
89 const monotonic_clock::time_point monotonic_time = result.second;
90 const float latency =
91 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -080092 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080093 .count();
94 timing_.latency.Add(latency);
95 return true;
96 }
97 return false;
98}
99
Austin Schuhad154822019-12-27 15:45:13 -0800100inline bool RawSender::Send(
101 size_t size, aos::monotonic_clock::time_point monotonic_remote_time,
102 aos::realtime_clock::time_point realtime_remote_time,
103 uint32_t remote_queue_index) {
104 if (DoSend(size, monotonic_remote_time, realtime_remote_time,
105 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800106 timing_.size.Add(size);
107 timing_.sender->mutate_count(timing_.sender->count() + 1);
108 return true;
109 }
110 return false;
111}
112
Austin Schuhad154822019-12-27 15:45:13 -0800113inline bool RawSender::Send(
114 const void *data, size_t size,
115 aos::monotonic_clock::time_point monotonic_remote_time,
116 aos::realtime_clock::time_point realtime_remote_time,
117 uint32_t remote_queue_index) {
118 if (DoSend(data, size, monotonic_remote_time, realtime_remote_time,
119 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800120 timing_.size.Add(size);
121 timing_.sender->mutate_count(timing_.sender->count() + 1);
122 return true;
123 }
124 return false;
125}
126
Austin Schuhcde39fd2020-02-22 20:58:24 -0800127inline monotonic_clock::time_point TimerHandler::Call(
Austin Schuh39788ff2019-12-01 18:22:57 -0800128 std::function<monotonic_clock::time_point()> get_time,
129 monotonic_clock::time_point event_time) {
130 CHECK_NOTNULL(timing_.timer);
131 const monotonic_clock::time_point monotonic_start_time = get_time();
132
Austin Schuhad154822019-12-27 15:45:13 -0800133 event_loop_->context_.monotonic_event_time = event_time;
134 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
135 event_loop_->context_.realtime_remote_time =
136 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800137 event_loop_->context_.queue_index = 0xffffffffu;
138 event_loop_->context_.size = 0;
139 event_loop_->context_.data = nullptr;
140
141 {
142 const float start_latency =
143 std::chrono::duration_cast<std::chrono::duration<float>>(
144 monotonic_start_time - event_time)
145 .count();
146 timing_.wakeup_latency.Add(start_latency);
147 }
148 timing_.timer->mutate_count(timing_.timer->count() + 1);
149 fn_();
150
151 const monotonic_clock::time_point monotonic_end_time = get_time();
152
153 const float handler_latency =
154 std::chrono::duration_cast<std::chrono::duration<float>>(
155 monotonic_end_time - monotonic_start_time)
156 .count();
157 timing_.handler_time.Add(handler_latency);
Austin Schuhcde39fd2020-02-22 20:58:24 -0800158 return monotonic_start_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800159}
160
161inline void PhasedLoopHandler::Call(
162 std::function<monotonic_clock::time_point()> get_time,
163 std::function<void(monotonic_clock::time_point)> schedule) {
164 // Read time directly to save a vtable indirection...
165 const monotonic_clock::time_point monotonic_start_time = get_time();
166
167 // Update the context to hold the desired wakeup time.
Austin Schuhad154822019-12-27 15:45:13 -0800168 event_loop_->context_.monotonic_event_time = phased_loop_.sleep_time();
169 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
170 event_loop_->context_.realtime_remote_time =
171 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800172 event_loop_->context_.queue_index = 0xffffffffu;
173 event_loop_->context_.size = 0;
174 event_loop_->context_.data = nullptr;
175
176 // Compute how many cycles elapsed and schedule the next wakeup.
177 Reschedule(schedule, monotonic_start_time);
178
179 {
180 const float start_latency =
181 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800182 monotonic_start_time - event_loop_->context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800183 .count();
184 timing_.wakeup_latency.Add(start_latency);
185 }
186 timing_.timer->mutate_count(timing_.timer->count() + 1);
187
188 // Call the function with the elapsed cycles.
189 fn_(cycles_elapsed_);
190 cycles_elapsed_ = 0;
191
192 const monotonic_clock::time_point monotonic_end_time = get_time();
193
194 const float handler_latency =
195 std::chrono::duration_cast<std::chrono::duration<float>>(
196 monotonic_end_time - monotonic_start_time)
197 .count();
198 timing_.handler_time.Add(handler_latency);
199
200 // If the handler too too long so we blew by the previous deadline, we
201 // want to just try for the next deadline. Rescuedule.
202 if (monotonic_end_time > phased_loop_.sleep_time()) {
203 Reschedule(schedule, monotonic_end_time);
204 }
205}
206
207// Class to automate the timing report generation for watchers.
208class WatcherState {
209 public:
210 WatcherState(
211 EventLoop *event_loop, const Channel *channel,
212 std::function<void(const Context &context, const void *message)> fn)
213 : channel_index_(event_loop->ChannelIndex(channel)), fn_(std::move(fn)) {}
214
215 virtual ~WatcherState() {}
216
217 // Calls the callback, measuring time with get_time, with the provided
218 // context.
219 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
220 Context context) {
Brian Silvermana1652f32020-01-29 20:41:44 -0800221 CheckChannelDataAlignment(context.data, context.size);
Austin Schuh39788ff2019-12-01 18:22:57 -0800222 const monotonic_clock::time_point monotonic_start_time = get_time();
223 {
224 const float start_latency =
225 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800226 monotonic_start_time - context.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800227 .count();
228 wakeup_latency_.Add(start_latency);
229 }
230 watcher_->mutate_count(watcher_->count() + 1);
231 fn_(context, context.data);
232
233 const monotonic_clock::time_point monotonic_end_time = get_time();
234
235 const float handler_latency =
236 std::chrono::duration_cast<std::chrono::duration<float>>(
237 monotonic_end_time - monotonic_start_time)
238 .count();
239 handler_time_.Add(handler_latency);
240 }
241
242 int channel_index() const { return channel_index_; }
243
244 void set_timing_report(timing::Watcher *watcher);
245 void ResetReport();
246
247 virtual void Startup(EventLoop *event_loop) = 0;
248
249 protected:
250 const int channel_index_;
251
252 std::function<void(const Context &context, const void *message)> fn_;
253
254 internal::TimingStatistic wakeup_latency_;
255 internal::TimingStatistic handler_time_;
256 timing::Watcher *watcher_ = nullptr;
257};
258
Austin Schuha28cbc32019-12-27 16:28:04 -0800259template <typename T>
260bool Sender<T>::Send(const Flatbuffer<T> &flatbuffer) {
261 return sender_->Send(flatbuffer.data(), flatbuffer.size());
262}
263
Alex Perrycb7da4b2019-08-28 19:35:56 -0700264} // namespace aos
265
266#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H