1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
6 #define QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
7
8 #include <map>
9
10 #include "absl/container/flat_hash_map.h"
11 #include "absl/container/flat_hash_set.h"
12 #include "quiche/quic/core/quic_connection.h"
13 #include "quiche/quic/platform/api/quic_bug_tracker.h"
14 #include "quiche/quic/test_tools/simulator/actor.h"
15 #include "quiche/quic/test_tools/simulator/alarm_factory.h"
16 #include "quiche/common/simple_buffer_allocator.h"
17
18 namespace quic {
19 namespace simulator {
20
21 // Simulator is responsible for scheduling actors in the simulation and
22 // providing basic utility interfaces (clock, alarms, RNG and others).
23 class Simulator : public QuicConnectionHelperInterface {
24 public:
25 Simulator();
26 explicit Simulator(QuicRandom* random_generator);
27 Simulator(const Simulator&) = delete;
28 Simulator& operator=(const Simulator&) = delete;
29 ~Simulator() override;
30
31 // Schedule the specified actor. This method will ensure that |actor| is
32 // called at |new_time| at latest. If Schedule() is called multiple times
33 // before the Actor is called, Act() is called exactly once, at the earliest
34 // time requested, and the Actor has to reschedule itself manually for the
35 // subsequent times if they are still necessary.
36 void Schedule(Actor* actor, QuicTime new_time);
37
38 // Remove the specified actor from the schedule.
39 void Unschedule(Actor* actor);
40
41 // Begin QuicConnectionHelperInterface implementation.
42 const QuicClock* GetClock() const override;
43 QuicRandom* GetRandomGenerator() override;
44 quiche::QuicheBufferAllocator* GetStreamSendBufferAllocator() override;
45 // End QuicConnectionHelperInterface implementation.
46
47 QuicAlarmFactory* GetAlarmFactory();
48
set_random_generator(QuicRandom * random)49 void set_random_generator(QuicRandom* random) { random_generator_ = random; }
50
enable_random_delays()51 bool enable_random_delays() const { return enable_random_delays_; }
52
53 // Run the simulation until either no actors are scheduled or
54 // |termination_predicate| returns true. Returns true if terminated due to
55 // predicate, and false otherwise.
56 template <class TerminationPredicate>
57 bool RunUntil(TerminationPredicate termination_predicate);
58
59 // Same as RunUntil, except this function also accepts a |deadline|, and will
60 // return false if the deadline is exceeded.
61 template <class TerminationPredicate>
62 bool RunUntilOrTimeout(TerminationPredicate termination_predicate,
63 QuicTime::Delta deadline);
64
65 // Runs the simulation for exactly the specified |time_span|.
66 void RunFor(QuicTime::Delta time_span);
67
68 private:
69 friend class Actor;
70
71 class Clock : public QuicClock {
72 public:
73 // Do not start at zero as certain code can treat zero as an invalid
74 // timestamp.
75 const QuicTime kStartTime =
76 QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(1);
77
78 Clock();
79
80 QuicTime ApproximateNow() const override;
81 QuicTime Now() const override;
82 QuicWallTime WallNow() const override;
83
84 QuicTime now_;
85 };
86
87 // The delegate used for RunFor().
88 class RunForDelegate : public QuicAlarm::DelegateWithoutContext {
89 public:
90 explicit RunForDelegate(bool* run_for_should_stop);
91 void OnAlarm() override;
92
93 private:
94 // Pointer to |run_for_should_stop_| in the parent simulator.
95 bool* run_for_should_stop_;
96 };
97
98 // Register an actor with the simulator. Invoked by Actor constructor.
99 void AddActor(Actor* actor);
100
101 // Unregister an actor with the simulator. Invoked by Actor destructor.
102 void RemoveActor(Actor* actor);
103
104 // Finds the next scheduled actor, advances time to the schedule time and
105 // notifies the actor.
106 void HandleNextScheduledActor();
107
108 Clock clock_;
109 QuicRandom* random_generator_;
110 quiche::SimpleBufferAllocator buffer_allocator_;
111 AlarmFactory alarm_factory_;
112
113 // Alarm for RunFor() method.
114 std::unique_ptr<QuicAlarm> run_for_alarm_;
115 // Flag used to stop simulations ran via RunFor().
116 bool run_for_should_stop_;
117
118 // Indicates whether the simulator should add random delays on the links in
119 // order to avoid synchronization issues.
120 bool enable_random_delays_;
121
122 // Schedule of when the actors will be executed via an Act() call. The
123 // schedule is subject to the following invariants:
124 // - An actor cannot be scheduled for a later time than it's currently in the
125 // schedule.
126 // - An actor is removed from schedule either immediately before Act() is
127 // called or by explicitly calling Unschedule().
128 // - Each Actor appears in the map at most once.
129 std::multimap<QuicTime, Actor*> schedule_;
130 // For each actor, maintain the time it is scheduled at. The value for
131 // unscheduled actors is QuicTime::Infinite().
132 absl::flat_hash_map<Actor*, QuicTime> scheduled_times_;
133 absl::flat_hash_set<std::string> actor_names_;
134 };
135
136 template <class TerminationPredicate>
RunUntil(TerminationPredicate termination_predicate)137 bool Simulator::RunUntil(TerminationPredicate termination_predicate) {
138 bool predicate_value = false;
139 while (true) {
140 predicate_value = termination_predicate();
141 if (predicate_value || schedule_.empty()) {
142 break;
143 }
144 HandleNextScheduledActor();
145 }
146 return predicate_value;
147 }
148
149 template <class TerminationPredicate>
RunUntilOrTimeout(TerminationPredicate termination_predicate,QuicTime::Delta timeout)150 bool Simulator::RunUntilOrTimeout(TerminationPredicate termination_predicate,
151 QuicTime::Delta timeout) {
152 QuicTime end_time = clock_.Now() + timeout;
153 bool return_value = RunUntil([end_time, &termination_predicate, this]() {
154 return termination_predicate() || clock_.Now() >= end_time;
155 });
156
157 if (clock_.Now() >= end_time) {
158 return false;
159 }
160 return return_value;
161 }
162
163 } // namespace simulator
164 } // namespace quic
165
166 #endif // QUICHE_QUIC_TEST_TOOLS_SIMULATOR_SIMULATOR_H_
167