Add simulation of robust throughput estimator to the event log analyzer
Bug: webrtc:11566 Change-Id: I873d1c1bd6682a973b3a130289390e09ef47cc37 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/177017 Commit-Queue: Björn Terelius <terelius@webrtc.org> Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31538}
This commit is contained in:

committed by
Commit Bot

parent
a46fce2194
commit
ae1892d4e4
@ -370,6 +370,7 @@ if (!build_with_chromium) {
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base:rtc_numerics",
|
||||
"../rtc_base:stringutils",
|
||||
"../test:explicit_key_value_config",
|
||||
]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/algorithm:container",
|
||||
|
@ -56,10 +56,7 @@
|
||||
#include "rtc_base/rate_statistics.h"
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
#include "rtc_tools/rtc_event_log_visualizer/log_simulation.h"
|
||||
|
||||
#ifndef BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
|
||||
#define BWE_TEST_LOGGING_COMPILE_TIME_ENABLE 0
|
||||
#endif // BWE_TEST_LOGGING_COMPILE_TIME_ENABLE
|
||||
#include "test/explicit_key_value_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -1212,10 +1209,13 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
|
||||
TimeSeries time_series("Delay-based estimate", LineStyle::kStep,
|
||||
PointStyle::kHighlight);
|
||||
TimeSeries acked_time_series("Acked bitrate", LineStyle::kLine,
|
||||
TimeSeries acked_time_series("Raw acked bitrate", LineStyle::kLine,
|
||||
PointStyle::kHighlight);
|
||||
TimeSeries robust_time_series("Robust throughput estimate", LineStyle::kLine,
|
||||
PointStyle::kHighlight);
|
||||
TimeSeries acked_estimate_time_series("Ackednowledged bitrate estimate",
|
||||
LineStyle::kLine,
|
||||
PointStyle::kHighlight);
|
||||
TimeSeries acked_estimate_time_series(
|
||||
"Acked bitrate estimate", LineStyle::kLine, PointStyle::kHighlight);
|
||||
|
||||
auto rtp_iterator = outgoing_rtp.begin();
|
||||
auto rtcp_iterator = incoming_rtcp.begin();
|
||||
@ -1241,20 +1241,18 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
return std::numeric_limits<int64_t>::max();
|
||||
};
|
||||
|
||||
RateStatistics acked_bitrate(250, 8000);
|
||||
#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
FieldTrialBasedConfig field_trial_config_;
|
||||
// The event_log_visualizer should normally not be compiled with
|
||||
// BWE_TEST_LOGGING_COMPILE_TIME_ENABLE since the normal plots won't work.
|
||||
// However, compiling with BWE_TEST_LOGGING, running with --plot=sendside_bwe
|
||||
// and piping the output to plot_dynamics.py can be used as a hack to get the
|
||||
// internal state of various BWE components. In this case, it is important
|
||||
// we don't instantiate the AcknowledgedBitrateEstimator both here and in
|
||||
// GoogCcNetworkController since that would lead to duplicate outputs.
|
||||
RateStatistics acked_bitrate(750, 8000);
|
||||
test::ExplicitKeyValueConfig throughput_config(
|
||||
"WebRTC-Bwe-RobustThroughputEstimatorSettings/"
|
||||
"enabled:true,reduce_bias:true,assume_shared_link:false,initial_packets:"
|
||||
"10,min_packets:25,window_duration:750ms,unacked_weight:0.5/");
|
||||
std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
|
||||
robust_throughput_estimator(
|
||||
AcknowledgedBitrateEstimatorInterface::Create(&throughput_config));
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
|
||||
acknowledged_bitrate_estimator(
|
||||
AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_));
|
||||
#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config));
|
||||
int64_t time_us =
|
||||
std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()});
|
||||
int64_t last_update_us = 0;
|
||||
@ -1264,24 +1262,40 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
RTC_DCHECK_EQ(clock.TimeInMicroseconds(), NextRtpTime());
|
||||
const RtpPacketType& rtp_packet = *rtp_iterator->second;
|
||||
if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) {
|
||||
RTC_DCHECK(rtp_packet.rtp.header.extension.hasTransportSequenceNumber);
|
||||
RtpPacketSendInfo packet_info;
|
||||
packet_info.ssrc = rtp_packet.rtp.header.ssrc;
|
||||
packet_info.transport_sequence_number =
|
||||
rtp_packet.rtp.header.extension.transportSequenceNumber;
|
||||
packet_info.rtp_sequence_number = rtp_packet.rtp.header.sequenceNumber;
|
||||
packet_info.length = rtp_packet.rtp.total_length;
|
||||
if (IsRtxSsrc(parsed_log_, PacketDirection::kOutgoingPacket,
|
||||
rtp_packet.rtp.header.ssrc)) {
|
||||
// Don't set the optional media type as we don't know if it is
|
||||
// a retransmission, FEC or padding.
|
||||
} else if (IsVideoSsrc(parsed_log_, PacketDirection::kOutgoingPacket,
|
||||
rtp_packet.rtp.header.ssrc)) {
|
||||
packet_info.packet_type = RtpPacketMediaType::kVideo;
|
||||
} else if (IsAudioSsrc(parsed_log_, PacketDirection::kOutgoingPacket,
|
||||
rtp_packet.rtp.header.ssrc)) {
|
||||
packet_info.packet_type = RtpPacketMediaType::kAudio;
|
||||
}
|
||||
transport_feedback.AddPacket(
|
||||
packet_info,
|
||||
0u, // Per packet overhead bytes.
|
||||
Timestamp::Micros(rtp_packet.rtp.log_time_us()));
|
||||
rtc::SentPacket sent_packet(
|
||||
rtp_packet.rtp.header.extension.transportSequenceNumber,
|
||||
rtp_packet.rtp.log_time_us() / 1000);
|
||||
}
|
||||
rtc::SentPacket sent_packet;
|
||||
sent_packet.send_time_ms = rtp_packet.rtp.log_time_ms();
|
||||
sent_packet.info.included_in_allocation = true;
|
||||
sent_packet.info.packet_size_bytes = rtp_packet.rtp.total_length;
|
||||
if (rtp_packet.rtp.header.extension.hasTransportSequenceNumber) {
|
||||
sent_packet.packet_id =
|
||||
rtp_packet.rtp.header.extension.transportSequenceNumber;
|
||||
sent_packet.info.included_in_feedback = true;
|
||||
}
|
||||
auto sent_msg = transport_feedback.ProcessSentPacket(sent_packet);
|
||||
if (sent_msg)
|
||||
observer.Update(goog_cc->OnSentPacket(*sent_msg));
|
||||
}
|
||||
++rtp_iterator;
|
||||
}
|
||||
if (clock.TimeInMicroseconds() >= NextRtcpTime()) {
|
||||
@ -1296,13 +1310,13 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
std::vector<PacketResult> feedback =
|
||||
feedback_msg->SortedByReceiveTime();
|
||||
if (!feedback.empty()) {
|
||||
#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
acknowledged_bitrate_estimator->IncomingPacketFeedbackVector(
|
||||
feedback);
|
||||
#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
for (const PacketResult& packet : feedback)
|
||||
robust_throughput_estimator->IncomingPacketFeedbackVector(feedback);
|
||||
for (const PacketResult& packet : feedback) {
|
||||
acked_bitrate.Update(packet.sent_packet.size.bytes(),
|
||||
packet.receive_time.ms());
|
||||
}
|
||||
bitrate_bps = acked_bitrate.Rate(feedback.back().receive_time.ms());
|
||||
}
|
||||
}
|
||||
@ -1310,12 +1324,14 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
float x = config_.GetCallTimeSec(clock.TimeInMicroseconds());
|
||||
float y = bitrate_bps.value_or(0) / 1000;
|
||||
acked_time_series.points.emplace_back(x, y);
|
||||
#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
y = robust_throughput_estimator->bitrate()
|
||||
.value_or(DataRate::Zero())
|
||||
.kbps();
|
||||
robust_time_series.points.emplace_back(x, y);
|
||||
y = acknowledged_bitrate_estimator->bitrate()
|
||||
.value_or(DataRate::Zero())
|
||||
.kbps();
|
||||
acked_estimate_time_series.points.emplace_back(x, y);
|
||||
#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
++rtcp_iterator;
|
||||
}
|
||||
if (clock.TimeInMicroseconds() >= NextProcessTime()) {
|
||||
@ -1336,6 +1352,7 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
}
|
||||
// Add the data set to the plot.
|
||||
plot->AppendTimeSeries(std::move(time_series));
|
||||
plot->AppendTimeSeries(std::move(robust_time_series));
|
||||
plot->AppendTimeSeries(std::move(acked_time_series));
|
||||
plot->AppendTimeSeriesIfNotEmpty(std::move(acked_estimate_time_series));
|
||||
|
||||
|
@ -216,6 +216,20 @@ rtc_library("field_trial") {
|
||||
deps = [ "../system_wrappers:field_trial" ]
|
||||
}
|
||||
|
||||
rtc_library("explicit_key_value_config") {
|
||||
sources = [
|
||||
"explicit_key_value_config.cc",
|
||||
"explicit_key_value_config.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../api/transport:webrtc_key_value_config",
|
||||
"../rtc_base:checks",
|
||||
"../system_wrappers:field_trial",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/strings:strings" ]
|
||||
}
|
||||
|
||||
rtc_library("perf_test") {
|
||||
visibility = [ "*" ]
|
||||
testonly = true
|
||||
|
57
test/explicit_key_value_config.cc
Normal file
57
test/explicit_key_value_config.cc
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 "test/explicit_key_value_config.h"
|
||||
|
||||
#include "api/transport/webrtc_key_value_config.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
ExplicitKeyValueConfig::ExplicitKeyValueConfig(const std::string& s) {
|
||||
std::string::size_type field_start = 0;
|
||||
while (field_start < s.size()) {
|
||||
std::string::size_type separator_pos = s.find('/', field_start);
|
||||
RTC_CHECK_NE(separator_pos, std::string::npos)
|
||||
<< "Missing separator '/' after field trial key.";
|
||||
RTC_CHECK_GT(separator_pos, field_start)
|
||||
<< "Field trial key cannot be empty.";
|
||||
std::string key = s.substr(field_start, separator_pos - field_start);
|
||||
field_start = separator_pos + 1;
|
||||
|
||||
RTC_CHECK_LT(field_start, s.size())
|
||||
<< "Missing value after field trial key. String ended.";
|
||||
separator_pos = s.find('/', field_start);
|
||||
RTC_CHECK_NE(separator_pos, std::string::npos)
|
||||
<< "Missing terminating '/' in field trial string.";
|
||||
RTC_CHECK_GT(separator_pos, field_start)
|
||||
<< "Field trial value cannot be empty.";
|
||||
std::string value = s.substr(field_start, separator_pos - field_start);
|
||||
field_start = separator_pos + 1;
|
||||
|
||||
key_value_map_[key] = value;
|
||||
}
|
||||
// This check is technically redundant due to earlier checks.
|
||||
// We nevertheless keep the check to make it clear that the entire
|
||||
// string has been processed, and without indexing past the end.
|
||||
RTC_CHECK_EQ(field_start, s.size());
|
||||
}
|
||||
|
||||
std::string ExplicitKeyValueConfig::Lookup(absl::string_view key) const {
|
||||
auto it = key_value_map_.find(std::string(key));
|
||||
if (it != key_value_map_.end())
|
||||
return it->second;
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
35
test/explicit_key_value_config.h
Normal file
35
test/explicit_key_value_config.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TEST_EXPLICIT_KEY_VALUE_CONFIG_H_
|
||||
#define TEST_EXPLICIT_KEY_VALUE_CONFIG_H_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/transport/webrtc_key_value_config.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
class ExplicitKeyValueConfig : public WebRtcKeyValueConfig {
|
||||
public:
|
||||
explicit ExplicitKeyValueConfig(const std::string& s);
|
||||
std::string Lookup(absl::string_view key) const override;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> key_value_map_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // TEST_EXPLICIT_KEY_VALUE_CONFIG_H_
|
Reference in New Issue
Block a user