Replace network layer stats struct with interface
It is a follow up CL to
https://webrtc-review.googlesource.com/c/src/+/179368.
Now when network stats became more complex structure it's better to hide
its implementation details and provide an interface for read-only
access.
Bug: webrtc:11756
Change-Id: I1980ef938f8de0c6aa90092d1dc90a14a82e0ee1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/179840
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31784}
diff --git a/api/test/network_emulation/BUILD.gn b/api/test/network_emulation/BUILD.gn
index a3dd961..4780da2 100644
--- a/api/test/network_emulation/BUILD.gn
+++ b/api/test/network_emulation/BUILD.gn
@@ -17,6 +17,7 @@
]
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 260ab0e..b1aa0d2 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 <map>
+#include <memory>
#include <vector>
#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 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<rtc::IPAddress> local_addresses;
+ virtual std::vector<rtc::IPAddress> LocalAddresses() const = 0;
- std::map<rtc::IPAddress, EmulatedNetworkIncomingStats>
- incoming_stats_per_source;
+ 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;
- 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 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<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ IncomingStatsPerSource() const = 0;
};
// EmulatedEndpoint is an abstraction for network interface on device. Instances
@@ -218,7 +161,7 @@
virtual void UnbindReceiver(uint16_t port) = 0;
virtual rtc::IPAddress GetPeerLocalAddress() const = 0;
- virtual EmulatedNetworkStats stats() = 0;
+ virtual std::unique_ptr<EmulatedNetworkStats> 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 3e9cf11..bdbc501 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 <functional>
#include <memory>
#include <vector>
@@ -69,7 +70,8 @@
// Returns summarized network stats for endpoints for this manager.
virtual void GetStats(
- std::function<void(EmulatedNetworkStats)> stats_callback) const = 0;
+ std::function<void(std::unique_ptr<EmulatedNetworkStats>)> stats_callback)
+ const = 0;
};
enum class TimeMode { kRealTime, kSimulated };
diff --git a/test/network/BUILD.gn b/test/network/BUILD.gn
index 3567374..058f473 100644
--- a/test/network/BUILD.gn
+++ b/test/network/BUILD.gn
@@ -35,6 +35,7 @@
"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 2dc2fad..ec8b2b3 100644
--- a/test/network/emulated_network_manager.cc
+++ b/test/network/emulated_network_manager.cc
@@ -80,7 +80,8 @@
}
void EmulatedNetworkManager::GetStats(
- std::function<void(EmulatedNetworkStats)> stats_callback) const {
+ std::function<void(std::unique_ptr<EmulatedNetworkStats>)> 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 ca85d0b..db88415 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 <functional>
#include <memory>
#include <vector>
@@ -49,8 +50,8 @@
// EmulatedNetworkManagerInterface API
rtc::Thread* network_thread() override { return network_thread_.get(); }
rtc::NetworkManager* network_manager() override { return this; }
- void GetStats(
- std::function<void(EmulatedNetworkStats)> stats_callback) const override;
+ void GetStats(std::function<void(std::unique_ptr<EmulatedNetworkStats>)>
+ stats_callback) const override;
private:
void UpdateNetworksOnce();
diff --git a/test/network/network_emulation.cc b/test/network/network_emulation.cc
index f3e2931..c71f6bb 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<EmulatedNetworkStats> 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<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ 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<EmulatedNetworkStats> EmulatedNetworkStatsBuilder::Build()
+ const {
+ RTC_DCHECK_RUN_ON(&sequence_checker_);
+ return std::make_unique<EmulatedNetworkStatsImpl>(
+ 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 @@
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 @@
network_->AddIP(ip);
enabled_state_checker_.Detach();
- stats_.local_addresses.push_back(peer_local_addr_);
}
EmulatedEndpointImpl::~EmulatedEndpointImpl() = default;
@@ -213,14 +328,8 @@
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 @@
<< 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 @@
// 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 @@
return is_enabled_;
}
-EmulatedNetworkStats EmulatedEndpointImpl::stats() {
+std::unique_ptr<EmulatedNetworkStats> 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 @@
return networks;
}
-EmulatedNetworkStats EndpointsContainer::GetStats() const {
- EmulatedNetworkStats stats;
+std::unique_ptr<EmulatedNetworkStats> 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 a811a10..d2bb121 100644
--- a/test/network/network_emulation.h
+++ b/test/network/network_emulation.h
@@ -20,6 +20,7 @@
#include <vector>
#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<rtc::IPAddress> local_addresses,
+ DataSize first_sent_packet_size,
+ Timestamp first_packet_sent_time,
+ Timestamp last_packet_sent_time,
+ std::map<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ 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<rtc::IPAddress> 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<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ IncomingStatsPerSource() const override {
+ return incoming_stats_per_source_;
+ }
+
+ private:
+ EmulatedNetworkIncomingStats GetOverallIncomingStats() const;
+
+ const int64_t packets_sent_;
+ const DataSize bytes_sent_;
+ const std::vector<rtc::IPAddress> local_addresses_;
+
+ const DataSize first_sent_packet_size_;
+ const Timestamp first_packet_sent_time_;
+ const Timestamp last_packet_sent_time_;
+
+ const std::map<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ 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<EmulatedNetworkStats> stats);
+
+ std::unique_ptr<EmulatedNetworkStats> 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<rtc::IPAddress> 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<rtc::IPAddress, EmulatedNetworkIncomingStats>
+ incoming_stats_per_source_ RTC_GUARDED_BY(sequence_checker_);
+};
class LinkEmulation : public EmulatedNetworkReceiverInterface {
public:
@@ -161,12 +299,11 @@
const rtc::Network& network() const { return *network_.get(); }
- EmulatedNetworkStats stats() override;
+ std::unique_ptr<EmulatedNetworkStats> 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 @@
std::map<uint16_t, EmulatedNetworkReceiverInterface*> 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 @@
// Returns list of networks for enabled endpoints. Caller takes ownership of
// returned rtc::Network objects.
std::vector<std::unique_ptr<rtc::Network>> GetEnabledNetworks() const;
- EmulatedNetworkStats GetStats() const;
+ std::unique_ptr<EmulatedNetworkStats> GetStats() const;
private:
const std::vector<EmulatedEndpointImpl*> endpoints_;
diff --git a/test/network/network_emulation_unittest.cc b/test/network/network_emulation_unittest.cc
index ff85390..6914c6e 100644
--- a/test/network/network_emulation_unittest.cc
+++ b/test/network/network_emulation_unittest.cc
@@ -247,59 +247,60 @@
const int64_t single_packet_size = data.size() + kOverheadIpv4Udp;
std::atomic<int> 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<EmulatedNetworkStats> 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<rtc::IPAddress, EmulatedNetworkIncomingStats> 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,
+ EXPECT_EQ(source_st.at(bob_endpoint->GetPeerLocalAddress()).packets_dropped,
0l);
- EXPECT_EQ(st.incoming_stats_per_source[bob_endpoint->GetPeerLocalAddress()]
- .bytes_dropped.bytes(),
- 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<EmulatedNetworkStats> 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<rtc::IPAddress, EmulatedNetworkIncomingStats> 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,
+ source_st.at(alice_endpoint->GetPeerLocalAddress()).packets_dropped,
0l);
- EXPECT_EQ(
- st.incoming_stats_per_source[alice_endpoint->GetPeerLocalAddress()]
- .bytes_dropped.bytes(),
- 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 @@
}
std::atomic<int> 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<EmulatedNetworkStats> 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 cd6dfb5..2df4529 100644
--- a/test/pc/e2e/network_quality_metrics_reporter.cc
+++ b/test/pc/e2e/network_quality_metrics_reporter.cc
@@ -34,12 +34,13 @@
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<EmulatedNetworkStats> alice_stats =
+ PopulateStats(alice_network_);
+ RTC_CHECK_EQ(alice_stats->PacketsSent(), 0);
+ RTC_CHECK_EQ(alice_stats->PacketsReceived(), 0);
+ std::unique_ptr<EmulatedNetworkStats> 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::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<EmulatedNetworkStats> alice_stats =
+ PopulateStats(alice_network_);
+ std::unique_ptr<EmulatedNetworkStats> 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 @@
}
}
-EmulatedNetworkStats NetworkQualityMetricsReporter::PopulateStats(
+std::unique_ptr<EmulatedNetworkStats>
+NetworkQualityMetricsReporter::PopulateStats(
EmulatedNetworkManagerInterface* network) {
rtc::Event wait;
- EmulatedNetworkStats stats;
- network->GetStats([&](const EmulatedNetworkStats& s) {
- stats = s;
+ std::unique_ptr<EmulatedNetworkStats> stats;
+ network->GetStats([&](std::unique_ptr<EmulatedNetworkStats> s) {
+ stats = std::move(s);
wait.Set();
});
bool stats_received = wait.Wait(kStatsWaitTimeoutMs);
@@ -102,26 +107,26 @@
void NetworkQualityMetricsReporter::ReportStats(
const std::string& network_label,
- const EmulatedNetworkStats& stats,
+ std::unique_ptr<EmulatedNetworkStats> 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 4c81f9d..50c3623 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 <memory>
#include <string>
#include "absl/strings/string_view.h"
@@ -47,10 +48,10 @@
DataSize payload_sent = DataSize::Zero();
};
- static EmulatedNetworkStats PopulateStats(
+ static std::unique_ptr<EmulatedNetworkStats> PopulateStats(
EmulatedNetworkManagerInterface* network);
void ReportStats(const std::string& network_label,
- const EmulatedNetworkStats& stats,
+ std::unique_ptr<EmulatedNetworkStats> stats,
int64_t packet_loss);
void ReportPCStats(const std::string& pc_label, const PCStats& stats);
void ReportResult(const std::string& metric_name,