Move HistogramPercentileCounter to rtc_base from RecieveStatisticProxy.
This should be a separate utility class, rather than internal thing in ReceiveStatisticsProxy. Bug: webrtc:8347 Change-Id: I9c8238e625999dba5776d6038c819732d07e9656 Reviewed-on: https://webrtc-review.googlesource.com/7609 Commit-Queue: Ilya Nikolaevskiy <ilnik@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#20267}
This commit is contained in:
parent
86f25d3bcd
commit
ed23be91b8
@ -137,6 +137,8 @@ rtc_source_set("rtc_base_approved_generic") {
|
|||||||
"flags.h",
|
"flags.h",
|
||||||
"format_macros.h",
|
"format_macros.h",
|
||||||
"function_view.h",
|
"function_view.h",
|
||||||
|
"histogram_percentile_counter.cc",
|
||||||
|
"histogram_percentile_counter.h",
|
||||||
"ignore_wundef.h",
|
"ignore_wundef.h",
|
||||||
"location.cc",
|
"location.cc",
|
||||||
"location.h",
|
"location.h",
|
||||||
@ -895,6 +897,7 @@ if (rtc_include_tests) {
|
|||||||
"event_unittest.cc",
|
"event_unittest.cc",
|
||||||
"file_unittest.cc",
|
"file_unittest.cc",
|
||||||
"function_view_unittest.cc",
|
"function_view_unittest.cc",
|
||||||
|
"histogram_percentile_counter_unittest.cc",
|
||||||
"logging_unittest.cc",
|
"logging_unittest.cc",
|
||||||
"md5digest_unittest.cc",
|
"md5digest_unittest.cc",
|
||||||
"mod_ops_unittest.cc",
|
"mod_ops_unittest.cc",
|
||||||
|
|||||||
79
rtc_base/histogram_percentile_counter.cc
Normal file
79
rtc_base/histogram_percentile_counter.cc
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 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/histogram_percentile_counter.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "rtc_base/checks.h"
|
||||||
|
|
||||||
|
namespace rtc {
|
||||||
|
HistogramPercentileCounter::HistogramPercentileCounter(
|
||||||
|
uint32_t long_tail_boundary)
|
||||||
|
: histogram_low_(size_t{long_tail_boundary}),
|
||||||
|
long_tail_boundary_(long_tail_boundary),
|
||||||
|
total_elements_(0),
|
||||||
|
total_elements_low_(0) {}
|
||||||
|
|
||||||
|
HistogramPercentileCounter::~HistogramPercentileCounter() = default;
|
||||||
|
|
||||||
|
void HistogramPercentileCounter::Add(const HistogramPercentileCounter& other) {
|
||||||
|
for (uint32_t value = 0; value < other.long_tail_boundary_; ++value) {
|
||||||
|
Add(value, other.histogram_low_[value]);
|
||||||
|
}
|
||||||
|
for (const auto& it : histogram_high_) {
|
||||||
|
Add(it.first, it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistogramPercentileCounter::Add(uint32_t value, size_t count) {
|
||||||
|
if (value < long_tail_boundary_) {
|
||||||
|
histogram_low_[value] += count;
|
||||||
|
total_elements_low_ += count;
|
||||||
|
} else {
|
||||||
|
histogram_high_[value] += count;
|
||||||
|
}
|
||||||
|
total_elements_ += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistogramPercentileCounter::Add(uint32_t value) {
|
||||||
|
Add(value, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::Optional<uint32_t> HistogramPercentileCounter::GetPercentile(
|
||||||
|
float fraction) {
|
||||||
|
RTC_CHECK_LE(fraction, 1.0);
|
||||||
|
RTC_CHECK_GE(fraction, 0.0);
|
||||||
|
if (total_elements_ == 0)
|
||||||
|
return rtc::Optional<uint32_t>();
|
||||||
|
size_t elements_to_skip = static_cast<size_t>(
|
||||||
|
std::max(0.0f, std::ceil(total_elements_ * fraction) - 1));
|
||||||
|
if (elements_to_skip >= total_elements_)
|
||||||
|
elements_to_skip = total_elements_ - 1;
|
||||||
|
if (elements_to_skip < total_elements_low_) {
|
||||||
|
for (uint32_t value = 0; value < long_tail_boundary_; ++value) {
|
||||||
|
if (elements_to_skip < histogram_low_[value])
|
||||||
|
return rtc::Optional<uint32_t>(value);
|
||||||
|
elements_to_skip -= histogram_low_[value];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
elements_to_skip -= total_elements_low_;
|
||||||
|
for (const auto& it : histogram_high_) {
|
||||||
|
if (elements_to_skip < it.second)
|
||||||
|
return rtc::Optional<uint32_t>(it.first);
|
||||||
|
elements_to_skip -= it.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RTC_NOTREACHED();
|
||||||
|
return rtc::Optional<uint32_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rtc
|
||||||
43
rtc_base/histogram_percentile_counter.h
Normal file
43
rtc_base/histogram_percentile_counter.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 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 RTC_BASE_HISTOGRAM_PERCENTILE_COUNTER_H_
|
||||||
|
#define RTC_BASE_HISTOGRAM_PERCENTILE_COUNTER_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "api/optional.h"
|
||||||
|
|
||||||
|
namespace rtc {
|
||||||
|
// Calculates percentiles on the stream of data. Use |Add| methods to add new
|
||||||
|
// values. Use |GetPercentile| to get percentile of the currently added values.
|
||||||
|
class HistogramPercentileCounter {
|
||||||
|
public:
|
||||||
|
// Values below |long_tail_boundary| are stored as the histogram in an array.
|
||||||
|
// Values above - in a map.
|
||||||
|
explicit HistogramPercentileCounter(uint32_t long_tail_boundary);
|
||||||
|
~HistogramPercentileCounter();
|
||||||
|
void Add(uint32_t value);
|
||||||
|
void Add(uint32_t value, size_t count);
|
||||||
|
void Add(const HistogramPercentileCounter& other);
|
||||||
|
// Argument should be from 0 to 1.
|
||||||
|
rtc::Optional<uint32_t> GetPercentile(float fraction);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<size_t> histogram_low_;
|
||||||
|
std::map<uint32_t, size_t> histogram_high_;
|
||||||
|
const uint32_t long_tail_boundary_;
|
||||||
|
size_t total_elements_;
|
||||||
|
size_t total_elements_low_;
|
||||||
|
};
|
||||||
|
} // namespace rtc
|
||||||
|
#endif // RTC_BASE_HISTOGRAM_PERCENTILE_COUNTER_H_
|
||||||
43
rtc_base/histogram_percentile_counter_unittest.cc
Normal file
43
rtc_base/histogram_percentile_counter_unittest.cc
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 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/histogram_percentile_counter.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "test/gtest.h"
|
||||||
|
|
||||||
|
TEST(HistogramPercentileCounterTest, ReturnsCorrectPercentiles) {
|
||||||
|
rtc::HistogramPercentileCounter counter(10);
|
||||||
|
const std::vector<int> kTestValues = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||||
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
||||||
|
|
||||||
|
EXPECT_FALSE(counter.GetPercentile(0.5f));
|
||||||
|
// Pairs of {fraction, percentile value} computed by hand
|
||||||
|
// for |kTestValues|.
|
||||||
|
const std::vector<std::pair<float, uint32_t>> kTestPercentiles = {
|
||||||
|
{0.0f, 1}, {0.01f, 1}, {0.5f, 10}, {0.9f, 18},
|
||||||
|
{0.95f, 19}, {0.99f, 20}, {1.0f, 20}};
|
||||||
|
for (int value : kTestValues) {
|
||||||
|
counter.Add(value);
|
||||||
|
}
|
||||||
|
for (const auto& test_percentile : kTestPercentiles) {
|
||||||
|
EXPECT_EQ(test_percentile.second,
|
||||||
|
counter.GetPercentile(test_percentile.first).value_or(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(HistogramPercentileCounterTest, HandlesEmptySequence) {
|
||||||
|
rtc::HistogramPercentileCounter counter(10);
|
||||||
|
EXPECT_FALSE(counter.GetPercentile(0.5f));
|
||||||
|
counter.Add(1u);
|
||||||
|
EXPECT_TRUE(counter.GetPercentile(0.5f));
|
||||||
|
}
|
||||||
@ -821,69 +821,4 @@ void ReceiveStatisticsProxy::ContentSpecificStats::Add(
|
|||||||
frame_counts.delta_frames += other.frame_counts.delta_frames;
|
frame_counts.delta_frames += other.frame_counts.delta_frames;
|
||||||
interframe_delay_percentiles.Add(other.interframe_delay_percentiles);
|
interframe_delay_percentiles.Add(other.interframe_delay_percentiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReceiveStatisticsProxy::HistogramPercentileCounter::HistogramPercentileCounter(
|
|
||||||
size_t long_tail_boundary)
|
|
||||||
: histogram_low_(long_tail_boundary),
|
|
||||||
long_tail_boundary_(long_tail_boundary),
|
|
||||||
total_elements_(0),
|
|
||||||
total_elements_low_(0) {}
|
|
||||||
|
|
||||||
void ReceiveStatisticsProxy::HistogramPercentileCounter::Add(
|
|
||||||
const HistogramPercentileCounter& other) {
|
|
||||||
uint32_t value;
|
|
||||||
for (value = 0; value < other.long_tail_boundary_; ++value) {
|
|
||||||
Add(value, other.histogram_low_[value]);
|
|
||||||
}
|
|
||||||
for (auto it = other.histogram_high_.begin();
|
|
||||||
it != other.histogram_high_.end(); ++it) {
|
|
||||||
Add(it->first, it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveStatisticsProxy::HistogramPercentileCounter::Add(uint32_t value,
|
|
||||||
size_t count) {
|
|
||||||
if (value < long_tail_boundary_) {
|
|
||||||
histogram_low_[value] += count;
|
|
||||||
total_elements_low_ += count;
|
|
||||||
} else {
|
|
||||||
histogram_high_[value] += count;
|
|
||||||
}
|
|
||||||
total_elements_ += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReceiveStatisticsProxy::HistogramPercentileCounter::Add(uint32_t value) {
|
|
||||||
Add(value, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
rtc::Optional<uint32_t>
|
|
||||||
ReceiveStatisticsProxy::HistogramPercentileCounter::GetPercentile(
|
|
||||||
float fraction) {
|
|
||||||
RTC_CHECK_LE(fraction, 1);
|
|
||||||
RTC_CHECK_GE(fraction, 0);
|
|
||||||
if (total_elements_ == 0)
|
|
||||||
return rtc::Optional<uint32_t>();
|
|
||||||
int elements_to_skip =
|
|
||||||
static_cast<int>(std::ceil(total_elements_ * fraction)) - 1;
|
|
||||||
if (elements_to_skip < 0)
|
|
||||||
elements_to_skip = 0;
|
|
||||||
if (elements_to_skip >= static_cast<int>(total_elements_))
|
|
||||||
elements_to_skip = total_elements_ - 1;
|
|
||||||
if (elements_to_skip < static_cast<int>(total_elements_low_)) {
|
|
||||||
for (uint32_t value = 0; value < long_tail_boundary_; ++value) {
|
|
||||||
elements_to_skip -= histogram_low_[value];
|
|
||||||
if (elements_to_skip < 0)
|
|
||||||
return rtc::Optional<uint32_t>(value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
elements_to_skip -= total_elements_low_;
|
|
||||||
for (auto it = histogram_high_.begin(); it != histogram_high_.end(); ++it) {
|
|
||||||
elements_to_skip -= it->second;
|
|
||||||
if (elements_to_skip < 0)
|
|
||||||
return rtc::Optional<uint32_t>(it->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RTC_NOTREACHED();
|
|
||||||
return rtc::Optional<uint32_t>();
|
|
||||||
}
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -21,6 +21,7 @@
|
|||||||
#include "common_video/include/frame_callback.h"
|
#include "common_video/include/frame_callback.h"
|
||||||
#include "modules/video_coding/include/video_coding_defines.h"
|
#include "modules/video_coding/include/video_coding_defines.h"
|
||||||
#include "rtc_base/criticalsection.h"
|
#include "rtc_base/criticalsection.h"
|
||||||
|
#include "rtc_base/histogram_percentile_counter.h"
|
||||||
#include "rtc_base/moving_max_counter.h"
|
#include "rtc_base/moving_max_counter.h"
|
||||||
#include "rtc_base/rate_statistics.h"
|
#include "rtc_base/rate_statistics.h"
|
||||||
#include "rtc_base/ratetracker.h"
|
#include "rtc_base/ratetracker.h"
|
||||||
@ -95,25 +96,6 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
|
|||||||
// Implements CallStatsObserver.
|
// Implements CallStatsObserver.
|
||||||
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
|
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
|
||||||
|
|
||||||
class HistogramPercentileCounter {
|
|
||||||
public:
|
|
||||||
// Values below |long_tail_boundary| are stored in the array.
|
|
||||||
// Values above - in the map.
|
|
||||||
explicit HistogramPercentileCounter(size_t long_tail_boundary);
|
|
||||||
void Add(uint32_t value);
|
|
||||||
void Add(uint32_t value, size_t count);
|
|
||||||
void Add(const HistogramPercentileCounter& other);
|
|
||||||
// Argument should be from 0 to 1.
|
|
||||||
rtc::Optional<uint32_t> GetPercentile(float fraction);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<size_t> histogram_low_;
|
|
||||||
std::map<uint32_t, size_t> histogram_high_;
|
|
||||||
const size_t long_tail_boundary_;
|
|
||||||
size_t total_elements_;
|
|
||||||
size_t total_elements_low_;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SampleCounter {
|
struct SampleCounter {
|
||||||
SampleCounter() : sum(0), num_samples(0) {}
|
SampleCounter() : sum(0), num_samples(0) {}
|
||||||
@ -146,7 +128,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
|
|||||||
SampleCounter received_height;
|
SampleCounter received_height;
|
||||||
SampleCounter qp_counter;
|
SampleCounter qp_counter;
|
||||||
FrameCounts frame_counts;
|
FrameCounts frame_counts;
|
||||||
HistogramPercentileCounter interframe_delay_percentiles;
|
rtc::HistogramPercentileCounter interframe_delay_percentiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
void UpdateHistograms() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
void UpdateHistograms() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||||
|
|||||||
@ -999,26 +999,4 @@ TEST_P(ReceiveStatisticsProxyTest, StatsAreSlicedOnSimulcastAndExperiment) {
|
|||||||
"WebRTC.Video.InterframeDelayInMs.ExperimentGroup0"));
|
"WebRTC.Video.InterframeDelayInMs.ExperimentGroup0"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ReceiveStatisticsProxyTest, PercentileCounterReturnsCorrectPercentiles) {
|
|
||||||
ReceiveStatisticsProxy::HistogramPercentileCounter counter(10);
|
|
||||||
const std::vector<int> kTestValues = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
||||||
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
|
|
||||||
|
|
||||||
EXPECT_FALSE(counter.GetPercentile(0.5f));
|
|
||||||
// Pairs of {fraction, percentile value} computed by hand
|
|
||||||
// for |kTestValues|.
|
|
||||||
const std::vector<std::pair<float, uint32_t>> kTestPercentiles = {
|
|
||||||
{0.0f, 1}, {0.01f, 1}, {0.5f, 10}, {0.9f, 18},
|
|
||||||
{0.95f, 19}, {0.99f, 20}, {1.0f, 20}};
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < kTestValues.size(); ++i) {
|
|
||||||
counter.Add(kTestValues[i]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < kTestPercentiles.size(); ++i) {
|
|
||||||
EXPECT_EQ(kTestPercentiles[i].second,
|
|
||||||
counter.GetPercentile(kTestPercentiles[i].first).value_or(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user