blob: 1daf88c51936cc515644d06794bc3ab54dab4d0e [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() {
Brian Silvermana1652f32020-01-29 20:41:44 -080026 return Builder(sender_.get(), sender_->fbb_allocator());
Alex Perrycb7da4b2019-08-28 19:35:56 -070027}
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(
Austin Schuhbca6cf02019-12-22 17:28:34 -080033 configuration_, channel_name, T::GetFullyQualifiedName(), name(), node());
Alex Perrycb7da4b2019-08-28 19:35:56 -070034
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>>(
Austin Schuhad154822019-12-27 15:45:13 -080053 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080054 .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>>(
Austin Schuhad154822019-12-27 15:45:13 -080068 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080069 .count();
70 timing_.latency.Add(latency);
71 return true;
72 }
73 return false;
74}
75
Austin Schuhad154822019-12-27 15:45:13 -080076inline bool RawSender::Send(
77 size_t size, aos::monotonic_clock::time_point monotonic_remote_time,
78 aos::realtime_clock::time_point realtime_remote_time,
79 uint32_t remote_queue_index) {
80 if (DoSend(size, monotonic_remote_time, realtime_remote_time,
81 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -080082 timing_.size.Add(size);
83 timing_.sender->mutate_count(timing_.sender->count() + 1);
84 return true;
85 }
86 return false;
87}
88
Austin Schuhad154822019-12-27 15:45:13 -080089inline bool RawSender::Send(
90 const void *data, size_t size,
91 aos::monotonic_clock::time_point monotonic_remote_time,
92 aos::realtime_clock::time_point realtime_remote_time,
93 uint32_t remote_queue_index) {
94 if (DoSend(data, size, monotonic_remote_time, realtime_remote_time,
95 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -080096 timing_.size.Add(size);
97 timing_.sender->mutate_count(timing_.sender->count() + 1);
98 return true;
99 }
100 return false;
101}
102
Austin Schuhcde39fd2020-02-22 20:58:24 -0800103inline monotonic_clock::time_point TimerHandler::Call(
Austin Schuh39788ff2019-12-01 18:22:57 -0800104 std::function<monotonic_clock::time_point()> get_time,
105 monotonic_clock::time_point event_time) {
106 CHECK_NOTNULL(timing_.timer);
107 const monotonic_clock::time_point monotonic_start_time = get_time();
108
Austin Schuhad154822019-12-27 15:45:13 -0800109 event_loop_->context_.monotonic_event_time = event_time;
110 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
111 event_loop_->context_.realtime_remote_time =
112 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800113 event_loop_->context_.queue_index = 0xffffffffu;
114 event_loop_->context_.size = 0;
115 event_loop_->context_.data = nullptr;
116
117 {
118 const float start_latency =
119 std::chrono::duration_cast<std::chrono::duration<float>>(
120 monotonic_start_time - event_time)
121 .count();
122 timing_.wakeup_latency.Add(start_latency);
123 }
124 timing_.timer->mutate_count(timing_.timer->count() + 1);
125 fn_();
126
127 const monotonic_clock::time_point monotonic_end_time = get_time();
128
129 const float handler_latency =
130 std::chrono::duration_cast<std::chrono::duration<float>>(
131 monotonic_end_time - monotonic_start_time)
132 .count();
133 timing_.handler_time.Add(handler_latency);
Austin Schuhcde39fd2020-02-22 20:58:24 -0800134 return monotonic_start_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800135}
136
137inline void PhasedLoopHandler::Call(
138 std::function<monotonic_clock::time_point()> get_time,
139 std::function<void(monotonic_clock::time_point)> schedule) {
140 // Read time directly to save a vtable indirection...
141 const monotonic_clock::time_point monotonic_start_time = get_time();
142
143 // Update the context to hold the desired wakeup time.
Austin Schuhad154822019-12-27 15:45:13 -0800144 event_loop_->context_.monotonic_event_time = phased_loop_.sleep_time();
145 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
146 event_loop_->context_.realtime_remote_time =
147 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800148 event_loop_->context_.queue_index = 0xffffffffu;
149 event_loop_->context_.size = 0;
150 event_loop_->context_.data = nullptr;
151
152 // Compute how many cycles elapsed and schedule the next wakeup.
153 Reschedule(schedule, monotonic_start_time);
154
155 {
156 const float start_latency =
157 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800158 monotonic_start_time - event_loop_->context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800159 .count();
160 timing_.wakeup_latency.Add(start_latency);
161 }
162 timing_.timer->mutate_count(timing_.timer->count() + 1);
163
164 // Call the function with the elapsed cycles.
165 fn_(cycles_elapsed_);
166 cycles_elapsed_ = 0;
167
168 const monotonic_clock::time_point monotonic_end_time = get_time();
169
170 const float handler_latency =
171 std::chrono::duration_cast<std::chrono::duration<float>>(
172 monotonic_end_time - monotonic_start_time)
173 .count();
174 timing_.handler_time.Add(handler_latency);
175
176 // If the handler too too long so we blew by the previous deadline, we
177 // want to just try for the next deadline. Rescuedule.
178 if (monotonic_end_time > phased_loop_.sleep_time()) {
179 Reschedule(schedule, monotonic_end_time);
180 }
181}
182
183// Class to automate the timing report generation for watchers.
184class WatcherState {
185 public:
186 WatcherState(
187 EventLoop *event_loop, const Channel *channel,
188 std::function<void(const Context &context, const void *message)> fn)
189 : channel_index_(event_loop->ChannelIndex(channel)), fn_(std::move(fn)) {}
190
191 virtual ~WatcherState() {}
192
193 // Calls the callback, measuring time with get_time, with the provided
194 // context.
195 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
196 Context context) {
Brian Silvermana1652f32020-01-29 20:41:44 -0800197 CheckChannelDataAlignment(context.data, context.size);
Austin Schuh39788ff2019-12-01 18:22:57 -0800198 const monotonic_clock::time_point monotonic_start_time = get_time();
199 {
200 const float start_latency =
201 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800202 monotonic_start_time - context.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800203 .count();
204 wakeup_latency_.Add(start_latency);
205 }
206 watcher_->mutate_count(watcher_->count() + 1);
207 fn_(context, context.data);
208
209 const monotonic_clock::time_point monotonic_end_time = get_time();
210
211 const float handler_latency =
212 std::chrono::duration_cast<std::chrono::duration<float>>(
213 monotonic_end_time - monotonic_start_time)
214 .count();
215 handler_time_.Add(handler_latency);
216 }
217
218 int channel_index() const { return channel_index_; }
219
220 void set_timing_report(timing::Watcher *watcher);
221 void ResetReport();
222
223 virtual void Startup(EventLoop *event_loop) = 0;
224
225 protected:
226 const int channel_index_;
227
228 std::function<void(const Context &context, const void *message)> fn_;
229
230 internal::TimingStatistic wakeup_latency_;
231 internal::TimingStatistic handler_time_;
232 timing::Watcher *watcher_ = nullptr;
233};
234
Austin Schuha28cbc32019-12-27 16:28:04 -0800235template <typename T>
236bool Sender<T>::Send(const Flatbuffer<T> &flatbuffer) {
237 return sender_->Send(flatbuffer.data(), flatbuffer.size());
238}
239
Alex Perrycb7da4b2019-08-28 19:35:56 -0700240} // namespace aos
241
242#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H