xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/test_tools/simulator/simulator.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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