dcsctp: Use TimeDelta in TX path
This commit replaces the internal use of DurationMs, with millisecond precision, to webrtc::TimeDelta, which uses microsecond precision. This is just a refactoring. The only change to the public API is convenience methods to convert between DurationMs and webrtc::TimeDelta. Bug: webrtc:15593 Change-Id: Ida861bf585c716be5f898d0e7ef98da2c15268b7 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/325402 Commit-Queue: Victor Boivie <boivie@webrtc.org> Reviewed-by: Florent Castelli <orphis@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41062}
This commit is contained in:
parent
8039cdbe48
commit
b78e6a9305
@ -11,6 +11,7 @@ import("../../../webrtc.gni")
|
||||
rtc_source_set("types") {
|
||||
deps = [
|
||||
"../../../api:array_view",
|
||||
"../../../api/units:time_delta",
|
||||
"../../../rtc_base:strong_alias",
|
||||
]
|
||||
sources = [
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/strong_alias.h"
|
||||
|
||||
namespace dcsctp {
|
||||
@ -41,6 +42,10 @@ class DurationMs : public webrtc::StrongAlias<class DurationMsTag, int32_t> {
|
||||
constexpr explicit DurationMs(const UnderlyingType& v)
|
||||
: webrtc::StrongAlias<class DurationMsTag, int32_t>(v) {}
|
||||
|
||||
constexpr explicit DurationMs(webrtc::TimeDelta v)
|
||||
: webrtc::StrongAlias<class DurationMsTag, int32_t>(
|
||||
v.IsInfinite() ? InfiniteDuration() : DurationMs(v.ms())) {}
|
||||
|
||||
static constexpr DurationMs InfiniteDuration() {
|
||||
return DurationMs(std::numeric_limits<int32_t>::max());
|
||||
}
|
||||
@ -58,6 +63,11 @@ class DurationMs : public webrtc::StrongAlias<class DurationMsTag, int32_t> {
|
||||
value_ *= factor;
|
||||
return *this;
|
||||
}
|
||||
constexpr webrtc::TimeDelta ToTimeDelta() const {
|
||||
return *this == DurationMs::InfiniteDuration()
|
||||
? webrtc::TimeDelta::PlusInfinity()
|
||||
: webrtc::TimeDelta::Millis(value_);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr inline DurationMs operator+(DurationMs lhs, DurationMs rhs) {
|
||||
|
||||
@ -39,8 +39,8 @@ class Context {
|
||||
// Returns the socket callbacks.
|
||||
virtual DcSctpSocketCallbacks& callbacks() const = 0;
|
||||
|
||||
// Observes a measured RTT value, in milliseconds.
|
||||
virtual void ObserveRTT(DurationMs rtt_ms) = 0;
|
||||
// Observes a measured RTT value.
|
||||
virtual void ObserveRTT(webrtc::TimeDelta rtt_ms) = 0;
|
||||
|
||||
// Returns the current Retransmission Timeout (rto) value, in milliseconds.
|
||||
virtual DurationMs current_rto() const = 0;
|
||||
|
||||
@ -155,7 +155,7 @@ void HeartbeatHandler::HandleHeartbeatAck(HeartbeatAckChunk chunk) {
|
||||
|
||||
TimeMs now = ctx_->callbacks().TimeMillis();
|
||||
if (info->created_at() > TimeMs(0) && info->created_at() <= now) {
|
||||
ctx_->ObserveRTT(now - info->created_at());
|
||||
ctx_->ObserveRTT((now - info->created_at()).ToTimeDelta());
|
||||
}
|
||||
|
||||
// https://tools.ietf.org/html/rfc4960#section-8.1
|
||||
|
||||
@ -30,6 +30,7 @@ using ::testing::IsEmpty;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
using ::testing::SizeIs;
|
||||
using ::webrtc::TimeDelta;
|
||||
|
||||
constexpr DurationMs kHeartbeatInterval = DurationMs(30'000);
|
||||
|
||||
@ -136,7 +137,7 @@ TEST_F(HeartbeatHandlerTest, SendsHeartbeatRequestsOnIdleChannel) {
|
||||
// Respond a while later. This RTT will be measured by the handler
|
||||
constexpr DurationMs rtt(313);
|
||||
|
||||
EXPECT_CALL(context_, ObserveRTT(rtt)).Times(1);
|
||||
EXPECT_CALL(context_, ObserveRTT(rtt.ToTimeDelta())).Times(1);
|
||||
|
||||
callbacks_.AdvanceTime(rtt);
|
||||
handler_.HandleHeartbeatAck(std::move(ack));
|
||||
|
||||
@ -51,7 +51,7 @@ class MockContext : public Context {
|
||||
MOCK_METHOD(TSN, peer_initial_tsn, (), (const, override));
|
||||
MOCK_METHOD(DcSctpSocketCallbacks&, callbacks, (), (const, override));
|
||||
|
||||
MOCK_METHOD(void, ObserveRTT, (DurationMs rtt_ms), (override));
|
||||
MOCK_METHOD(void, ObserveRTT, (webrtc::TimeDelta rtt), (override));
|
||||
MOCK_METHOD(DurationMs, current_rto, (), (const, override));
|
||||
MOCK_METHOD(bool,
|
||||
IncrementTxErrorCounter,
|
||||
|
||||
@ -48,6 +48,7 @@ using ::testing::Property;
|
||||
using ::testing::Return;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::webrtc::TimeDelta;
|
||||
using ResponseResult = ReconfigurationResponseParameter::Result;
|
||||
using SkippedStream = AnyForwardTsnChunk::SkippedStream;
|
||||
|
||||
@ -115,7 +116,7 @@ class StreamResetHandlerTest : public testing::Test {
|
||||
kMyInitialTsn,
|
||||
kArwnd,
|
||||
producer_,
|
||||
[](DurationMs rtt_ms) {},
|
||||
[](TimeDelta rtt) {},
|
||||
[]() {},
|
||||
*t3_rtx_timer_,
|
||||
DcSctpOptions())),
|
||||
@ -205,7 +206,7 @@ class StreamResetHandlerTest : public testing::Test {
|
||||
reasm_->RestoreFromState(state);
|
||||
retransmission_queue_ = std::make_unique<RetransmissionQueue>(
|
||||
"", &callbacks_, kMyInitialTsn, kArwnd, producer_,
|
||||
[](DurationMs rtt_ms) {}, []() {}, *t3_rtx_timer_, DcSctpOptions(),
|
||||
[](TimeDelta rtt) {}, []() {}, *t3_rtx_timer_, DcSctpOptions(),
|
||||
/*supports_partial_reliability=*/true,
|
||||
/*use_message_interleaving=*/false);
|
||||
retransmission_queue_->RestoreFromState(state);
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
#include "rtc_base/strings/string_builder.h"
|
||||
|
||||
namespace dcsctp {
|
||||
using ::webrtc::TimeDelta;
|
||||
|
||||
TransmissionControlBlock::TransmissionControlBlock(
|
||||
TimerManager& timer_manager,
|
||||
@ -112,10 +113,10 @@ TransmissionControlBlock::TransmissionControlBlock(
|
||||
send_queue.EnableMessageInterleaving(capabilities.message_interleaving);
|
||||
}
|
||||
|
||||
void TransmissionControlBlock::ObserveRTT(DurationMs rtt) {
|
||||
void TransmissionControlBlock::ObserveRTT(TimeDelta rtt) {
|
||||
DurationMs prev_rto = rto_.rto();
|
||||
rto_.ObserveRTT(rtt);
|
||||
RTC_DLOG(LS_VERBOSE) << log_prefix_ << "new rtt=" << *rtt
|
||||
rto_.ObserveRTT(DurationMs(rtt));
|
||||
RTC_DLOG(LS_VERBOSE) << log_prefix_ << "new rtt=" << webrtc::ToString(rtt)
|
||||
<< ", srtt=" << *rto_.srtt() << ", rto=" << *rto_.rto()
|
||||
<< " (" << *prev_rto << ")";
|
||||
t3_rtx_->set_duration(rto_.rto());
|
||||
|
||||
@ -67,7 +67,7 @@ class TransmissionControlBlock : public Context {
|
||||
TSN my_initial_tsn() const override { return my_initial_tsn_; }
|
||||
TSN peer_initial_tsn() const override { return peer_initial_tsn_; }
|
||||
DcSctpSocketCallbacks& callbacks() const override { return callbacks_; }
|
||||
void ObserveRTT(DurationMs rtt) override;
|
||||
void ObserveRTT(webrtc::TimeDelta rtt) override;
|
||||
DurationMs current_rto() const override { return rto_.rto(); }
|
||||
bool IncrementTxErrorCounter(absl::string_view reason) override {
|
||||
return tx_error_counter_.Increment(reason);
|
||||
|
||||
@ -103,6 +103,7 @@ rtc_library("outstanding_data") {
|
||||
":retransmission_timeout",
|
||||
":send_queue",
|
||||
"../../../api:array_view",
|
||||
"../../../api/units:time_delta",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:logging",
|
||||
"../../../rtc_base/containers:flat_set",
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "net/dcsctp/common/math.h"
|
||||
#include "net/dcsctp/common/sequence_numbers.h"
|
||||
#include "net/dcsctp/public/types.h"
|
||||
@ -441,8 +442,8 @@ void OutstandingData::NackAll() {
|
||||
RTC_DCHECK(IsConsistent());
|
||||
}
|
||||
|
||||
absl::optional<DurationMs> OutstandingData::MeasureRTT(TimeMs now,
|
||||
UnwrappedTSN tsn) const {
|
||||
webrtc::TimeDelta OutstandingData::MeasureRTT(TimeMs now,
|
||||
UnwrappedTSN tsn) const {
|
||||
auto it = outstanding_data_.find(tsn);
|
||||
if (it != outstanding_data_.end() && !it->second.has_been_retransmitted()) {
|
||||
// https://tools.ietf.org/html/rfc4960#section-6.3.1
|
||||
@ -450,9 +451,9 @@ absl::optional<DurationMs> OutstandingData::MeasureRTT(TimeMs now,
|
||||
// packets that were retransmitted (and thus for which it is ambiguous
|
||||
// whether the reply was for the first instance of the chunk or for a
|
||||
// later instance)"
|
||||
return now - it->second.time_sent();
|
||||
return (now - it->second.time_sent()).ToTimeDelta();
|
||||
}
|
||||
return absl::nullopt;
|
||||
return webrtc::TimeDelta::PlusInfinity();
|
||||
}
|
||||
|
||||
std::vector<std::pair<TSN, OutstandingData::State>>
|
||||
|
||||
@ -147,8 +147,8 @@ class OutstandingData {
|
||||
|
||||
// Given the current time and a TSN, it returns the measured RTT between when
|
||||
// the chunk was sent and now. It takes into acccount Karn's algorithm, so if
|
||||
// the chunk has ever been retransmitted, it will return absl::nullopt.
|
||||
absl::optional<DurationMs> MeasureRTT(TimeMs now, UnwrappedTSN tsn) const;
|
||||
// the chunk has ever been retransmitted, it will return `PlusInfinity()`.
|
||||
webrtc::TimeDelta MeasureRTT(TimeMs now, UnwrappedTSN tsn) const;
|
||||
|
||||
// Returns the internal state of all queued chunks. This is only used in
|
||||
// unit-tests.
|
||||
|
||||
@ -37,6 +37,7 @@ using ::testing::Property;
|
||||
using ::testing::Return;
|
||||
using ::testing::StrictMock;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::webrtc::TimeDelta;
|
||||
|
||||
constexpr TimeMs kNow(42);
|
||||
constexpr OutgoingMessageId kMessageId = OutgoingMessageId(17);
|
||||
@ -365,12 +366,11 @@ TEST_F(OutstandingDataTest, MeasureRTT) {
|
||||
buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow + DurationMs(1));
|
||||
buf_.Insert(kMessageId, gen_.Ordered({1}, "BE"), kNow + DurationMs(2));
|
||||
|
||||
static constexpr DurationMs kDuration(123);
|
||||
ASSERT_HAS_VALUE_AND_ASSIGN(
|
||||
DurationMs duration,
|
||||
buf_.MeasureRTT(kNow + kDuration, unwrapper_.Unwrap(TSN(11))));
|
||||
static constexpr TimeDelta kDuration = TimeDelta::Millis(123);
|
||||
TimeDelta duration =
|
||||
buf_.MeasureRTT(kNow + DurationMs(kDuration), unwrapper_.Unwrap(TSN(11)));
|
||||
|
||||
EXPECT_EQ(duration, kDuration - DurationMs(1));
|
||||
EXPECT_EQ(duration, kDuration - TimeDelta::Millis(1));
|
||||
}
|
||||
|
||||
TEST_F(OutstandingDataTest, MustRetransmitBeforeGettingNackedAgain) {
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
|
||||
namespace dcsctp {
|
||||
namespace {
|
||||
using ::webrtc::TimeDelta;
|
||||
|
||||
// Allow sending only slightly less than an MTU, to account for headers.
|
||||
constexpr float kMinBytesRequiredToSendFactor = 0.9;
|
||||
@ -55,7 +56,7 @@ RetransmissionQueue::RetransmissionQueue(
|
||||
TSN my_initial_tsn,
|
||||
size_t a_rwnd,
|
||||
SendQueue& send_queue,
|
||||
std::function<void(DurationMs rtt)> on_new_rtt,
|
||||
std::function<void(TimeDelta rtt)> on_new_rtt,
|
||||
std::function<void()> on_clear_retransmission_counter,
|
||||
Timer& t3_rtx,
|
||||
const DcSctpOptions& options,
|
||||
@ -345,11 +346,10 @@ void RetransmissionQueue::UpdateRTT(TimeMs now,
|
||||
// TODO(boivie): Consider occasionally sending DATA chunks with I-bit set and
|
||||
// use only those packets for measurement.
|
||||
|
||||
absl::optional<DurationMs> rtt =
|
||||
outstanding_data_.MeasureRTT(now, cumulative_tsn_ack);
|
||||
TimeDelta rtt = outstanding_data_.MeasureRTT(now, cumulative_tsn_ack);
|
||||
|
||||
if (rtt.has_value()) {
|
||||
on_new_rtt_(*rtt);
|
||||
if (rtt.IsFinite()) {
|
||||
on_new_rtt_(rtt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ class RetransmissionQueue {
|
||||
TSN my_initial_tsn,
|
||||
size_t a_rwnd,
|
||||
SendQueue& send_queue,
|
||||
std::function<void(DurationMs rtt)> on_new_rtt,
|
||||
std::function<void(webrtc::TimeDelta rtt)> on_new_rtt,
|
||||
std::function<void()> on_clear_retransmission_counter,
|
||||
Timer& t3_rtx,
|
||||
const DcSctpOptions& options,
|
||||
@ -230,7 +230,7 @@ class RetransmissionQueue {
|
||||
// The size of the data chunk (DATA/I-DATA) header that is used.
|
||||
const size_t data_chunk_header_size_;
|
||||
// Called when a new RTT measurement has been done
|
||||
const std::function<void(DurationMs rtt)> on_new_rtt_;
|
||||
const std::function<void(webrtc::TimeDelta rtt)> on_new_rtt_;
|
||||
// Called when a SACK has been seen that cleared the retransmission counter.
|
||||
const std::function<void()> on_clear_retransmission_counter_;
|
||||
// The retransmission counter.
|
||||
|
||||
@ -52,6 +52,7 @@ using ::testing::Pair;
|
||||
using ::testing::Return;
|
||||
using ::testing::SizeIs;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::webrtc::TimeDelta;
|
||||
|
||||
constexpr uint32_t kArwnd = 100000;
|
||||
constexpr uint32_t kMaxMtu = 1191;
|
||||
@ -130,7 +131,7 @@ class RetransmissionQueueTest : public testing::Test {
|
||||
TimeMs now_ = TimeMs(0);
|
||||
FakeTimeoutManager timeout_manager_;
|
||||
TimerManager timer_manager_;
|
||||
NiceMock<MockFunction<void(DurationMs rtt_ms)>> on_rtt_;
|
||||
NiceMock<MockFunction<void(TimeDelta rtt_ms)>> on_rtt_;
|
||||
NiceMock<MockFunction<void()>> on_clear_retransmission_counter_;
|
||||
NiceMock<MockSendQueue> producer_;
|
||||
std::unique_ptr<Timer> timer_;
|
||||
@ -864,7 +865,7 @@ TEST_F(RetransmissionQueueTest, MeasureRTT) {
|
||||
|
||||
now_ = now_ + DurationMs(123);
|
||||
|
||||
EXPECT_CALL(on_rtt_, Call(DurationMs(123))).Times(1);
|
||||
EXPECT_CALL(on_rtt_, Call(TimeDelta::Millis(123))).Times(1);
|
||||
queue.HandleSack(now_, SackChunk(TSN(10), kArwnd, {}, {}));
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user