blob: 019172b8469cab14ebe58602d0cdc58b575d072f [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>
5#include <map>
6#include <memory>
Austin Schuh5f1cc5c2019-12-01 18:01:11 -08007#include <string_view>
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include <unordered_set>
9#include <utility>
10#include <vector>
11
12#include "absl/container/btree_map.h"
13#include "aos/events/event_loop.h"
14#include "aos/events/event_scheduler.h"
Austin Schuhe1dafe42020-01-06 21:12:03 -080015#include "aos/events/simple_channel.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070016#include "aos/flatbuffer_merge.h"
17#include "aos/flatbuffers.h"
18#include "aos/ipc_lib/index.h"
19#include "glog/logging.h"
20
21namespace aos {
22
23// Class for simulated fetchers.
24class SimulatedChannel;
25
Austin Schuhac0771c2020-01-07 18:36:30 -080026class NodeEventLoopFactory;
27
28// There are 2 concepts needed to support multi-node simulations.
29// 1) The node. This is implemented with NodeEventLoopFactory.
30// 2) The "robot" which runs multiple nodes. This is implemented with
31// SimulatedEventLoopFactory.
32//
33// To make things easier, SimulatedEventLoopFactory takes an optional Node
34// argument if you want to make event loops without interacting with the
35// NodeEventLoopFactory object.
36//
37// The basic flow goes something like as follows:
38//
39// SimulatedEventLoopFactory factory(config);
40// const Node *pi1 = configuration::GetNode(factory.configuration(), "pi1");
41// std::unique_ptr<EventLoop> event_loop = factory.MakeEventLoop("ping", pi1);
42//
43// Or
44//
45// SimulatedEventLoopFactory factory(config);
46// const Node *pi1 = configuration::GetNode(factory.configuration(), "pi1");
47// NodeEventLoopFactory *pi1_factory = factory.GetNodeEventLoopFactory(pi1);
48// std::unique_ptr<EventLoop> event_loop = pi1_factory.MakeEventLoop("ping");
49//
50// The distributed_clock is used to be the base time. NodeEventLoopFactory has
51// all the information needed to adjust both the realtime and monotonic clocks
52// relative to the distributed_clock.
Alex Perrycb7da4b2019-08-28 19:35:56 -070053class SimulatedEventLoopFactory {
54 public:
55 // Constructs a SimulatedEventLoopFactory with the provided configuration.
56 // This configuration must remain in scope for the lifetime of the factory and
57 // all sub-objects.
58 SimulatedEventLoopFactory(const Configuration *configuration);
59 ~SimulatedEventLoopFactory();
60
Austin Schuhac0771c2020-01-07 18:36:30 -080061 // Creates an event loop. If running in a multi-node environment, node needs
62 // to point to the node to create this event loop on.
63 ::std::unique_ptr<EventLoop> MakeEventLoop(std::string_view name,
64 const Node *node = nullptr);
65
66 // Returns the NodeEventLoopFactory for the provided node. The returned
67 // NodeEventLoopFactory is owned by the SimulatedEventLoopFactory and has a
68 // lifetime identical to the factory.
69 NodeEventLoopFactory *GetNodeEventLoopFactory(const Node *node);
Alex Perrycb7da4b2019-08-28 19:35:56 -070070
71 // Starts executing the event loops unconditionally.
72 void Run();
73 // Executes the event loops for a duration.
Austin Schuhac0771c2020-01-07 18:36:30 -080074 void RunFor(distributed_clock::duration duration);
Alex Perrycb7da4b2019-08-28 19:35:56 -070075
76 // Stops executing all event loops. Meant to be called from within an event
77 // loop handler.
78 void Exit() { scheduler_.Exit(); }
79
Austin Schuhac0771c2020-01-07 18:36:30 -080080 const std::vector<const Node *> &nodes() const { return nodes_; }
81
82 // Sets the simulated send delay for all messages sent within a single node.
Austin Schuh7d87b672019-12-01 20:23:49 -080083 void set_send_delay(std::chrono::nanoseconds send_delay);
Austin Schuhac0771c2020-01-07 18:36:30 -080084 std::chrono::nanoseconds send_delay() const { return send_delay_; }
85
86 // Sets the simulated network delay for messages forwarded between nodes.
87 void set_network_delay(std::chrono::nanoseconds network_delay);
88 std::chrono::nanoseconds network_delay() const { return network_delay_; }
89
90 // Returns the clock used to synchronize the nodes.
91 distributed_clock::time_point distributed_now() const {
92 return scheduler_.distributed_now();
93 }
94
95 // Returns the configuration used for everything.
96 const Configuration *configuration() const { return configuration_; }
97
98 private:
99 const Configuration *const configuration_;
100 EventScheduler scheduler_;
101 // List of event loops to manage running and not running for.
102 // The function is a callback used to set and clear the running bool on each
103 // event loop.
104 std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
105 raw_event_loops_;
106
107 std::chrono::nanoseconds send_delay_ = std::chrono::microseconds(50);
108 std::chrono::nanoseconds network_delay_ = std::chrono::microseconds(100);
109
110 std::vector<std::unique_ptr<NodeEventLoopFactory>> node_factories_;
111
112 std::vector<const Node *> nodes_;
113};
114
115// This class holds all the state required to be a single node.
116class NodeEventLoopFactory {
117 public:
118 ::std::unique_ptr<EventLoop> MakeEventLoop(std::string_view name);
Austin Schuh7d87b672019-12-01 20:23:49 -0800119
Austin Schuh217a9782019-12-21 23:02:50 -0800120 // Returns the node that this factory is running as, or nullptr if this is a
121 // single node setup.
122 const Node *node() const { return node_; }
123
Austin Schuh92547522019-12-28 14:33:43 -0800124 // Sets realtime clock to realtime_now for a given monotonic clock.
125 void SetRealtimeOffset(monotonic_clock::time_point monotonic_now,
126 realtime_clock::time_point realtime_now) {
Austin Schuhac0771c2020-01-07 18:36:30 -0800127 realtime_offset_ =
128 realtime_now.time_since_epoch() - monotonic_now.time_since_epoch();
Austin Schuh92547522019-12-28 14:33:43 -0800129 }
130
Austin Schuhac0771c2020-01-07 18:36:30 -0800131 // Returns the current time on both clocks.
132 inline monotonic_clock::time_point monotonic_now() const;
133 inline realtime_clock::time_point realtime_now() const;
Austin Schuh39788ff2019-12-01 18:22:57 -0800134
Austin Schuhac0771c2020-01-07 18:36:30 -0800135 // Converts a time to the distributed clock for scheduling and cross-node time
136 // measurement.
137 inline distributed_clock::time_point ToDistributedClock(
138 monotonic_clock::time_point time) const;
139
140 private:
141 friend class SimulatedEventLoopFactory;
142 NodeEventLoopFactory(
143 EventScheduler *scheduler, SimulatedEventLoopFactory *factory,
144 const Node *node,
145 std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
146 *raw_event_loops);
147
148 EventScheduler *const scheduler_;
149 SimulatedEventLoopFactory *const factory_;
Austin Schuh7d87b672019-12-01 20:23:49 -0800150
Austin Schuh217a9782019-12-21 23:02:50 -0800151 const Node *const node_;
152
Austin Schuhac0771c2020-01-07 18:36:30 -0800153 std::vector<std::pair<EventLoop *, std::function<void(bool)>>>
154 *const raw_event_loops_;
155
156 std::chrono::nanoseconds monotonic_offset_ = std::chrono::seconds(0);
157 std::chrono::nanoseconds realtime_offset_ = std::chrono::seconds(0);
158
159 // Map from name, type to queue.
160 absl::btree_map<SimpleChannel, std::unique_ptr<SimulatedChannel>> channels_;
161
162 // pid so we get unique timing reports.
Austin Schuh39788ff2019-12-01 18:22:57 -0800163 pid_t tid_ = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700164};
165
Austin Schuhac0771c2020-01-07 18:36:30 -0800166inline monotonic_clock::time_point NodeEventLoopFactory::monotonic_now() const {
167 return monotonic_clock::time_point(
168 factory_->distributed_now().time_since_epoch() + monotonic_offset_);
169}
170
171inline realtime_clock::time_point NodeEventLoopFactory::realtime_now() const {
172 return realtime_clock::time_point(monotonic_now().time_since_epoch() +
173 realtime_offset_);
174}
175
176inline distributed_clock::time_point NodeEventLoopFactory::ToDistributedClock(
177 monotonic_clock::time_point time) const {
178 return distributed_clock::time_point(time.time_since_epoch() -
179 monotonic_offset_);
180}
181
Alex Perrycb7da4b2019-08-28 19:35:56 -0700182} // namespace aos
183
184#endif // AOS_EVENTS_SIMULATED_EVENT_LOOP_H_