From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../rtc_base/frequency_tracker_unittest.cc | 203 +++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc (limited to 'third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc') diff --git a/third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc b/third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc new file mode 100644 index 0000000000..00788c3ee8 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/frequency_tracker_unittest.cc @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2023 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 "rtc_base/frequency_tracker.h" + +#include +#include + +#include "absl/types/optional.h" +#include "api/units/frequency.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::AllOf; +using ::testing::Gt; +using ::testing::Lt; + +constexpr TimeDelta kWindow = TimeDelta::Millis(500); +constexpr TimeDelta kEpsilon = TimeDelta::Millis(1); + +TEST(FrequencyTrackerTest, ReturnsNulloptInitially) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(FrequencyTrackerTest, ReturnsNulloptAfterSingleDataPoint) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + stats.Update(now); + now += TimeDelta::Millis(10); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +TEST(FrequencyTrackerTest, ReturnsRateAfterTwoMeasurements) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + stats.Update(now); + now += TimeDelta::Millis(1); + stats.Update(now); + + // 1 event per 1 ms ~= 1'000 events per second. + EXPECT_EQ(stats.Rate(now), Frequency::Hertz(1'000)); +} + +TEST(FrequencyTrackerTest, MeasuresConstantRate) { + const Timestamp start = Timestamp::Seconds(12'345); + const TimeDelta kInterval = TimeDelta::Millis(10); + const Frequency kConstantRate = 1 / kInterval; + + Timestamp now = start; + FrequencyTracker stats(kWindow); + + stats.Update(now); + Frequency last_error = Frequency::PlusInfinity(); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + SCOPED_TRACE(i); + now += kInterval; + stats.Update(now); + + // Until window is full, rate is measured over a smaller window and might + // look larger than the constant rate. + absl::optional rate = stats.Rate(now); + ASSERT_GE(rate, kConstantRate); + + // Expect the estimation error to decrease as the window is extended. + Frequency error = *rate - kConstantRate; + EXPECT_LE(error, last_error); + last_error = error; + } + + // Once window is full, rate measurment should be stable. + for (TimeDelta i = TimeDelta::Zero(); i < kInterval; + i += TimeDelta::Millis(1)) { + SCOPED_TRACE(i); + EXPECT_EQ(stats.Rate(now + i), kConstantRate); + } +} + +TEST(FrequencyTrackerTest, CanMeasureFractionalRate) { + const TimeDelta kInterval = TimeDelta::Millis(134); + Timestamp now = Timestamp::Seconds(12'345); + // FrequencyTracker counts number of events in the window, thus when window is + // fraction of 1 second, number of events per second would always be integer. + const TimeDelta window = TimeDelta::Seconds(2); + + FrequencyTracker framerate(window); + framerate.Update(now); + for (TimeDelta i = TimeDelta::Zero(); i < window; i += kInterval) { + now += kInterval; + framerate.Update(now); + } + + // Should be aproximitly 7.5 fps + EXPECT_THAT(framerate.Rate(now), + AllOf(Gt(Frequency::Hertz(7)), Lt(Frequency::Hertz(8)))); +} + +TEST(FrequencyTrackerTest, IncreasingThenDecreasingRate) { + const int64_t kLargeSize = 1'500; + const int64_t kSmallSize = 300; + const TimeDelta kLargeInterval = TimeDelta::Millis(10); + const TimeDelta kSmallInterval = TimeDelta::Millis(2); + + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + stats.Update(kLargeSize, now); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) { + SCOPED_TRACE(i); + now += kLargeInterval; + stats.Update(kLargeSize, now); + } + absl::optional last_rate = stats.Rate(now); + EXPECT_EQ(last_rate, kLargeSize / kLargeInterval); + + // Decrease rate with smaller measurments. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) { + SCOPED_TRACE(i); + now += kLargeInterval; + stats.Update(kSmallSize, now); + + absl::optional rate = stats.Rate(now); + EXPECT_LT(rate, last_rate); + + last_rate = rate; + } + EXPECT_EQ(last_rate, kSmallSize / kLargeInterval); + + // Increase rate with more frequent measurments. + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kSmallInterval) { + SCOPED_TRACE(i); + now += kSmallInterval; + stats.Update(kSmallSize, now); + + absl::optional rate = stats.Rate(now); + EXPECT_GE(rate, last_rate); + + last_rate = rate; + } + EXPECT_EQ(last_rate, kSmallSize / kSmallInterval); +} + +TEST(FrequencyTrackerTest, ResetAfterSilence) { + const TimeDelta kInterval = TimeDelta::Millis(10); + const int64_t kPixels = 640 * 360; + + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker pixel_rate(kWindow); + + // Feed data until window has been filled. + pixel_rate.Update(kPixels, now); + for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) { + now += kInterval; + pixel_rate.Update(kPixels, now); + } + ASSERT_GT(pixel_rate.Rate(now), Frequency::Zero()); + + now += kWindow + kEpsilon; + // Silence over window size should trigger auto reset for coming sample. + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); + pixel_rate.Update(kPixels, now); + // Single measurment after reset is not enough to estimate the rate. + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); + + // Manual reset, add the same check again. + pixel_rate.Reset(); + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); + now += kInterval; + pixel_rate.Update(kPixels, now); + EXPECT_EQ(pixel_rate.Rate(now), absl::nullopt); +} + +TEST(FrequencyTrackerTest, ReturnsNulloptWhenOverflows) { + Timestamp now = Timestamp::Seconds(12'345); + FrequencyTracker stats(kWindow); + + int64_t very_large_number = std::numeric_limits::max(); + stats.Update(very_large_number, now); + now += kEpsilon; + stats.Update(very_large_number, now); + + EXPECT_EQ(stats.Rate(now), absl::nullopt); +} + +} // namespace +} // namespace webrtc -- cgit v1.2.3