From 6ce033a863acf6627a3bbf7d3f453097a1eec9f6 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Wed, 22 Jan 2020 10:12:56 +0100 Subject: [PATCH] Moves ownership of time controller into NetworkEmulationManager. This makes it easier to maintain consistency between real time and simulated time modes. The RealTimeController is updated to use an explicit main thread, this ensures that pending destruction tasks are run as the network emulator goes out of scope. Bug: webrtc:11255 Change-Id: Ie73ab778c78a68d7c58c0f857f14a8d8ac027c67 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/166164 Commit-Queue: Sebastian Jansson Reviewed-by: Steve Anton Reviewed-by: Artem Titov Cr-Commit-Position: refs/heads/master@{#30342} --- api/BUILD.gn | 42 +++++++++---------- api/test/create_network_emulation_manager.cc | 5 ++- api/test/create_network_emulation_manager.h | 3 +- api/test/network_emulation_manager.h | 5 +++ api/test/time_controller.cc | 27 ++++++++++++ api/test/time_controller.h | 5 ++- rtc_base/thread.h | 15 +++++++ test/network/cross_traffic_unittest.cc | 10 ++--- test/network/feedback_generator.cc | 7 ++-- test/network/feedback_generator.h | 1 - test/network/network_emulation_manager.cc | 28 +++++++++---- test/network/network_emulation_manager.h | 11 ++--- test/network/network_emulation_pc_unittest.cc | 2 +- test/network/network_emulation_unittest.cc | 37 +++++++++------- test/peer_scenario/peer_scenario.cc | 42 +++++-------------- test/peer_scenario/peer_scenario.h | 11 +++-- test/peer_scenario/peer_scenario_client.cc | 7 ++-- test/peer_scenario/peer_scenario_client.h | 1 - test/scenario/scenario.cc | 32 ++++++-------- test/scenario/scenario.h | 1 - test/time_controller/real_time_controller.cc | 31 ++++++++++---- test/time_controller/real_time_controller.h | 3 +- test/time_controller/simulated_thread.h | 15 +------ 23 files changed, 185 insertions(+), 156 deletions(-) create mode 100644 api/test/time_controller.cc diff --git a/api/BUILD.gn b/api/BUILD.gn index a1969cab47..d95f749da9 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -538,6 +538,7 @@ rtc_source_set("network_emulation_manager_api") { ] deps = [ ":simulated_network_api", + ":time_controller", "../call:simulated_network", "../rtc_base", "test/network_emulation", @@ -547,6 +548,24 @@ rtc_source_set("network_emulation_manager_api") { ] } +rtc_source_set("time_controller") { + visibility = [ "*" ] + sources = [ + "test/time_controller.cc", + "test/time_controller.h", + ] + + deps = [ + "../modules/utility", + "../rtc_base", + "../rtc_base/synchronization:yield_policy", + "../system_wrappers", + "task_queue", + "units:time_delta", + "units:timestamp", + ] +} + rtc_source_set("fec_controller_api") { visibility = [ "*" ] sources = [ @@ -913,29 +932,6 @@ if (rtc_include_tests) { ] } - rtc_library("time_controller") { - visibility = [ "*" ] - testonly = true - sources = [ "test/time_controller.h" ] - - deps = [ - "../modules:module_api", - "../modules/utility:utility", - "../rtc_base", - "../rtc_base:rtc_base_tests_utils", - "../rtc_base:rtc_event", - "../rtc_base/synchronization:sequence_checker", - "../rtc_base/synchronization:yield_policy", - "../rtc_base/task_utils:to_queued_task", - "../system_wrappers", - "task_queue", - "task_queue:default_task_queue_factory", - "units:time_delta", - "units:timestamp", - "//third_party/abseil-cpp/absl/strings", - ] - } - rtc_library("create_time_controller") { visibility = [ "*" ] testonly = true diff --git a/api/test/create_network_emulation_manager.cc b/api/test/create_network_emulation_manager.cc index 72efec2ad2..089a2f8a86 100644 --- a/api/test/create_network_emulation_manager.cc +++ b/api/test/create_network_emulation_manager.cc @@ -17,8 +17,9 @@ namespace webrtc { -std::unique_ptr CreateNetworkEmulationManager() { - return std::make_unique(); +std::unique_ptr CreateNetworkEmulationManager( + TimeMode mode) { + return std::make_unique(mode); } } // namespace webrtc diff --git a/api/test/create_network_emulation_manager.h b/api/test/create_network_emulation_manager.h index 747da1cb54..c57c34874c 100644 --- a/api/test/create_network_emulation_manager.h +++ b/api/test/create_network_emulation_manager.h @@ -18,7 +18,8 @@ namespace webrtc { -std::unique_ptr CreateNetworkEmulationManager(); +std::unique_ptr CreateNetworkEmulationManager( + TimeMode mode = TimeMode::kRealTime); } // namespace webrtc diff --git a/api/test/network_emulation_manager.h b/api/test/network_emulation_manager.h index 4e5379f68b..a04767019b 100644 --- a/api/test/network_emulation_manager.h +++ b/api/test/network_emulation_manager.h @@ -16,6 +16,7 @@ #include "api/test/network_emulation/network_emulation_interfaces.h" #include "api/test/simulated_network.h" +#include "api/test/time_controller.h" #include "api/units/timestamp.h" #include "rtc_base/network.h" @@ -69,6 +70,8 @@ class EmulatedNetworkManagerInterface { std::function stats_callback) const = 0; }; +enum class TimeMode { kRealTime, kSimulated }; + // Provides an API for creating and configuring emulated network layer. // All objects returned by this API are owned by NetworkEmulationManager itself // and will be deleted when manager will be deleted. @@ -103,6 +106,8 @@ class NetworkEmulationManager { }; virtual ~NetworkEmulationManager() = default; + virtual TimeController* time_controller() = 0; + // Creates an emulated network node, which represents single network in // the emulated network layer. virtual EmulatedNetworkNode* CreateEmulatedNode( diff --git a/api/test/time_controller.cc b/api/test/time_controller.cc new file mode 100644 index 0000000000..26fe69cce1 --- /dev/null +++ b/api/test/time_controller.cc @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2020 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "api/test/time_controller.h" + +namespace webrtc { +bool TimeController::Wait(const std::function& done, + TimeDelta max_duration) { + // Step size is chosen to be short enough to not significantly affect latency + // in real time tests while being long enough to avoid adding too much load to + // the system. + const auto kStep = TimeDelta::ms(5); + for (auto elapsed = TimeDelta::Zero(); elapsed < max_duration; + elapsed += kStep) { + if (done()) + return true; + AdvanceTime(kStep); + } + return done(); +} +} // namespace webrtc diff --git a/api/test/time_controller.h b/api/test/time_controller.h index 6c47e91575..6d09481660 100644 --- a/api/test/time_controller.h +++ b/api/test/time_controller.h @@ -23,7 +23,6 @@ #include "system_wrappers/include/clock.h" namespace webrtc { - // Interface for controlling time progress. This allows us to execute test code // in either real time or simulated time by using different implementation of // this interface. @@ -51,6 +50,10 @@ class TimeController { // Allow task queues and process threads created by this instance to execute // for the given |duration|. virtual void AdvanceTime(TimeDelta duration) = 0; + + // Waits until done() == true, polling done() in small time intervals. + bool Wait(const std::function& done, + TimeDelta max_duration = TimeDelta::seconds(5)); }; // Interface for telling time, scheduling an event to fire at a particular time, diff --git a/rtc_base/thread.h b/rtc_base/thread.h index 77aff611f9..d08c3bd09c 100644 --- a/rtc_base/thread.h +++ b/rtc_base/thread.h @@ -425,6 +425,21 @@ class RTC_LOCKABLE RTC_EXPORT Thread : public webrtc::TaskQueueBase { #endif protected: + class CurrentThreadSetter : CurrentTaskQueueSetter { + public: + explicit CurrentThreadSetter(Thread* thread) + : CurrentTaskQueueSetter(thread), + manager_(rtc::ThreadManager::Instance()), + previous_(manager_->CurrentThread()) { + manager_->ChangeCurrentThreadForTest(thread); + } + ~CurrentThreadSetter() { manager_->ChangeCurrentThreadForTest(previous_); } + + private: + rtc::ThreadManager* const manager_; + rtc::Thread* const previous_; + }; + // DelayedMessage goes into a priority queue, sorted by trigger time. Messages // with the same trigger time are processed in num_ (FIFO) order. class DelayedMessage { diff --git a/test/network/cross_traffic_unittest.cc b/test/network/cross_traffic_unittest.cc index 52bbd48c1a..4bf19845c0 100644 --- a/test/network/cross_traffic_unittest.cc +++ b/test/network/cross_traffic_unittest.cc @@ -113,8 +113,7 @@ TEST(CrossTrafficTest, RandomWalkCrossTraffic) { } TEST(TcpMessageRouteTest, DeliveredOnLossyNetwork) { - GlobalSimulatedTimeController time(Timestamp::seconds(0)); - NetworkEmulationManagerImpl net(&time); + NetworkEmulationManagerImpl net(TimeMode::kSimulated); BuiltInNetworkBehaviorConfig send; // 800 kbps means that the 100 kB message would be delivered in ca 1 second // under ideal conditions and no overhead. @@ -134,17 +133,16 @@ TEST(TcpMessageRouteTest, DeliveredOnLossyNetwork) { constexpr size_t kMessageSize = 100000; tcp_route->SendMessage(kMessageSize, [&] { - RTC_LOG(LS_INFO) << "Received at " - << ToString(time.GetClock()->CurrentTime()); + RTC_LOG(LS_INFO) << "Received at " << ToString(net.Now()); deliver_count++; }); // If there was no loss, we would have delivered the message in ca 1 second, // with 50% it should take much longer. - time.AdvanceTime(TimeDelta::seconds(5)); + net.time_controller()->AdvanceTime(TimeDelta::seconds(5)); ASSERT_EQ(deliver_count, 0); // But given enough time the messsage will be delivered, but only once. - time.AdvanceTime(TimeDelta::seconds(60)); + net.time_controller()->AdvanceTime(TimeDelta::seconds(60)); EXPECT_EQ(deliver_count, 1); } diff --git a/test/network/feedback_generator.cc b/test/network/feedback_generator.cc index 3ae6fb2086..f2e345f6b2 100644 --- a/test/network/feedback_generator.cc +++ b/test/network/feedback_generator.cc @@ -17,8 +17,7 @@ namespace webrtc { FeedbackGeneratorImpl::FeedbackGeneratorImpl( FeedbackGeneratorImpl::Config config) : conf_(config), - time_controller_{Timestamp::seconds(100000)}, - net_{&time_controller_}, + net_(TimeMode::kSimulated), send_link_{new SimulatedNetwork(conf_.send_link)}, ret_link_{new SimulatedNetwork(conf_.return_link)}, route_(this, @@ -28,11 +27,11 @@ FeedbackGeneratorImpl::FeedbackGeneratorImpl( {net_.CreateEmulatedNode(absl::WrapUnique(ret_link_))})) {} Timestamp FeedbackGeneratorImpl::Now() { - return time_controller_.GetClock()->CurrentTime(); + return net_.Now(); } void FeedbackGeneratorImpl::Sleep(TimeDelta duration) { - time_controller_.AdvanceTime(duration); + net_.time_controller()->AdvanceTime(duration); } void FeedbackGeneratorImpl::SendPacket(size_t size) { diff --git a/test/network/feedback_generator.h b/test/network/feedback_generator.h index afc306892a..98ac01c7a6 100644 --- a/test/network/feedback_generator.h +++ b/test/network/feedback_generator.h @@ -44,7 +44,6 @@ class FeedbackGeneratorImpl private: Config conf_; - GlobalSimulatedTimeController time_controller_; ::webrtc::test::NetworkEmulationManagerImpl net_; SimulatedNetwork* const send_link_; SimulatedNetwork* const ret_link_; diff --git a/test/network/network_emulation_manager.cc b/test/network/network_emulation_manager.cc index 494e885fc2..caa950e0bd 100644 --- a/test/network/network_emulation_manager.cc +++ b/test/network/network_emulation_manager.cc @@ -18,6 +18,7 @@ #include "call/simulated_network.h" #include "rtc_base/fake_network.h" #include "test/time_controller/real_time_controller.h" +#include "test/time_controller/simulated_time_controller.h" namespace webrtc { namespace test { @@ -27,18 +28,27 @@ namespace { constexpr uint32_t kMinIPv4Address = 0xC0A80000; // uint32_t representation of 192.168.255.255 address constexpr uint32_t kMaxIPv4Address = 0xC0A8FFFF; + +std::unique_ptr CreateTimeController(TimeMode mode) { + switch (mode) { + case TimeMode::kRealTime: + return std::make_unique(); + case TimeMode::kSimulated: + // Using an offset of 100000 to get nice fixed width and readable + // timestamps in typical test scenarios. + const Timestamp kSimulatedStartTime = Timestamp::seconds(100000); + return std::make_unique( + kSimulatedStartTime); + } +} } // namespace -NetworkEmulationManagerImpl::NetworkEmulationManagerImpl() - : NetworkEmulationManagerImpl(GlobalRealTimeController()) {} - -NetworkEmulationManagerImpl::NetworkEmulationManagerImpl( - TimeController* time_controller) - : time_controller_(time_controller), - clock_(time_controller->GetClock()), +NetworkEmulationManagerImpl::NetworkEmulationManagerImpl(TimeMode mode) + : time_controller_(CreateTimeController(mode)), + clock_(time_controller_->GetClock()), next_node_id_(1), next_ip4_address_(kMinIPv4Address), - task_queue_(time_controller->GetTaskQueueFactory()->CreateTaskQueue( + task_queue_(time_controller_->GetTaskQueueFactory()->CreateTaskQueue( "NetworkEmulation", TaskQueueFactory::Priority::NORMAL)) {} @@ -266,7 +276,7 @@ NetworkEmulationManagerImpl::CreateEmulatedNetworkManagerInterface( auto endpoints_container = std::make_unique(endpoint_impls); auto network_manager = std::make_unique( - time_controller_, &task_queue_, endpoints_container.get()); + time_controller_.get(), &task_queue_, endpoints_container.get()); for (auto* endpoint : endpoints) { // Associate endpoint with network manager. bool insertion_result = diff --git a/test/network/network_emulation_manager.h b/test/network/network_emulation_manager.h index 25c8050aab..2b33fa1575 100644 --- a/test/network/network_emulation_manager.h +++ b/test/network/network_emulation_manager.h @@ -39,8 +39,7 @@ namespace test { class NetworkEmulationManagerImpl : public NetworkEmulationManager { public: - NetworkEmulationManagerImpl(); - explicit NetworkEmulationManagerImpl(TimeController* time_controller); + explicit NetworkEmulationManagerImpl(TimeMode mode); ~NetworkEmulationManagerImpl(); EmulatedNetworkNode* CreateEmulatedNode( @@ -84,11 +83,13 @@ class NetworkEmulationManagerImpl : public NetworkEmulationManager { EmulatedNetworkManagerInterface* CreateEmulatedNetworkManagerInterface( const std::vector& endpoints) override; - private: - absl::optional GetNextIPv4Address(); + TimeController* time_controller() override { return time_controller_.get(); } + Timestamp Now() const; - TimeController* const time_controller_; + private: + absl::optional GetNextIPv4Address(); + const std::unique_ptr time_controller_; Clock* const clock_; int next_node_id_; diff --git a/test/network/network_emulation_pc_unittest.cc b/test/network/network_emulation_pc_unittest.cc index c1582263d8..e04da34076 100644 --- a/test/network/network_emulation_pc_unittest.cc +++ b/test/network/network_emulation_pc_unittest.cc @@ -99,7 +99,7 @@ TEST(NetworkEmulationManagerPCTest, Run) { signaling_thread->Start(); // Setup emulated network - NetworkEmulationManagerImpl emulation; + NetworkEmulationManagerImpl emulation(TimeMode::kRealTime); EmulatedNetworkNode* alice_node = emulation.CreateEmulatedNode( std::make_unique(BuiltInNetworkBehaviorConfig())); diff --git a/test/network/network_emulation_unittest.cc b/test/network/network_emulation_unittest.cc index 9a8a9823e2..70dfa77930 100644 --- a/test/network/network_emulation_unittest.cc +++ b/test/network/network_emulation_unittest.cc @@ -28,8 +28,8 @@ namespace webrtc { namespace test { namespace { -constexpr int kNetworkPacketWaitTimeoutMs = 100; -constexpr int kStatsWaitTimeoutMs = 1000; +constexpr TimeDelta kNetworkPacketWaitTimeout = TimeDelta::Millis<100>(); +constexpr TimeDelta kStatsWaitTimeout = TimeDelta::Seconds<1>(); constexpr int kOverheadIpv4Udp = 20 + 8; class SocketReader : public sigslot::has_slots<> { @@ -128,7 +128,7 @@ class NetworkEmulationManagerThreeNodesRoutingTest : public ::testing::Test { rtc::CopyOnWriteBuffer(10)); // Sleep at the end to wait for async packets delivery. - SleepMs(kNetworkPacketWaitTimeoutMs); + emulation_.time_controller()->AdvanceTime(kNetworkPacketWaitTimeout); } private: @@ -139,7 +139,7 @@ class NetworkEmulationManagerThreeNodesRoutingTest : public ::testing::Test { MockReceiver r_e1_e3_; MockReceiver r_e3_e1_; - NetworkEmulationManagerImpl emulation_; + NetworkEmulationManagerImpl emulation_{TimeMode::kRealTime}; EmulatedEndpoint* e1_; EmulatedEndpoint* e2_; EmulatedEndpoint* e3_; @@ -156,7 +156,7 @@ EmulatedNetworkNode* CreateEmulatedNodeWithDefaultBuiltInConfig( using ::testing::_; TEST(NetworkEmulationManagerTest, GeneratedIpv4AddressDoesNotCollide) { - NetworkEmulationManagerImpl network_manager; + NetworkEmulationManagerImpl network_manager(TimeMode::kRealTime); std::set ips; EmulatedEndpointConfig config; config.generated_ip_family = EmulatedEndpointConfig::IpAddressFamily::kIpv4; @@ -169,7 +169,7 @@ TEST(NetworkEmulationManagerTest, GeneratedIpv4AddressDoesNotCollide) { } TEST(NetworkEmulationManagerTest, GeneratedIpv6AddressDoesNotCollide) { - NetworkEmulationManagerImpl network_manager; + NetworkEmulationManagerImpl network_manager(TimeMode::kRealTime); std::set ips; EmulatedEndpointConfig config; config.generated_ip_family = EmulatedEndpointConfig::IpAddressFamily::kIpv6; @@ -182,7 +182,7 @@ TEST(NetworkEmulationManagerTest, GeneratedIpv6AddressDoesNotCollide) { } TEST(NetworkEmulationManagerTest, Run) { - NetworkEmulationManagerImpl network_manager; + NetworkEmulationManagerImpl network_manager(TimeMode::kRealTime); EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode( std::make_unique(BuiltInNetworkBehaviorConfig())); @@ -233,8 +233,8 @@ TEST(NetworkEmulationManagerTest, Run) { [&]() { s2->Send(data.data(), data.size()); }); } - rtc::Event wait; - wait.Wait(1000); + network_manager.time_controller()->AdvanceTime(TimeDelta::seconds(1)); + EXPECT_EQ(r1.ReceivedCount(), 1000); EXPECT_EQ(r2.ReceivedCount(), 1000); @@ -262,11 +262,13 @@ TEST(NetworkEmulationManagerTest, Run) { EXPECT_EQ(st.bytes_dropped.bytes(), 0l); received_stats_count++; }); - ASSERT_EQ_WAIT(received_stats_count.load(), 2, kStatsWaitTimeoutMs); + ASSERT_EQ_SIMULATED_WAIT(received_stats_count.load(), 2, + kStatsWaitTimeout.ms(), + *network_manager.time_controller()); } TEST(NetworkEmulationManagerTest, ThroughputStats) { - NetworkEmulationManagerImpl network_manager; + NetworkEmulationManagerImpl network_manager(TimeMode::kRealTime); EmulatedNetworkNode* alice_node = network_manager.CreateEmulatedNode( std::make_unique(BuiltInNetworkBehaviorConfig())); @@ -313,12 +315,11 @@ TEST(NetworkEmulationManagerTest, ThroughputStats) { // Send 11 packets, totalizing 1 second between the first and the last. const int kNumPacketsSent = 11; - const int kDelayMs = 100; - rtc::Event wait; + const TimeDelta kDelay = TimeDelta::ms(100); for (int i = 0; i < kNumPacketsSent; i++) { t1->PostTask(RTC_FROM_HERE, [&]() { s1->Send(data.data(), data.size()); }); t2->PostTask(RTC_FROM_HERE, [&]() { s2->Send(data.data(), data.size()); }); - wait.Wait(kDelayMs); + network_manager.time_controller()->AdvanceTime(kDelay); } std::atomic received_stats_count{0}; @@ -328,11 +329,15 @@ TEST(NetworkEmulationManagerTest, ThroughputStats) { const double tolerance = 0.95; // Accept 5% tolerance for timing. EXPECT_GE(st.last_packet_sent_time - st.first_packet_sent_time, - TimeDelta::ms((kNumPacketsSent - 1) * kDelayMs * tolerance)); + (kNumPacketsSent - 1) * kDelay * tolerance); EXPECT_GT(st.AverageSendRate().bps(), 0); received_stats_count++; }); - ASSERT_EQ_WAIT(received_stats_count.load(), 1, kStatsWaitTimeoutMs); + + ASSERT_EQ_SIMULATED_WAIT(received_stats_count.load(), 1, + kStatsWaitTimeout.ms(), + *network_manager.time_controller()); + EXPECT_EQ(r1.ReceivedCount(), 11); EXPECT_EQ(r2.ReceivedCount(), 11); diff --git a/test/peer_scenario/peer_scenario.cc b/test/peer_scenario/peer_scenario.cc index 99d97c7190..c3443aa185 100644 --- a/test/peer_scenario/peer_scenario.cc +++ b/test/peer_scenario/peer_scenario.cc @@ -41,34 +41,22 @@ std::unique_ptr GetPeerScenarioLogManager( } return nullptr; } - -std::unique_ptr CreateTimeController(bool real_time) { - if (real_time) { - return std::make_unique(); - } else { - // Using an offset of 100000 to get nice fixed width and readable timestamps - // in typical test scenarios. - const Timestamp kSimulatedStartTime = Timestamp::seconds(100000); - return std::make_unique(kSimulatedStartTime); - } -} } // namespace -PeerScenario::PeerScenario(const testing::TestInfo& test_info, bool real_time) +PeerScenario::PeerScenario(const testing::TestInfo& test_info, TimeMode mode) : PeerScenario( std::string(test_info.test_suite_name()) + "/" + test_info.name(), - real_time) {} + mode) {} -PeerScenario::PeerScenario(std::string file_name, bool real_time) - : PeerScenario(GetPeerScenarioLogManager(file_name), real_time) {} +PeerScenario::PeerScenario(std::string file_name, TimeMode mode) + : PeerScenario(GetPeerScenarioLogManager(file_name), mode) {} PeerScenario::PeerScenario( std::unique_ptr log_writer_manager, - bool real_time) + TimeMode mode) : log_writer_manager_(std::move(log_writer_manager)), - time_controller_(CreateTimeController(real_time)), - signaling_thread_(time_controller_->GetMainThread()), - net_(time_controller_.get()) {} + net_(mode), + signaling_thread_(net_.time_controller()->GetMainThread()) {} PeerScenarioClient* PeerScenario::CreateClient( PeerScenarioClient::Config config) { @@ -79,7 +67,7 @@ PeerScenarioClient* PeerScenario::CreateClient( PeerScenarioClient* PeerScenario::CreateClient( std::string name, PeerScenarioClient::Config config) { - peer_clients_.emplace_back(net(), time_controller_.get(), thread(), + peer_clients_.emplace_back(net(), signaling_thread_, GetLogWriterFactory(name), config); return &peer_clients_.back(); } @@ -119,20 +107,12 @@ void PeerScenario::AttachVideoQualityAnalyzer(VideoQualityAnalyzer* analyzer, bool PeerScenario::WaitAndProcess(std::atomic* event, TimeDelta max_duration) { - const auto kStep = TimeDelta::ms(5); - if (*event) - return true; - for (auto elapsed = TimeDelta::Zero(); elapsed < max_duration; - elapsed += kStep) { - time_controller_->AdvanceTime(kStep); - if (*event) - return true; - } - return false; + return net_.time_controller()->Wait([event] { return event->load(); }, + max_duration); } void PeerScenario::ProcessMessages(TimeDelta duration) { - time_controller_->AdvanceTime(duration); + net_.time_controller()->AdvanceTime(duration); } std::unique_ptr PeerScenario::GetLogWriterFactory( diff --git a/test/peer_scenario/peer_scenario.h b/test/peer_scenario/peer_scenario.h index 94dd4425b9..8d6ad1b00c 100644 --- a/test/peer_scenario/peer_scenario.h +++ b/test/peer_scenario/peer_scenario.h @@ -47,14 +47,14 @@ class PeerScenario { // command line flag. Optionally, the TestInfo struct available in gtest can // be used to automatically generate a path based on the test name. explicit PeerScenario(const testing::TestInfo& test_info, - bool real_time = false); - explicit PeerScenario(std::string file_name, bool real_time = false); + TimeMode mode = TimeMode::kSimulated); + explicit PeerScenario(std::string file_name, + TimeMode mode = TimeMode::kSimulated); explicit PeerScenario( std::unique_ptr log_writer_manager, - bool real_time = false); + TimeMode mode = TimeMode::kSimulated); NetworkEmulationManagerImpl* net() { return &net_; } - rtc::Thread* thread() { return signaling_thread_; } // Creates a client wrapping a peer connection conforming to the given config. // The client will share the signaling thread with the scenario. To maintain @@ -111,10 +111,9 @@ class PeerScenario { std::string name); const std::unique_ptr log_writer_manager_; - const std::unique_ptr time_controller_; + NetworkEmulationManagerImpl net_; rtc::Thread* const signaling_thread_; std::list video_quality_pairs_; - NetworkEmulationManagerImpl net_; std::list peer_clients_; }; diff --git a/test/peer_scenario/peer_scenario_client.cc b/test/peer_scenario/peer_scenario_client.cc index 0ee709e60e..4614942f78 100644 --- a/test/peer_scenario/peer_scenario_client.cc +++ b/test/peer_scenario/peer_scenario_client.cc @@ -147,15 +147,14 @@ class TimeControllerBasedCallFactory : public CallFactoryInterface { PeerScenarioClient::PeerScenarioClient( NetworkEmulationManager* net, - TimeController* time_controller, rtc::Thread* signaling_thread, std::unique_ptr log_writer_factory, PeerScenarioClient::Config config) : endpoints_(CreateEndpoints(net, config.endpoints)), - task_queue_factory_(time_controller->GetTaskQueueFactory()), + task_queue_factory_(net->time_controller()->GetTaskQueueFactory()), signaling_thread_(signaling_thread), log_writer_factory_(std::move(log_writer_factory)), - worker_thread_(time_controller->CreateThread("worker")), + worker_thread_(net->time_controller()->CreateThread("worker")), handlers_(config.handlers), observer_(new LambdaPeerConnectionObserver(&handlers_)) { handlers_.on_track.push_back( @@ -191,7 +190,7 @@ PeerScenarioClient::PeerScenarioClient( pcf_deps.signaling_thread = signaling_thread_; pcf_deps.worker_thread = worker_thread_.get(); pcf_deps.call_factory = - std::make_unique(time_controller); + std::make_unique(net->time_controller()); pcf_deps.task_queue_factory = std::make_unique(task_queue_factory_); pcf_deps.event_log_factory = diff --git a/test/peer_scenario/peer_scenario_client.h b/test/peer_scenario/peer_scenario_client.h index e9b86e2bf3..b832f903e6 100644 --- a/test/peer_scenario/peer_scenario_client.h +++ b/test/peer_scenario/peer_scenario_client.h @@ -108,7 +108,6 @@ class PeerScenarioClient { PeerScenarioClient( NetworkEmulationManager* net, - TimeController* time_controller, rtc::Thread* signaling_thread, std::unique_ptr log_writer_factory, Config config); diff --git a/test/scenario/scenario.cc b/test/scenario/scenario.cc index 0c5e3814fd..e4e4f8d2d0 100644 --- a/test/scenario/scenario.cc +++ b/test/scenario/scenario.cc @@ -20,8 +20,6 @@ #include "test/logging/file_log_writer.h" #include "test/network/network_emulation.h" #include "test/testsupport/file_utils.h" -#include "test/time_controller/real_time_controller.h" -#include "test/time_controller/simulated_time_controller.h" ABSL_FLAG(bool, scenario_logs, false, "Save logs from scenario framework."); ABSL_FLAG(std::string, @@ -47,13 +45,6 @@ std::unique_ptr GetScenarioLogManager( } return nullptr; } -std::unique_ptr CreateTimeController(bool real_time) { - if (real_time) { - return std::make_unique(); - } else { - return std::make_unique(kSimulatedStartTime); - } -} } // namespace Scenario::Scenario() @@ -74,14 +65,14 @@ Scenario::Scenario( std::unique_ptr log_writer_factory, bool real_time) : log_writer_factory_(std::move(log_writer_factory)), - time_controller_(CreateTimeController(real_time)), - network_manager_(time_controller_.get()), - clock_(time_controller_->GetClock()), + network_manager_(real_time ? TimeMode::kRealTime : TimeMode::kSimulated), + clock_(network_manager_.time_controller()->GetClock()), audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()), audio_encoder_factory_(CreateBuiltinAudioEncoderFactory()), - task_queue_(time_controller_->GetTaskQueueFactory()->CreateTaskQueue( - "Scenario", - TaskQueueFactory::Priority::NORMAL)) {} + task_queue_(network_manager_.time_controller() + ->GetTaskQueueFactory() + ->CreateTaskQueue("Scenario", + TaskQueueFactory::Priority::NORMAL)) {} Scenario::~Scenario() { if (start_time_.IsFinite()) @@ -116,8 +107,8 @@ StatesPrinter* Scenario::CreatePrinter(std::string name, } CallClient* Scenario::CreateClient(std::string name, CallClientConfig config) { - CallClient* client = - new CallClient(time_controller_.get(), GetLogWriterFactory(name), config); + CallClient* client = new CallClient(network_manager_.time_controller(), + GetLogWriterFactory(name), config); if (config.transport.state_log_interval.IsFinite()) { Every(config.transport.state_log_interval, [this, client]() { client->network_controller_factory_.LogCongestionControllerStats(Now()); @@ -282,7 +273,7 @@ void Scenario::At(TimeDelta offset, std::function function) { void Scenario::RunFor(TimeDelta duration) { if (start_time_.IsInfinite()) Start(); - time_controller_->AdvanceTime(duration); + network_manager_.time_controller()->AdvanceTime(duration); } void Scenario::RunUntil(TimeDelta target_time_since_start) { @@ -295,11 +286,12 @@ void Scenario::RunUntil(TimeDelta target_time_since_start, if (start_time_.IsInfinite()) Start(); while (check_interval >= TimeUntilTarget(target_time_since_start)) { - time_controller_->AdvanceTime(check_interval); + network_manager_.time_controller()->AdvanceTime(check_interval); if (exit_function()) return; } - time_controller_->AdvanceTime(TimeUntilTarget(target_time_since_start)); + network_manager_.time_controller()->AdvanceTime( + TimeUntilTarget(target_time_since_start)); } void Scenario::Start() { diff --git a/test/scenario/scenario.h b/test/scenario/scenario.h index a5803bf60d..1aad5b9cd1 100644 --- a/test/scenario/scenario.h +++ b/test/scenario/scenario.h @@ -161,7 +161,6 @@ class Scenario { TimeDelta TimeUntilTarget(TimeDelta target_time_offset); const std::unique_ptr log_writer_factory_; - std::unique_ptr time_controller_; NetworkEmulationManagerImpl network_manager_; Clock* clock_; diff --git a/test/time_controller/real_time_controller.cc b/test/time_controller/real_time_controller.cc index d9fd9dcb51..73772b968f 100644 --- a/test/time_controller/real_time_controller.cc +++ b/test/time_controller/real_time_controller.cc @@ -14,8 +14,28 @@ #include "system_wrappers/include/sleep.h" namespace webrtc { +namespace { +class MainThread : public rtc::Thread { + public: + MainThread() + : Thread(std::make_unique(), false), + current_setter_(this) { + DoInit(); + } + ~MainThread() { + Stop(); + DoDestroy(); + } + + private: + CurrentThreadSetter current_setter_; +}; +} // namespace RealTimeController::RealTimeController() - : task_queue_factory_(CreateDefaultTaskQueueFactory()) {} + : task_queue_factory_(CreateDefaultTaskQueueFactory()), + main_thread_(std::make_unique()) { + main_thread_->SetName("Main", this); +} Clock* RealTimeController::GetClock() { return Clock::GetRealTimeClock(); @@ -42,16 +62,11 @@ std::unique_ptr RealTimeController::CreateThread( } rtc::Thread* RealTimeController::GetMainThread() { - return rtc::Thread::Current(); + return main_thread_.get(); } void RealTimeController::AdvanceTime(TimeDelta duration) { - GetMainThread()->ProcessMessages(duration.ms()); -} - -RealTimeController* GlobalRealTimeController() { - static RealTimeController* time_controller = new RealTimeController(); - return time_controller; + main_thread_->ProcessMessages(duration.ms()); } } // namespace webrtc diff --git a/test/time_controller/real_time_controller.h b/test/time_controller/real_time_controller.h index f68fe441d5..bbee6ef967 100644 --- a/test/time_controller/real_time_controller.h +++ b/test/time_controller/real_time_controller.h @@ -36,10 +36,9 @@ class RealTimeController : public TimeController { private: const std::unique_ptr task_queue_factory_; + const std::unique_ptr main_thread_; }; -RealTimeController* GlobalRealTimeController(); - } // namespace webrtc #endif // TEST_TIME_CONTROLLER_REAL_TIME_CONTROLLER_H_ diff --git a/test/time_controller/simulated_thread.h b/test/time_controller/simulated_thread.h index bbaafd75bd..fd3969670a 100644 --- a/test/time_controller/simulated_thread.h +++ b/test/time_controller/simulated_thread.h @@ -19,20 +19,7 @@ namespace webrtc { class SimulatedThread : public rtc::Thread, public sim_time_impl::SimulatedSequenceRunner { public: - class CurrentThreadSetter : CurrentTaskQueueSetter { - public: - explicit CurrentThreadSetter(Thread* thread) - : CurrentTaskQueueSetter(thread), - manager_(rtc::ThreadManager::Instance()), - previous_(manager_->CurrentThread()) { - manager_->ChangeCurrentThreadForTest(thread); - } - ~CurrentThreadSetter() { manager_->ChangeCurrentThreadForTest(previous_); } - - private: - rtc::ThreadManager* const manager_; - rtc::Thread* const previous_; - }; + using CurrentThreadSetter = CurrentThreadSetter; SimulatedThread(sim_time_impl::SimulatedTimeControllerImpl* handler, absl::string_view name, std::unique_ptr socket_server);