diff --git a/api/test/network_emulation/BUILD.gn b/api/test/network_emulation/BUILD.gn index a3dd961c81..4780da2451 100644 --- a/api/test/network_emulation/BUILD.gn +++ b/api/test/network_emulation/BUILD.gn @@ -17,6 +17,7 @@ rtc_library("network_emulation") { ] deps = [ + "../..:array_view", "../../../rtc_base", "../../../rtc_base:checks", "../../../rtc_base:rtc_base_approved", diff --git a/api/test/network_emulation/network_emulation_interfaces.h b/api/test/network_emulation/network_emulation_interfaces.h index 260ab0e292..b1aa0d2809 100644 --- a/api/test/network_emulation/network_emulation_interfaces.h +++ b/api/test/network_emulation/network_emulation_interfaces.h @@ -11,9 +11,11 @@ #define API_TEST_NETWORK_EMULATION_NETWORK_EMULATION_INTERFACES_H_ #include +#include #include #include "absl/types/optional.h" +#include "api/array_view.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" #include "api/units/timestamp.h" @@ -86,107 +88,48 @@ struct EmulatedNetworkIncomingStats { } }; -struct EmulatedNetworkStats { - int64_t packets_sent = 0; - DataSize bytes_sent = DataSize::Zero(); +class EmulatedNetworkStats { + public: + virtual ~EmulatedNetworkStats() = default; - DataSize first_sent_packet_size = DataSize::Zero(); - Timestamp first_packet_sent_time = Timestamp::PlusInfinity(); - Timestamp last_packet_sent_time = Timestamp::MinusInfinity(); + virtual int64_t PacketsSent() const = 0; + + virtual DataSize BytesSent() const = 0; // List of IP addresses that were used to send data considered in this stats // object. - std::vector local_addresses; + virtual std::vector LocalAddresses() const = 0; - std::map - incoming_stats_per_source; - - DataRate AverageSendRate() const { - RTC_DCHECK_GE(packets_sent, 2); - return (bytes_sent - first_sent_packet_size) / - (last_packet_sent_time - first_packet_sent_time); - } + virtual DataSize FirstSentPacketSize() const = 0; + // Returns time of the first packet sent or infinite value if no packets were + // sent. + virtual Timestamp FirstPacketSentTime() const = 0; + // Returns time of the last packet sent or infinite value if no packets were + // sent. + virtual Timestamp LastPacketSentTime() const = 0; + virtual DataRate AverageSendRate() const = 0; // Total amount of packets received regardless of the destination address. - int64_t PacketsReceived() const { - int64_t packets_received = 0; - for (const auto& incoming_stats : incoming_stats_per_source) { - packets_received += incoming_stats.second.packets_received; - } - return packets_received; - } - + virtual int64_t PacketsReceived() const = 0; // Total amount of bytes in received packets. - DataSize BytesReceived() const { - DataSize bytes_received = DataSize::Zero(); - for (const auto& incoming_stats : incoming_stats_per_source) { - bytes_received += incoming_stats.second.bytes_received; - } - return bytes_received; - } - + virtual DataSize BytesReceived() const = 0; // Total amount of packets that were received, but no destination was found. - int64_t PacketsDropped() const { - int64_t packets_dropped = 0; - for (const auto& incoming_stats : incoming_stats_per_source) { - packets_dropped += incoming_stats.second.packets_dropped; - } - return packets_dropped; - } - + virtual int64_t PacketsDropped() const = 0; // Total amount of bytes in dropped packets. - DataSize BytesDropped() const { - DataSize bytes_dropped = DataSize::Zero(); - for (const auto& incoming_stats : incoming_stats_per_source) { - bytes_dropped += incoming_stats.second.bytes_dropped; - } - return bytes_dropped; - } + virtual DataSize BytesDropped() const = 0; - DataSize FirstReceivedPacketSize() const { - Timestamp first_packet_received_time = Timestamp::PlusInfinity(); - DataSize first_received_packet_size = DataSize::Zero(); - for (const auto& incoming_stats : incoming_stats_per_source) { - if (first_packet_received_time > - incoming_stats.second.first_packet_received_time) { - first_packet_received_time = - incoming_stats.second.first_packet_received_time; - first_received_packet_size = - incoming_stats.second.first_received_packet_size; - } - } - return first_received_packet_size; - } + virtual DataSize FirstReceivedPacketSize() const = 0; + // Returns time of the first packet received or infinite value if no packets + // were received. + virtual Timestamp FirstPacketReceivedTime() const = 0; + // Returns time of the last packet received or infinite value if no packets + // were received. + virtual Timestamp LastPacketReceivedTime() const = 0; - Timestamp FirstPacketReceivedTime() const { - Timestamp first_packet_received_time = Timestamp::PlusInfinity(); - for (const auto& incoming_stats : incoming_stats_per_source) { - if (first_packet_received_time > - incoming_stats.second.first_packet_received_time) { - first_packet_received_time = - incoming_stats.second.first_packet_received_time; - } - } - return first_packet_received_time; - } + virtual DataRate AverageReceiveRate() const = 0; - Timestamp LastPacketReceivedTime() const { - Timestamp last_packet_received_time = Timestamp::MinusInfinity(); - for (const auto& incoming_stats : incoming_stats_per_source) { - if (last_packet_received_time < - incoming_stats.second.last_packet_received_time) { - last_packet_received_time = - incoming_stats.second.last_packet_received_time; - } - } - return last_packet_received_time; - } - - DataRate AverageReceiveRate() const { - RTC_DCHECK_GE(PacketsReceived(), 2); - return (BytesReceived() - FirstReceivedPacketSize()) / - (LastPacketReceivedTime() - FirstPacketReceivedTime()); - } + virtual std::map + IncomingStatsPerSource() const = 0; }; // EmulatedEndpoint is an abstraction for network interface on device. Instances @@ -218,7 +161,7 @@ class EmulatedEndpoint : public EmulatedNetworkReceiverInterface { virtual void UnbindReceiver(uint16_t port) = 0; virtual rtc::IPAddress GetPeerLocalAddress() const = 0; - virtual EmulatedNetworkStats stats() = 0; + virtual std::unique_ptr stats() const = 0; private: // Ensure that there can be no other subclass than EmulatedEndpointImpl. This diff --git a/api/test/network_emulation_manager.h b/api/test/network_emulation_manager.h index 3e9cf113d2..bdbc50138b 100644 --- a/api/test/network_emulation_manager.h +++ b/api/test/network_emulation_manager.h @@ -11,6 +11,7 @@ #ifndef API_TEST_NETWORK_EMULATION_MANAGER_H_ #define API_TEST_NETWORK_EMULATION_MANAGER_H_ +#include #include #include @@ -69,7 +70,8 @@ class EmulatedNetworkManagerInterface { // Returns summarized network stats for endpoints for this manager. virtual void GetStats( - std::function stats_callback) const = 0; + std::function)> stats_callback) + const = 0; }; enum class TimeMode { kRealTime, kSimulated }; diff --git a/test/network/BUILD.gn b/test/network/BUILD.gn index 35673741ce..058f473d1b 100644 --- a/test/network/BUILD.gn +++ b/test/network/BUILD.gn @@ -35,6 +35,7 @@ rtc_library("emulated_network") { "traffic_route.h", ] deps = [ + "../../api:array_view", "../../api:network_emulation_manager_api", "../../api:simulated_network_api", "../../api:time_controller", diff --git a/test/network/emulated_network_manager.cc b/test/network/emulated_network_manager.cc index 2dc2fad5b0..ec8b2b3554 100644 --- a/test/network/emulated_network_manager.cc +++ b/test/network/emulated_network_manager.cc @@ -80,7 +80,8 @@ void EmulatedNetworkManager::StopUpdating() { } void EmulatedNetworkManager::GetStats( - std::function stats_callback) const { + std::function)> stats_callback) + const { task_queue_->PostTask([stats_callback, this]() { stats_callback(endpoints_container_->GetStats()); }); diff --git a/test/network/emulated_network_manager.h b/test/network/emulated_network_manager.h index ca85d0b918..db884157c5 100644 --- a/test/network/emulated_network_manager.h +++ b/test/network/emulated_network_manager.h @@ -11,6 +11,7 @@ #ifndef TEST_NETWORK_EMULATED_NETWORK_MANAGER_H_ #define TEST_NETWORK_EMULATED_NETWORK_MANAGER_H_ +#include #include #include @@ -49,8 +50,8 @@ class EmulatedNetworkManager : public rtc::NetworkManagerBase, // EmulatedNetworkManagerInterface API rtc::Thread* network_thread() override { return network_thread_.get(); } rtc::NetworkManager* network_manager() override { return this; } - void GetStats( - std::function stats_callback) const override; + void GetStats(std::function)> + stats_callback) const override; private: void UpdateNetworksOnce(); diff --git a/test/network/network_emulation.cc b/test/network/network_emulation.cc index f3e29317ba..c71f6bb4a1 100644 --- a/test/network/network_emulation.cc +++ b/test/network/network_emulation.cc @@ -20,6 +20,121 @@ namespace webrtc { +EmulatedNetworkIncomingStats EmulatedNetworkStatsImpl::GetOverallIncomingStats() + const { + EmulatedNetworkIncomingStats stats; + for (const auto& entry : incoming_stats_per_source_) { + const EmulatedNetworkIncomingStats& source = entry.second; + stats.packets_received += source.packets_received; + stats.bytes_received += source.bytes_received; + stats.packets_dropped += source.packets_dropped; + stats.bytes_dropped += source.bytes_dropped; + if (stats.first_packet_received_time > source.first_packet_received_time) { + stats.first_packet_received_time = source.first_packet_received_time; + stats.first_received_packet_size = source.first_received_packet_size; + } + if (stats.last_packet_received_time < source.last_packet_received_time) { + stats.last_packet_received_time = source.last_packet_received_time; + } + } + return stats; +} + +EmulatedNetworkStatsBuilder::EmulatedNetworkStatsBuilder() { + sequence_checker_.Detach(); +} +EmulatedNetworkStatsBuilder::EmulatedNetworkStatsBuilder( + rtc::IPAddress local_ip) { + local_addresses_.push_back(local_ip); + sequence_checker_.Detach(); +} + +void EmulatedNetworkStatsBuilder::OnPacketSent(Timestamp sent_time, + DataSize packet_size) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_CHECK_GE(packet_size, DataSize::Zero()); + if (first_packet_sent_time_.IsInfinite()) { + first_packet_sent_time_ = sent_time; + first_sent_packet_size_ = packet_size; + } + last_packet_sent_time_ = sent_time; + packets_sent_++; + bytes_sent_ += packet_size; +} + +void EmulatedNetworkStatsBuilder::OnPacketDropped(rtc::IPAddress source_ip, + DataSize packet_size) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_CHECK_GE(packet_size, DataSize::Zero()); + EmulatedNetworkIncomingStats& source_stats = + incoming_stats_per_source_[source_ip]; + source_stats.packets_dropped++; + source_stats.bytes_dropped += packet_size; +} + +void EmulatedNetworkStatsBuilder::OnPacketReceived(Timestamp received_time, + rtc::IPAddress source_ip, + DataSize packet_size) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_CHECK_GE(packet_size, DataSize::Zero()); + EmulatedNetworkIncomingStats& source_stats = + incoming_stats_per_source_[source_ip]; + if (source_stats.first_packet_received_time.IsInfinite()) { + source_stats.first_packet_received_time = received_time; + source_stats.first_received_packet_size = packet_size; + } + source_stats.last_packet_received_time = received_time; + source_stats.packets_received++; + source_stats.bytes_received += packet_size; +} + +void EmulatedNetworkStatsBuilder::AppendEmulatedNetworkStats( + std::unique_ptr stats) { + RTC_DCHECK_RUN_ON(&sequence_checker_); + RTC_CHECK(stats); + packets_sent_ += stats->PacketsSent(); + bytes_sent_ += stats->BytesSent(); + if (first_packet_sent_time_ > stats->FirstPacketSentTime()) { + first_packet_sent_time_ = stats->FirstPacketSentTime(); + first_sent_packet_size_ = stats->FirstSentPacketSize(); + } + if (last_packet_sent_time_ < stats->LastPacketSentTime()) { + last_packet_sent_time_ = stats->LastPacketSentTime(); + } + for (const rtc::IPAddress& addr : stats->LocalAddresses()) { + local_addresses_.push_back(addr); + } + + const std::map + incoming_stats_per_source = stats->IncomingStatsPerSource(); + for (const auto& entry : incoming_stats_per_source) { + const EmulatedNetworkIncomingStats& source = entry.second; + EmulatedNetworkIncomingStats& in_stats = + incoming_stats_per_source_[entry.first]; + in_stats.packets_received += source.packets_received; + in_stats.bytes_received += source.bytes_received; + in_stats.packets_dropped += source.packets_dropped; + in_stats.bytes_dropped += source.bytes_dropped; + if (in_stats.first_packet_received_time > + source.first_packet_received_time) { + in_stats.first_packet_received_time = source.first_packet_received_time; + in_stats.first_received_packet_size = source.first_received_packet_size; + } + if (in_stats.last_packet_received_time < source.last_packet_received_time) { + in_stats.last_packet_received_time = source.last_packet_received_time; + } + } +} + +std::unique_ptr EmulatedNetworkStatsBuilder::Build() + const { + RTC_DCHECK_RUN_ON(&sequence_checker_); + return std::make_unique( + packets_sent_, bytes_sent_, local_addresses_, first_sent_packet_size_, + first_packet_sent_time_, last_packet_sent_time_, + incoming_stats_per_source_); +} + void LinkEmulation::OnPacketReceived(EmulatedIpPacket packet) { task_queue_->PostTask([this, packet = std::move(packet)]() mutable { RTC_DCHECK_RUN_ON(task_queue_); @@ -179,7 +294,8 @@ EmulatedEndpointImpl::EmulatedEndpointImpl(uint64_t id, clock_(clock), task_queue_(task_queue), router_(task_queue_), - next_port_(kFirstEphemeralPort) { + next_port_(kFirstEphemeralPort), + stats_builder_(peer_local_addr_) { constexpr int kIPv4NetworkPrefixLength = 24; constexpr int kIPv6NetworkPrefixLength = 64; @@ -196,7 +312,6 @@ EmulatedEndpointImpl::EmulatedEndpointImpl(uint64_t id, network_->AddIP(ip); enabled_state_checker_.Detach(); - stats_.local_addresses.push_back(peer_local_addr_); } EmulatedEndpointImpl::~EmulatedEndpointImpl() = default; @@ -213,14 +328,8 @@ void EmulatedEndpointImpl::SendPacket(const rtc::SocketAddress& from, clock_->CurrentTime(), application_overhead); task_queue_->PostTask([this, packet = std::move(packet)]() mutable { RTC_DCHECK_RUN_ON(task_queue_); - Timestamp current_time = clock_->CurrentTime(); - if (stats_.first_packet_sent_time.IsInfinite()) { - stats_.first_packet_sent_time = current_time; - stats_.first_sent_packet_size = DataSize::Bytes(packet.ip_packet_size()); - } - stats_.last_packet_sent_time = current_time; - stats_.packets_sent++; - stats_.bytes_sent += DataSize::Bytes(packet.ip_packet_size()); + stats_builder_.OnPacketSent(clock_->CurrentTime(), + DataSize::Bytes(packet.ip_packet_size())); router_.OnPacketReceived(std::move(packet)); }); @@ -283,7 +392,8 @@ void EmulatedEndpointImpl::OnPacketReceived(EmulatedIpPacket packet) { << packet.to.ipaddr().ToString() << "; Receiver peer_local_addr_=" << peer_local_addr_.ToString(); rtc::CritScope crit(&receiver_lock_); - UpdateReceiveStats(packet); + stats_builder_.OnPacketReceived(clock_->CurrentTime(), packet.from.ipaddr(), + DataSize::Bytes(packet.ip_packet_size())); auto it = port_to_receiver_.find(packet.to.port()); if (it == port_to_receiver_.end()) { // It can happen, that remote peer closed connection, but there still some @@ -291,9 +401,8 @@ void EmulatedEndpointImpl::OnPacketReceived(EmulatedIpPacket packet) { // process: one peer closed connection, second still sending data. RTC_LOG(INFO) << "Drop packet: no receiver registered in " << id_ << " on port " << packet.to.port(); - stats_.incoming_stats_per_source[packet.from.ipaddr()].packets_dropped++; - stats_.incoming_stats_per_source[packet.from.ipaddr()].bytes_dropped += - DataSize::Bytes(packet.ip_packet_size()); + stats_builder_.OnPacketDropped(packet.from.ipaddr(), + DataSize::Bytes(packet.ip_packet_size())); return; } // Endpoint assumes frequent calls to bind and unbind methods, so it holds @@ -319,26 +428,9 @@ bool EmulatedEndpointImpl::Enabled() const { return is_enabled_; } -EmulatedNetworkStats EmulatedEndpointImpl::stats() { +std::unique_ptr EmulatedEndpointImpl::stats() const { RTC_DCHECK_RUN_ON(task_queue_); - return stats_; -} - -void EmulatedEndpointImpl::UpdateReceiveStats(const EmulatedIpPacket& packet) { - RTC_DCHECK_RUN_ON(task_queue_); - Timestamp current_time = clock_->CurrentTime(); - if (stats_.incoming_stats_per_source[packet.from.ipaddr()] - .first_packet_received_time.IsInfinite()) { - stats_.incoming_stats_per_source[packet.from.ipaddr()] - .first_packet_received_time = current_time; - stats_.incoming_stats_per_source[packet.from.ipaddr()] - .first_received_packet_size = DataSize::Bytes(packet.ip_packet_size()); - } - stats_.incoming_stats_per_source[packet.from.ipaddr()] - .last_packet_received_time = current_time; - stats_.incoming_stats_per_source[packet.from.ipaddr()].packets_received++; - stats_.incoming_stats_per_source[packet.from.ipaddr()].bytes_received += - DataSize::Bytes(packet.ip_packet_size()); + return stats_builder_.Build(); } EndpointsContainer::EndpointsContainer( @@ -377,42 +469,12 @@ EndpointsContainer::GetEnabledNetworks() const { return networks; } -EmulatedNetworkStats EndpointsContainer::GetStats() const { - EmulatedNetworkStats stats; +std::unique_ptr EndpointsContainer::GetStats() const { + EmulatedNetworkStatsBuilder stats_builder; for (auto* endpoint : endpoints_) { - EmulatedNetworkStats endpoint_stats = endpoint->stats(); - stats.packets_sent += endpoint_stats.packets_sent; - stats.bytes_sent += endpoint_stats.bytes_sent; - if (stats.first_packet_sent_time > endpoint_stats.first_packet_sent_time) { - stats.first_packet_sent_time = endpoint_stats.first_packet_sent_time; - stats.first_sent_packet_size = endpoint_stats.first_sent_packet_size; - } - if (stats.last_packet_sent_time < endpoint_stats.last_packet_sent_time) { - stats.last_packet_sent_time = endpoint_stats.last_packet_sent_time; - } - for (const rtc::IPAddress& addr : endpoint_stats.local_addresses) { - stats.local_addresses.push_back(addr); - } - for (auto& entry : endpoint_stats.incoming_stats_per_source) { - const EmulatedNetworkIncomingStats& source = entry.second; - EmulatedNetworkIncomingStats& in_stats = - stats.incoming_stats_per_source[entry.first]; - in_stats.packets_received += source.packets_received; - in_stats.bytes_received += source.bytes_received; - in_stats.packets_dropped += source.packets_dropped; - in_stats.bytes_dropped += source.bytes_dropped; - if (in_stats.first_packet_received_time > - source.first_packet_received_time) { - in_stats.first_packet_received_time = source.first_packet_received_time; - in_stats.first_received_packet_size = source.first_received_packet_size; - } - if (in_stats.last_packet_received_time < - source.last_packet_received_time) { - in_stats.last_packet_received_time = source.last_packet_received_time; - } - } + stats_builder.AppendEmulatedNetworkStats(endpoint->stats()); } - return stats; + return stats_builder.Build(); } } // namespace webrtc diff --git a/test/network/network_emulation.h b/test/network/network_emulation.h index a811a108ef..d2bb121a62 100644 --- a/test/network/network_emulation.h +++ b/test/network/network_emulation.h @@ -20,6 +20,7 @@ #include #include "absl/types/optional.h" +#include "api/array_view.h" #include "api/test/network_emulation_manager.h" #include "api/test/simulated_network.h" #include "api/units/timestamp.h" @@ -27,6 +28,7 @@ #include "rtc_base/network.h" #include "rtc_base/network_constants.h" #include "rtc_base/socket_address.h" +#include "rtc_base/synchronization/sequence_checker.h" #include "rtc_base/task_queue_for_test.h" #include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/thread_checker.h" @@ -34,6 +36,142 @@ namespace webrtc { +// This class is immutable and so is thread safe. +class EmulatedNetworkStatsImpl final : public EmulatedNetworkStats { + public: + EmulatedNetworkStatsImpl( + int64_t packets_sent, + DataSize bytes_sent, + std::vector local_addresses, + DataSize first_sent_packet_size, + Timestamp first_packet_sent_time, + Timestamp last_packet_sent_time, + std::map + incoming_stats_per_source) + : packets_sent_(packets_sent), + bytes_sent_(bytes_sent), + local_addresses_(std::move(local_addresses)), + first_sent_packet_size_(first_sent_packet_size), + first_packet_sent_time_(first_packet_sent_time), + last_packet_sent_time_(last_packet_sent_time), + incoming_stats_per_source_(std::move(incoming_stats_per_source)) {} + ~EmulatedNetworkStatsImpl() override = default; + + int64_t PacketsSent() const override { return packets_sent_; } + + DataSize BytesSent() const override { return bytes_sent_; } + + std::vector LocalAddresses() const override { + return local_addresses_; + } + + DataSize FirstSentPacketSize() const override { + return first_sent_packet_size_; + } + + Timestamp FirstPacketSentTime() const override { + return first_packet_sent_time_; + } + + Timestamp LastPacketSentTime() const override { + return last_packet_sent_time_; + } + + DataRate AverageSendRate() const override { + RTC_DCHECK_GE(packets_sent_, 2); + return (bytes_sent_ - first_sent_packet_size_) / + (last_packet_sent_time_ - first_packet_sent_time_); + } + + int64_t PacketsReceived() const override { + return GetOverallIncomingStats().packets_received; + } + + DataSize BytesReceived() const override { + return GetOverallIncomingStats().bytes_received; + } + + int64_t PacketsDropped() const override { + return GetOverallIncomingStats().packets_dropped; + } + + DataSize BytesDropped() const override { + return GetOverallIncomingStats().bytes_dropped; + } + + DataSize FirstReceivedPacketSize() const override { + return GetOverallIncomingStats().first_received_packet_size; + } + + Timestamp FirstPacketReceivedTime() const override { + return GetOverallIncomingStats().first_packet_received_time; + } + + Timestamp LastPacketReceivedTime() const override { + return GetOverallIncomingStats().last_packet_received_time; + } + + DataRate AverageReceiveRate() const override { + return GetOverallIncomingStats().AverageReceiveRate(); + } + + std::map + IncomingStatsPerSource() const override { + return incoming_stats_per_source_; + } + + private: + EmulatedNetworkIncomingStats GetOverallIncomingStats() const; + + const int64_t packets_sent_; + const DataSize bytes_sent_; + const std::vector local_addresses_; + + const DataSize first_sent_packet_size_; + const Timestamp first_packet_sent_time_; + const Timestamp last_packet_sent_time_; + + const std::map + incoming_stats_per_source_; +}; + +// All methods of EmulatedNetworkStatsBuilder have to be used on a single +// thread. It may be created on another thread. +class EmulatedNetworkStatsBuilder { + public: + EmulatedNetworkStatsBuilder(); + explicit EmulatedNetworkStatsBuilder(rtc::IPAddress local_ip); + + void OnPacketSent(Timestamp sent_time, DataSize packet_size); + + void OnPacketDropped(rtc::IPAddress source_ip, DataSize packet_size); + + void OnPacketReceived(Timestamp received_time, + rtc::IPAddress source_ip, + DataSize packet_size); + + void AppendEmulatedNetworkStats(std::unique_ptr stats); + + std::unique_ptr Build() const; + + private: + SequenceChecker sequence_checker_; + + int64_t packets_sent_ RTC_GUARDED_BY(sequence_checker_) = 0; + DataSize bytes_sent_ RTC_GUARDED_BY(sequence_checker_) = DataSize::Zero(); + std::vector local_addresses_ + RTC_GUARDED_BY(sequence_checker_); + + DataSize first_sent_packet_size_ RTC_GUARDED_BY(sequence_checker_) = + DataSize::Zero(); + Timestamp first_packet_sent_time_ RTC_GUARDED_BY(sequence_checker_) = + Timestamp::PlusInfinity(); + Timestamp last_packet_sent_time_ RTC_GUARDED_BY(sequence_checker_) = + Timestamp::MinusInfinity(); + + std::map + incoming_stats_per_source_ RTC_GUARDED_BY(sequence_checker_); +}; class LinkEmulation : public EmulatedNetworkReceiverInterface { public: @@ -161,12 +299,11 @@ class EmulatedEndpointImpl : public EmulatedEndpoint { const rtc::Network& network() const { return *network_.get(); } - EmulatedNetworkStats stats() override; + std::unique_ptr stats() const override; private: static constexpr uint16_t kFirstEphemeralPort = 49152; uint16_t NextPort() RTC_EXCLUSIVE_LOCKS_REQUIRED(receiver_lock_); - void UpdateReceiveStats(const EmulatedIpPacket& packet); rtc::RecursiveCriticalSection receiver_lock_; rtc::ThreadChecker enabled_state_checker_; @@ -185,7 +322,7 @@ class EmulatedEndpointImpl : public EmulatedEndpoint { std::map port_to_receiver_ RTC_GUARDED_BY(receiver_lock_); - EmulatedNetworkStats stats_ RTC_GUARDED_BY(task_queue_); + EmulatedNetworkStatsBuilder stats_builder_ RTC_GUARDED_BY(task_queue_); }; class EmulatedRoute { @@ -212,7 +349,7 @@ class EndpointsContainer { // Returns list of networks for enabled endpoints. Caller takes ownership of // returned rtc::Network objects. std::vector> GetEnabledNetworks() const; - EmulatedNetworkStats GetStats() const; + std::unique_ptr GetStats() const; private: const std::vector endpoints_; diff --git a/test/network/network_emulation_unittest.cc b/test/network/network_emulation_unittest.cc index ff8539007d..6914c6e039 100644 --- a/test/network/network_emulation_unittest.cc +++ b/test/network/network_emulation_unittest.cc @@ -247,59 +247,60 @@ TEST(NetworkEmulationManagerTest, Run) { const int64_t single_packet_size = data.size() + kOverheadIpv4Udp; std::atomic received_stats_count{0}; - nt1->GetStats([&](EmulatedNetworkStats st) { - EXPECT_EQ(st.packets_sent, 2000l); - EXPECT_EQ(st.bytes_sent.bytes(), single_packet_size * 2000l); - EXPECT_THAT(st.local_addresses, + nt1->GetStats([&](std::unique_ptr st) { + EXPECT_EQ(st->PacketsSent(), 2000l); + EXPECT_EQ(st->BytesSent().bytes(), single_packet_size * 2000l); + EXPECT_THAT(st->LocalAddresses(), ElementsAreArray({alice_endpoint->GetPeerLocalAddress()})); - EXPECT_EQ(st.PacketsReceived(), 2000l); - EXPECT_EQ(st.BytesReceived().bytes(), single_packet_size * 2000l); - EXPECT_EQ(st.PacketsDropped(), 0l); - EXPECT_EQ(st.BytesDropped().bytes(), 0l); + EXPECT_EQ(st->PacketsReceived(), 2000l); + EXPECT_EQ(st->BytesReceived().bytes(), single_packet_size * 2000l); + EXPECT_EQ(st->PacketsDropped(), 0l); + EXPECT_EQ(st->BytesDropped().bytes(), 0l); - EXPECT_EQ(st.incoming_stats_per_source[bob_endpoint->GetPeerLocalAddress()] - .packets_received, - 2000l); - EXPECT_EQ(st.incoming_stats_per_source[bob_endpoint->GetPeerLocalAddress()] + std::map source_st = + st->IncomingStatsPerSource(); + ASSERT_EQ(source_st.size(), 1lu); + EXPECT_EQ( + source_st.at(bob_endpoint->GetPeerLocalAddress()).packets_received, + 2000l); + EXPECT_EQ(source_st.at(bob_endpoint->GetPeerLocalAddress()) .bytes_received.bytes(), single_packet_size * 2000l); - EXPECT_EQ(st.incoming_stats_per_source[bob_endpoint->GetPeerLocalAddress()] - .packets_dropped, - 0l); - EXPECT_EQ(st.incoming_stats_per_source[bob_endpoint->GetPeerLocalAddress()] - .bytes_dropped.bytes(), + EXPECT_EQ(source_st.at(bob_endpoint->GetPeerLocalAddress()).packets_dropped, 0l); + EXPECT_EQ( + source_st.at(bob_endpoint->GetPeerLocalAddress()).bytes_dropped.bytes(), + 0l); received_stats_count++; }); - nt2->GetStats([&](EmulatedNetworkStats st) { - EXPECT_EQ(st.packets_sent, 2000l); - EXPECT_EQ(st.bytes_sent.bytes(), single_packet_size * 2000l); - EXPECT_THAT(st.local_addresses, + nt2->GetStats([&](std::unique_ptr st) { + EXPECT_EQ(st->PacketsSent(), 2000l); + EXPECT_EQ(st->BytesSent().bytes(), single_packet_size * 2000l); + EXPECT_THAT(st->LocalAddresses(), ElementsAreArray({bob_endpoint->GetPeerLocalAddress()})); - EXPECT_EQ(st.PacketsReceived(), 2000l); - EXPECT_EQ(st.BytesReceived().bytes(), single_packet_size * 2000l); - EXPECT_EQ(st.PacketsDropped(), 0l); - EXPECT_EQ(st.BytesDropped().bytes(), 0l); - EXPECT_GT(st.FirstReceivedPacketSize(), DataSize::Zero()); - EXPECT_TRUE(st.FirstPacketReceivedTime().IsFinite()); - EXPECT_TRUE(st.LastPacketReceivedTime().IsFinite()); + EXPECT_EQ(st->PacketsReceived(), 2000l); + EXPECT_EQ(st->BytesReceived().bytes(), single_packet_size * 2000l); + EXPECT_EQ(st->PacketsDropped(), 0l); + EXPECT_EQ(st->BytesDropped().bytes(), 0l); + EXPECT_GT(st->FirstReceivedPacketSize(), DataSize::Zero()); + EXPECT_TRUE(st->FirstPacketReceivedTime().IsFinite()); + EXPECT_TRUE(st->LastPacketReceivedTime().IsFinite()); + std::map source_st = + st->IncomingStatsPerSource(); + ASSERT_EQ(source_st.size(), 1lu); EXPECT_EQ( - st.incoming_stats_per_source[alice_endpoint->GetPeerLocalAddress()] - .packets_received, + source_st.at(alice_endpoint->GetPeerLocalAddress()).packets_received, 2000l); + EXPECT_EQ(source_st.at(alice_endpoint->GetPeerLocalAddress()) + .bytes_received.bytes(), + single_packet_size * 2000l); EXPECT_EQ( - st.incoming_stats_per_source[alice_endpoint->GetPeerLocalAddress()] - .bytes_received.bytes(), - single_packet_size * 2000l); - EXPECT_EQ( - st.incoming_stats_per_source[alice_endpoint->GetPeerLocalAddress()] - .packets_dropped, - 0l); - EXPECT_EQ( - st.incoming_stats_per_source[alice_endpoint->GetPeerLocalAddress()] - .bytes_dropped.bytes(), + source_st.at(alice_endpoint->GetPeerLocalAddress()).packets_dropped, 0l); + EXPECT_EQ(source_st.at(alice_endpoint->GetPeerLocalAddress()) + .bytes_dropped.bytes(), + 0l); received_stats_count++; }); ASSERT_EQ_SIMULATED_WAIT(received_stats_count.load(), 2, @@ -363,14 +364,14 @@ TEST(NetworkEmulationManagerTest, ThroughputStats) { } std::atomic received_stats_count{0}; - nt1->GetStats([&](EmulatedNetworkStats st) { - EXPECT_EQ(st.packets_sent, kNumPacketsSent); - EXPECT_EQ(st.bytes_sent.bytes(), kSinglePacketSize * kNumPacketsSent); + nt1->GetStats([&](std::unique_ptr st) { + EXPECT_EQ(st->PacketsSent(), kNumPacketsSent); + EXPECT_EQ(st->BytesSent().bytes(), kSinglePacketSize * kNumPacketsSent); const double tolerance = 0.95; // Accept 5% tolerance for timing. - EXPECT_GE(st.last_packet_sent_time - st.first_packet_sent_time, + EXPECT_GE(st->LastPacketSentTime() - st->FirstPacketSentTime(), (kNumPacketsSent - 1) * kDelay * tolerance); - EXPECT_GT(st.AverageSendRate().bps(), 0); + EXPECT_GT(st->AverageSendRate().bps(), 0); received_stats_count++; }); diff --git a/test/pc/e2e/network_quality_metrics_reporter.cc b/test/pc/e2e/network_quality_metrics_reporter.cc index cd6dfb5032..2df45291d8 100644 --- a/test/pc/e2e/network_quality_metrics_reporter.cc +++ b/test/pc/e2e/network_quality_metrics_reporter.cc @@ -34,12 +34,13 @@ void NetworkQualityMetricsReporter::Start( const TrackIdStreamInfoMap* /*reporter_helper*/) { test_case_name_ = std::string(test_case_name); // Check that network stats are clean before test execution. - EmulatedNetworkStats alice_stats = PopulateStats(alice_network_); - RTC_CHECK_EQ(alice_stats.packets_sent, 0); - RTC_CHECK_EQ(alice_stats.PacketsReceived(), 0); - EmulatedNetworkStats bob_stats = PopulateStats(bob_network_); - RTC_CHECK_EQ(bob_stats.packets_sent, 0); - RTC_CHECK_EQ(bob_stats.PacketsReceived(), 0); + std::unique_ptr alice_stats = + PopulateStats(alice_network_); + RTC_CHECK_EQ(alice_stats->PacketsSent(), 0); + RTC_CHECK_EQ(alice_stats->PacketsReceived(), 0); + std::unique_ptr bob_stats = PopulateStats(bob_network_); + RTC_CHECK_EQ(bob_stats->PacketsSent(), 0); + RTC_CHECK_EQ(bob_stats->PacketsReceived(), 0); } void NetworkQualityMetricsReporter::OnStatsReports( @@ -69,12 +70,15 @@ void NetworkQualityMetricsReporter::OnStatsReports( } void NetworkQualityMetricsReporter::StopAndReportResults() { - EmulatedNetworkStats alice_stats = PopulateStats(alice_network_); - EmulatedNetworkStats bob_stats = PopulateStats(bob_network_); - ReportStats("alice", alice_stats, - alice_stats.packets_sent - bob_stats.PacketsReceived()); - ReportStats("bob", bob_stats, - bob_stats.packets_sent - alice_stats.PacketsReceived()); + std::unique_ptr alice_stats = + PopulateStats(alice_network_); + std::unique_ptr bob_stats = PopulateStats(bob_network_); + int64_t alice_packets_loss = + alice_stats->PacketsSent() - bob_stats->PacketsReceived(); + int64_t bob_packets_loss = + bob_stats->PacketsSent() - alice_stats->PacketsReceived(); + ReportStats("alice", std::move(alice_stats), alice_packets_loss); + ReportStats("bob", std::move(bob_stats), bob_packets_loss); if (!webrtc::field_trial::IsEnabled(kUseStandardBytesStats)) { RTC_LOG(LS_ERROR) @@ -87,12 +91,13 @@ void NetworkQualityMetricsReporter::StopAndReportResults() { } } -EmulatedNetworkStats NetworkQualityMetricsReporter::PopulateStats( +std::unique_ptr +NetworkQualityMetricsReporter::PopulateStats( EmulatedNetworkManagerInterface* network) { rtc::Event wait; - EmulatedNetworkStats stats; - network->GetStats([&](const EmulatedNetworkStats& s) { - stats = s; + std::unique_ptr stats; + network->GetStats([&](std::unique_ptr s) { + stats = std::move(s); wait.Set(); }); bool stats_received = wait.Wait(kStatsWaitTimeoutMs); @@ -102,26 +107,26 @@ EmulatedNetworkStats NetworkQualityMetricsReporter::PopulateStats( void NetworkQualityMetricsReporter::ReportStats( const std::string& network_label, - const EmulatedNetworkStats& stats, + std::unique_ptr stats, int64_t packet_loss) { - ReportResult("bytes_sent", network_label, stats.bytes_sent.bytes(), + ReportResult("bytes_sent", network_label, stats->BytesSent().bytes(), "sizeInBytes"); - ReportResult("packets_sent", network_label, stats.packets_sent, "unitless"); + ReportResult("packets_sent", network_label, stats->PacketsSent(), "unitless"); ReportResult( "average_send_rate", network_label, - stats.packets_sent >= 2 ? stats.AverageSendRate().bytes_per_sec() : 0, + stats->PacketsSent() >= 2 ? stats->AverageSendRate().bytes_per_sec() : 0, "bytesPerSecond"); - ReportResult("bytes_dropped", network_label, stats.BytesDropped().bytes(), + ReportResult("bytes_dropped", network_label, stats->BytesDropped().bytes(), "sizeInBytes"); - ReportResult("packets_dropped", network_label, stats.PacketsDropped(), + ReportResult("packets_dropped", network_label, stats->PacketsDropped(), "unitless"); - ReportResult("bytes_received", network_label, stats.BytesReceived().bytes(), + ReportResult("bytes_received", network_label, stats->BytesReceived().bytes(), "sizeInBytes"); - ReportResult("packets_received", network_label, stats.PacketsReceived(), + ReportResult("packets_received", network_label, stats->PacketsReceived(), "unitless"); ReportResult("average_receive_rate", network_label, - stats.PacketsReceived() >= 2 - ? stats.AverageReceiveRate().bytes_per_sec() + stats->PacketsReceived() >= 2 + ? stats->AverageReceiveRate().bytes_per_sec() : 0, "bytesPerSecond"); ReportResult("sent_packets_loss", network_label, packet_loss, "unitless"); diff --git a/test/pc/e2e/network_quality_metrics_reporter.h b/test/pc/e2e/network_quality_metrics_reporter.h index 4c81f9d716..50c36234a5 100644 --- a/test/pc/e2e/network_quality_metrics_reporter.h +++ b/test/pc/e2e/network_quality_metrics_reporter.h @@ -11,6 +11,7 @@ #ifndef TEST_PC_E2E_NETWORK_QUALITY_METRICS_REPORTER_H_ #define TEST_PC_E2E_NETWORK_QUALITY_METRICS_REPORTER_H_ +#include #include #include "absl/strings/string_view.h" @@ -47,10 +48,10 @@ class NetworkQualityMetricsReporter DataSize payload_sent = DataSize::Zero(); }; - static EmulatedNetworkStats PopulateStats( + static std::unique_ptr PopulateStats( EmulatedNetworkManagerInterface* network); void ReportStats(const std::string& network_label, - const EmulatedNetworkStats& stats, + std::unique_ptr stats, int64_t packet_loss); void ReportPCStats(const std::string& pc_label, const PCStats& stats); void ReportResult(const std::string& metric_name,