blob: d073b15437a9e46e945fec48a2ce083c78f69143 [file] [log] [blame]
/*
* Copyright (c) 2019 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 "test/pc/e2e/network_quality_metrics_reporter.h"
#include <utility>
#include "api/stats/rtc_stats.h"
#include "api/stats/rtcstats_objects.h"
#include "api/test/metrics/metric.h"
#include "rtc_base/event.h"
#include "system_wrappers/include/field_trial.h"
#include "test/testsupport/perf_test.h"
namespace webrtc {
namespace webrtc_pc_e2e {
namespace {
using ::webrtc::test::ImprovementDirection;
using ::webrtc::test::Unit;
constexpr TimeDelta kStatsWaitTimeout = TimeDelta::Seconds(1);
// Field trial which controls whether to report standard-compliant bytes
// sent/received per stream. If enabled, padding and headers are not included
// in bytes sent or received.
constexpr char kUseStandardBytesStats[] = "WebRTC-UseStandardBytesStats";
}
void NetworkQualityMetricsReporter::Start(
absl::string_view test_case_name,
const TrackIdStreamInfoMap* /*reporter_helper*/) {
test_case_name_ = std::string(test_case_name);
// Check that network stats are clean before test execution.
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(
absl::string_view pc_label,
const rtc::scoped_refptr<const RTCStatsReport>& report) {
DataSize payload_received = DataSize::Zero();
DataSize payload_sent = DataSize::Zero();
auto inbound_stats = report->GetStatsOfType<RTCInboundRTPStreamStats>();
for (const auto& stat : inbound_stats) {
payload_received +=
DataSize::Bytes(stat->bytes_received.ValueOrDefault(0ul) +
stat->header_bytes_received.ValueOrDefault(0ul));
}
auto outbound_stats = report->GetStatsOfType<RTCOutboundRTPStreamStats>();
for (const auto& stat : outbound_stats) {
payload_sent +=
DataSize::Bytes(stat->bytes_sent.ValueOrDefault(0ul) +
stat->header_bytes_sent.ValueOrDefault(0ul));
}
MutexLock lock(&lock_);
PCStats& stats = pc_stats_[std::string(pc_label)];
stats.payload_received = payload_received;
stats.payload_sent = payload_sent;
}
void NetworkQualityMetricsReporter::StopAndReportResults() {
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)
<< "Non-standard GetStats; \"payload\" counts include RTP headers";
}
MutexLock lock(&lock_);
for (const auto& pair : pc_stats_) {
ReportPCStats(pair.first, pair.second);
}
}
std::unique_ptr<EmulatedNetworkStats>
NetworkQualityMetricsReporter::PopulateStats(
EmulatedNetworkManagerInterface* network) {
rtc::Event wait;
std::unique_ptr<EmulatedNetworkStats> stats;
network->GetStats([&](std::unique_ptr<EmulatedNetworkStats> s) {
stats = std::move(s);
wait.Set();
});
bool stats_received = wait.Wait(kStatsWaitTimeout);
RTC_CHECK(stats_received);
return stats;
}
void NetworkQualityMetricsReporter::ReportStats(
const std::string& network_label,
std::unique_ptr<EmulatedNetworkStats> stats,
int64_t packet_loss) {
if (metrics_logger_ == nullptr) {
ReportResult("bytes_sent", network_label, stats->BytesSent().bytes(),
"sizeInBytes");
ReportResult("packets_sent", network_label, stats->PacketsSent(),
"unitless");
ReportResult("average_send_rate", network_label,
stats->PacketsSent() >= 2
? stats->AverageSendRate().bytes_per_sec()
: 0,
"bytesPerSecond");
ReportResult("bytes_discarded_no_receiver", network_label,
stats->BytesDropped().bytes(), "sizeInBytes");
ReportResult("packets_discarded_no_receiver", network_label,
stats->PacketsDropped(), "unitless");
ReportResult("bytes_received", network_label,
stats->BytesReceived().bytes(), "sizeInBytes");
ReportResult("packets_received", network_label, stats->PacketsReceived(),
"unitless");
ReportResult("average_receive_rate", network_label,
stats->PacketsReceived() >= 2
? stats->AverageReceiveRate().bytes_per_sec()
: 0,
"bytesPerSecond");
ReportResult("sent_packets_loss", network_label, packet_loss, "unitless");
} else {
metrics_logger_->LogSingleValueMetric(
"bytes_sent", GetTestCaseName(network_label),
stats->BytesSent().bytes(), Unit::kBytes,
ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"packets_sent", GetTestCaseName(network_label), stats->PacketsSent(),
Unit::kUnitless, ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"average_send_rate", GetTestCaseName(network_label),
stats->PacketsSent() >= 2 ? stats->AverageSendRate().kbps() : 0,
Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"bytes_discarded_no_receiver", GetTestCaseName(network_label),
stats->BytesDropped().bytes(), Unit::kBytes,
ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"packets_discarded_no_receiver", GetTestCaseName(network_label),
stats->PacketsDropped(), Unit::kUnitless,
ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"bytes_received", GetTestCaseName(network_label),
stats->BytesReceived().bytes(), Unit::kBytes,
ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"packets_received", GetTestCaseName(network_label),
stats->PacketsReceived(), Unit::kUnitless,
ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"average_receive_rate", GetTestCaseName(network_label),
stats->PacketsReceived() >= 2 ? stats->AverageReceiveRate().kbps() : 0,
Unit::kKilobitsPerSecond, ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"sent_packets_loss", GetTestCaseName(network_label), packet_loss,
Unit::kUnitless, ImprovementDirection::kNeitherIsBetter);
}
}
void NetworkQualityMetricsReporter::ReportPCStats(const std::string& pc_label,
const PCStats& stats) {
if (metrics_logger_ == nullptr) {
ReportResult("payload_bytes_received", pc_label,
stats.payload_received.bytes(), "sizeInBytes");
ReportResult("payload_bytes_sent", pc_label, stats.payload_sent.bytes(),
"sizeInBytes");
} else {
metrics_logger_->LogSingleValueMetric(
"payload_bytes_received", pc_label, stats.payload_received.bytes(),
Unit::kBytes, ImprovementDirection::kNeitherIsBetter);
metrics_logger_->LogSingleValueMetric(
"payload_bytes_sent", pc_label, stats.payload_sent.bytes(),
Unit::kBytes, ImprovementDirection::kNeitherIsBetter);
}
}
void NetworkQualityMetricsReporter::ReportResult(
const std::string& metric_name,
const std::string& network_label,
const double value,
const std::string& unit) const {
test::PrintResult(metric_name, /*modifier=*/"",
GetTestCaseName(network_label), value, unit,
/*important=*/false);
}
std::string NetworkQualityMetricsReporter::GetTestCaseName(
const std::string& network_label) const {
return test_case_name_ + "/" + network_label;
}
} // namespace webrtc_pc_e2e
} // namespace webrtc