blob: a4b3822946505c4df02b3794202d197ff1d776e5 [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#ifndef AOS_EVENTS_SIMULATED_EVENT_LOOP_H_
2#define AOS_EVENTS_SIMULATED_EVENT_LOOP_H_
3
4#include <algorithm>
Brian Silverman601b9722020-06-18 14:33:43 -07005#include <functional>
Alex Perrycb7da4b2019-08-28 19:35:56 -07006#include <map>
7#include <memory>
Austin Schuh5f1cc5c2019-12-01 18:01:11 -08008#include <string_view>
Alex Perrycb7da4b2019-08-28 19:35:56 -07009#include <unordered_set>
10#include <utility>
11#include <vector>
12
13#include "absl/container/btree_map.h"
14#include "aos/events/event_loop.h"
15#include "aos/events/event_scheduler.h"
Austin Schuhe1dafe42020-01-06 21:12:03 -080016#include "aos/events/simple_channel.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070017#include "aos/flatbuffer_merge.h"
18#include "aos/flatbuffers.h"
19#include "aos/ipc_lib/index.h"
20#include "glog/logging.h"
21
22namespace aos {
23
24// Class for simulated fetchers.
25class SimulatedChannel;
26
Austin Schuhac0771c2020-01-07 18:36:30 -080027class NodeEventLoopFactory;
Austin Schuh898f4972020-01-11 17:21:25 -080028namespace message_bridge {
29class SimulatedMessageBridge;
30}
Austin Schuhac0771c2020-01-07 18:36:30 -080031
32// There are 2 concepts needed to support multi-node simulations.
33// 1) The node. This is implemented with NodeEventLoopFactory.
34// 2) The "robot" which runs multiple nodes. This is implemented with
35// SimulatedEventLoopFactory.
36//
37// To make things easier, SimulatedEventLoopFactory takes an optional Node
38// argument if you want to make event loops without interacting with the
39// NodeEventLoopFactory object.
40//
41// The basic flow goes something like as follows:
42//
43// SimulatedEventLoopFactory factory(config);
44// const Node *pi1 = configuration::GetNode(factory.configuration(), "pi1");
45// std::unique_ptr<EventLoop> event_loop = factory.MakeEventLoop("ping", pi1);
46//
47// Or
48//
49// SimulatedEventLoopFactory factory(config);
50// const Node *pi1 = configuration::GetNode(factory.configuration(), "pi1");
51// NodeEventLoopFactory *pi1_factory = factory.GetNodeEventLoopFactory(pi1);
52// std::unique_ptr<EventLoop> event_loop = pi1_factory.MakeEventLoop("ping");
53//
54// The distributed_clock is used to be the base time. NodeEventLoopFactory has
55// all the information needed to adjust both the realtime and monotonic clocks
56// relative to the distributed_clock.
Alex Perrycb7da4b2019-08-28 19:35:56 -070057class SimulatedEventLoopFactory {
58 public:
59 // Constructs a SimulatedEventLoopFactory with the provided configuration.
60 // This configuration must remain in scope for the lifetime of the factory and
61 // all sub-objects.
62 SimulatedEventLoopFactory(const Configuration *configuration);
63 ~SimulatedEventLoopFactory();
64
Austin Schuhac0771c2020-01-07 18:36:30 -080065 // Creates an event loop. If running in a multi-node environment, node needs
66 // to point to the node to create this event loop on.
67 ::std::unique_ptr<EventLoop> MakeEventLoop(std::string_view name,
68 const Node *node = nullptr);
69
70 // Returns the NodeEventLoopFactory for the provided node. The returned
71 // NodeEventLoopFactory is owned by the SimulatedEventLoopFactory and has a
72 // lifetime identical to the factory.
73 NodeEventLoopFactory *GetNodeEventLoopFactory(const Node *node);
Alex Perrycb7da4b2019-08-28 19:35:56 -070074
75 // Starts executing the event loops unconditionally.
76 void Run();
77 // Executes the event loops for a duration.
Austin Schuhac0771c2020-01-07 18:36:30 -080078 void RunFor(distributed_clock::duration duration);
Alex Perrycb7da4b2019-08-28 19:35:56 -070079
80 // Stops executing all event loops. Meant to be called from within an event
81 // loop handler.
Austin Schuh8bd96322020-02-13 21:18:22 -080082 void Exit() { scheduler_scheduler_.Exit(); }
Alex Perrycb7da4b2019-08-28 19:35:56 -070083
Austin Schuhac0771c2020-01-07 18:36:30 -080084 const std::vector<const Node *> &nodes() const { return nodes_; }
85
86 // Sets the simulated send delay for all messages sent within a single node.
Austin Schuh7d87b672019-12-01 20:23:49 -080087 void set_send_delay(std::chrono::nanoseconds send_delay);
Austin Schuhac0771c2020-01-07 18:36:30 -080088 std::chrono::nanoseconds send_delay() const { return send_delay_; }
89
90 // Sets the simulated network delay for messages forwarded between nodes.
Brian Silvermana7c62052020-04-28 16:52:27 -070091 void set_network_delay(std::chrono::nanoseconds network_delay) {
92 network_delay_ = network_delay;
93 }
Austin Schuhac0771c2020-01-07 18:36:30 -080094 std::chrono::nanoseconds network_delay() const { return network_delay_; }
95
96 // Returns the clock used to synchronize the nodes.
97 distributed_clock::time_point distributed_now() const {
Austin Schuh8bd96322020-02-13 21:18:22 -080098 return scheduler_scheduler_.distributed_now();
Austin Schuhac0771c2020-01-07 18:36:30 -080099 }
100
101 // Returns the configuration used for everything.
102 const Configuration *configuration() const { return configuration_; }
103
Austin Schuh6f3babe2020-01-26 20:34:50 -0800104 // Disables forwarding for this channel. This should be used very rarely only
105 // for things like the logger.
106 void DisableForwarding(const Channel *channel);
107
Austin Schuh4c3b9702020-08-30 11:34:55 -0700108 // Disables the messages sent by the simulated message gateway.
109 void DisableStatistics();
110
Austin Schuhac0771c2020-01-07 18:36:30 -0800111 private:
112 const Configuration *const configuration_;
Austin Schuh8bd96322020-02-13 21:18:22 -0800113 EventSchedulerScheduler scheduler_scheduler_;
Austin Schuhac0771c2020-01-07 18:36:30 -0800114 // List of event loops to manage running and not running for.
115 // The function is a callback used to set and clear the running bool on each
116 // event loop.
117 std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
118 raw_event_loops_;
119
120 std::chrono::nanoseconds send_delay_ = std::chrono::microseconds(50);
121 std::chrono::nanoseconds network_delay_ = std::chrono::microseconds(100);
122
123 std::vector<std::unique_ptr<NodeEventLoopFactory>> node_factories_;
124
125 std::vector<const Node *> nodes_;
Austin Schuh898f4972020-01-11 17:21:25 -0800126
127 std::unique_ptr<message_bridge::SimulatedMessageBridge> bridge_;
Austin Schuhac0771c2020-01-07 18:36:30 -0800128};
129
130// This class holds all the state required to be a single node.
131class NodeEventLoopFactory {
132 public:
133 ::std::unique_ptr<EventLoop> MakeEventLoop(std::string_view name);
Austin Schuh7d87b672019-12-01 20:23:49 -0800134
Austin Schuh217a9782019-12-21 23:02:50 -0800135 // Returns the node that this factory is running as, or nullptr if this is a
136 // single node setup.
137 const Node *node() const { return node_; }
138
Austin Schuh92547522019-12-28 14:33:43 -0800139 // Sets realtime clock to realtime_now for a given monotonic clock.
140 void SetRealtimeOffset(monotonic_clock::time_point monotonic_now,
141 realtime_clock::time_point realtime_now) {
Austin Schuhac0771c2020-01-07 18:36:30 -0800142 realtime_offset_ =
143 realtime_now.time_since_epoch() - monotonic_now.time_since_epoch();
Austin Schuh92547522019-12-28 14:33:43 -0800144 }
145
Austin Schuhac0771c2020-01-07 18:36:30 -0800146 // Returns the current time on both clocks.
147 inline monotonic_clock::time_point monotonic_now() const;
148 inline realtime_clock::time_point realtime_now() const;
Austin Schuh39788ff2019-12-01 18:22:57 -0800149
Austin Schuhfaec5e12020-11-05 17:39:55 -0800150 const Configuration *configuration() const {
151 return factory_->configuration();
152 }
153
Austin Schuh898f4972020-01-11 17:21:25 -0800154 // Returns the simulated network delay for messages forwarded between nodes.
155 std::chrono::nanoseconds network_delay() const {
156 return factory_->network_delay();
157 }
158 // Returns the simulated send delay for all messages sent within a single
159 // node.
160 std::chrono::nanoseconds send_delay() const { return factory_->send_delay(); }
161
Austin Schuh8bd96322020-02-13 21:18:22 -0800162 // TODO(austin): Private for the following?
163
Austin Schuhac0771c2020-01-07 18:36:30 -0800164 // Converts a time to the distributed clock for scheduling and cross-node time
165 // measurement.
166 inline distributed_clock::time_point ToDistributedClock(
167 monotonic_clock::time_point time) const;
Austin Schuhbe69cf32020-08-27 11:38:33 -0700168 inline monotonic_clock::time_point FromDistributedClock(
169 distributed_clock::time_point time) const;
Austin Schuhac0771c2020-01-07 18:36:30 -0800170
Austin Schuh8bd96322020-02-13 21:18:22 -0800171 // Sets the offset between the monotonic clock and the central distributed
172 // clock. distributed_clock = monotonic_clock + offset.
Austin Schuhbe69cf32020-08-27 11:38:33 -0700173 void SetDistributedOffset(std::chrono::nanoseconds monotonic_offset,
174 double monotonic_slope) {
175 scheduler_.SetDistributedOffset(monotonic_offset, monotonic_slope);
Austin Schuhcde938c2020-02-02 17:30:07 -0800176 }
177
Austin Schuhac0771c2020-01-07 18:36:30 -0800178 private:
179 friend class SimulatedEventLoopFactory;
180 NodeEventLoopFactory(
Austin Schuh8bd96322020-02-13 21:18:22 -0800181 EventSchedulerScheduler *scheduler_scheduler,
182 SimulatedEventLoopFactory *factory, const Node *node,
Austin Schuhac0771c2020-01-07 18:36:30 -0800183 std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
184 *raw_event_loops);
185
Austin Schuh8bd96322020-02-13 21:18:22 -0800186 EventScheduler scheduler_;
Austin Schuhac0771c2020-01-07 18:36:30 -0800187 SimulatedEventLoopFactory *const factory_;
Austin Schuh7d87b672019-12-01 20:23:49 -0800188
Austin Schuh217a9782019-12-21 23:02:50 -0800189 const Node *const node_;
190
Austin Schuhac0771c2020-01-07 18:36:30 -0800191 std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
192 *const raw_event_loops_;
193
Austin Schuhac0771c2020-01-07 18:36:30 -0800194 std::chrono::nanoseconds realtime_offset_ = std::chrono::seconds(0);
195
196 // Map from name, type to queue.
197 absl::btree_map<SimpleChannel, std::unique_ptr<SimulatedChannel>> channels_;
198
199 // pid so we get unique timing reports.
Austin Schuh39788ff2019-12-01 18:22:57 -0800200 pid_t tid_ = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700201};
202
Austin Schuhac0771c2020-01-07 18:36:30 -0800203inline monotonic_clock::time_point NodeEventLoopFactory::monotonic_now() const {
Austin Schuh8bd96322020-02-13 21:18:22 -0800204 // TODO(austin): Confirm that time never goes backwards?
Austin Schuhbe69cf32020-08-27 11:38:33 -0700205 return scheduler_.monotonic_now();
Austin Schuhac0771c2020-01-07 18:36:30 -0800206}
207
208inline realtime_clock::time_point NodeEventLoopFactory::realtime_now() const {
209 return realtime_clock::time_point(monotonic_now().time_since_epoch() +
210 realtime_offset_);
211}
212
Austin Schuhbe69cf32020-08-27 11:38:33 -0700213inline monotonic_clock::time_point NodeEventLoopFactory::FromDistributedClock(
214 distributed_clock::time_point time) const {
215 return scheduler_.FromDistributedClock(time);
216}
217
Austin Schuhac0771c2020-01-07 18:36:30 -0800218inline distributed_clock::time_point NodeEventLoopFactory::ToDistributedClock(
219 monotonic_clock::time_point time) const {
Austin Schuh8bd96322020-02-13 21:18:22 -0800220 return scheduler_.ToDistributedClock(time);
Austin Schuhac0771c2020-01-07 18:36:30 -0800221}
222
Alex Perrycb7da4b2019-08-28 19:35:56 -0700223} // namespace aos
224
225#endif // AOS_EVENTS_SIMULATED_EVENT_LOOP_H_