blob: 0d7b419ff44e2c3f237f292fa5c54058f6d68315 [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(
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
Austin Schuh217a9782019-12-21 23:02:50 -080039 if (node() != nullptr) {
40 if (!configuration::ChannelIsReadableOnNode(channel, node())) {
41 LOG(FATAL) << "Channel { \"name\": \"" << channel_name
42 << "\", \"type\": \"" << T::GetFullyQualifiedName()
43 << "\" } is not able to be watched on this node. Check your "
44 "configuration.";
45 }
46 }
47
Alex Perrycb7da4b2019-08-28 19:35:56 -070048 return MakeRawWatcher(
49 channel, [this, w](const Context &context, const void *message) {
50 context_ = context;
51 w(*flatbuffers::GetRoot<T>(reinterpret_cast<const char *>(message)));
52 });
53}
54
Austin Schuh39788ff2019-12-01 18:22:57 -080055inline bool RawFetcher::FetchNext() {
56 const auto result = DoFetchNext();
57 if (result.first) {
58 timing_.fetcher->mutate_count(timing_.fetcher->count() + 1);
59 const monotonic_clock::time_point monotonic_time = result.second;
60 const float latency =
61 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -080062 monotonic_time - context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -080063 .count();
64 timing_.latency.Add(latency);
65 return true;
66 }
67 return false;
68}
69
70inline bool RawFetcher::Fetch() {
71 const auto result = DoFetch();
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
Austin Schuhad154822019-12-27 15:45:13 -080085inline bool RawSender::Send(
86 size_t size, aos::monotonic_clock::time_point monotonic_remote_time,
87 aos::realtime_clock::time_point realtime_remote_time,
88 uint32_t remote_queue_index) {
89 if (DoSend(size, monotonic_remote_time, realtime_remote_time,
90 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -080091 timing_.size.Add(size);
92 timing_.sender->mutate_count(timing_.sender->count() + 1);
93 return true;
94 }
95 return false;
96}
97
Austin Schuhad154822019-12-27 15:45:13 -080098inline bool RawSender::Send(
99 const void *data, size_t size,
100 aos::monotonic_clock::time_point monotonic_remote_time,
101 aos::realtime_clock::time_point realtime_remote_time,
102 uint32_t remote_queue_index) {
103 if (DoSend(data, size, monotonic_remote_time, realtime_remote_time,
104 remote_queue_index)) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800105 timing_.size.Add(size);
106 timing_.sender->mutate_count(timing_.sender->count() + 1);
107 return true;
108 }
109 return false;
110}
111
112inline void TimerHandler::Call(
113 std::function<monotonic_clock::time_point()> get_time,
114 monotonic_clock::time_point event_time) {
115 CHECK_NOTNULL(timing_.timer);
116 const monotonic_clock::time_point monotonic_start_time = get_time();
117
Austin Schuhad154822019-12-27 15:45:13 -0800118 event_loop_->context_.monotonic_event_time = event_time;
119 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
120 event_loop_->context_.realtime_remote_time =
121 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800122 event_loop_->context_.queue_index = 0xffffffffu;
123 event_loop_->context_.size = 0;
124 event_loop_->context_.data = nullptr;
125
126 {
127 const float start_latency =
128 std::chrono::duration_cast<std::chrono::duration<float>>(
129 monotonic_start_time - event_time)
130 .count();
131 timing_.wakeup_latency.Add(start_latency);
132 }
133 timing_.timer->mutate_count(timing_.timer->count() + 1);
134 fn_();
135
136 const monotonic_clock::time_point monotonic_end_time = get_time();
137
138 const float handler_latency =
139 std::chrono::duration_cast<std::chrono::duration<float>>(
140 monotonic_end_time - monotonic_start_time)
141 .count();
142 timing_.handler_time.Add(handler_latency);
143}
144
145inline void PhasedLoopHandler::Call(
146 std::function<monotonic_clock::time_point()> get_time,
147 std::function<void(monotonic_clock::time_point)> schedule) {
148 // Read time directly to save a vtable indirection...
149 const monotonic_clock::time_point monotonic_start_time = get_time();
150
151 // Update the context to hold the desired wakeup time.
Austin Schuhad154822019-12-27 15:45:13 -0800152 event_loop_->context_.monotonic_event_time = phased_loop_.sleep_time();
153 event_loop_->context_.monotonic_remote_time = monotonic_clock::min_time;
154 event_loop_->context_.realtime_remote_time =
155 event_loop_->context_.realtime_event_time = realtime_clock::min_time;
Austin Schuh39788ff2019-12-01 18:22:57 -0800156 event_loop_->context_.queue_index = 0xffffffffu;
157 event_loop_->context_.size = 0;
158 event_loop_->context_.data = nullptr;
159
160 // Compute how many cycles elapsed and schedule the next wakeup.
161 Reschedule(schedule, monotonic_start_time);
162
163 {
164 const float start_latency =
165 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800166 monotonic_start_time - event_loop_->context_.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800167 .count();
168 timing_.wakeup_latency.Add(start_latency);
169 }
170 timing_.timer->mutate_count(timing_.timer->count() + 1);
171
172 // Call the function with the elapsed cycles.
173 fn_(cycles_elapsed_);
174 cycles_elapsed_ = 0;
175
176 const monotonic_clock::time_point monotonic_end_time = get_time();
177
178 const float handler_latency =
179 std::chrono::duration_cast<std::chrono::duration<float>>(
180 monotonic_end_time - monotonic_start_time)
181 .count();
182 timing_.handler_time.Add(handler_latency);
183
184 // If the handler too too long so we blew by the previous deadline, we
185 // want to just try for the next deadline. Rescuedule.
186 if (monotonic_end_time > phased_loop_.sleep_time()) {
187 Reschedule(schedule, monotonic_end_time);
188 }
189}
190
191// Class to automate the timing report generation for watchers.
192class WatcherState {
193 public:
194 WatcherState(
195 EventLoop *event_loop, const Channel *channel,
196 std::function<void(const Context &context, const void *message)> fn)
197 : channel_index_(event_loop->ChannelIndex(channel)), fn_(std::move(fn)) {}
198
199 virtual ~WatcherState() {}
200
201 // Calls the callback, measuring time with get_time, with the provided
202 // context.
203 void DoCallCallback(std::function<monotonic_clock::time_point()> get_time,
204 Context context) {
205 const monotonic_clock::time_point monotonic_start_time = get_time();
206 {
207 const float start_latency =
208 std::chrono::duration_cast<std::chrono::duration<float>>(
Austin Schuhad154822019-12-27 15:45:13 -0800209 monotonic_start_time - context.monotonic_event_time)
Austin Schuh39788ff2019-12-01 18:22:57 -0800210 .count();
211 wakeup_latency_.Add(start_latency);
212 }
213 watcher_->mutate_count(watcher_->count() + 1);
214 fn_(context, context.data);
215
216 const monotonic_clock::time_point monotonic_end_time = get_time();
217
218 const float handler_latency =
219 std::chrono::duration_cast<std::chrono::duration<float>>(
220 monotonic_end_time - monotonic_start_time)
221 .count();
222 handler_time_.Add(handler_latency);
223 }
224
225 int channel_index() const { return channel_index_; }
226
227 void set_timing_report(timing::Watcher *watcher);
228 void ResetReport();
229
230 virtual void Startup(EventLoop *event_loop) = 0;
231
232 protected:
233 const int channel_index_;
234
235 std::function<void(const Context &context, const void *message)> fn_;
236
237 internal::TimingStatistic wakeup_latency_;
238 internal::TimingStatistic handler_time_;
239 timing::Watcher *watcher_ = nullptr;
240};
241
Austin Schuha28cbc32019-12-27 16:28:04 -0800242template <typename T>
243bool Sender<T>::Send(const Flatbuffer<T> &flatbuffer) {
244 return sender_->Send(flatbuffer.data(), flatbuffer.size());
245}
246
Alex Perrycb7da4b2019-08-28 19:35:56 -0700247} // namespace aos
248
249#endif // AOS_EVENTS_EVENT_LOOP_TMPL_H