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:
Ilya Nikolaevskiy 2017-10-12 12:38:01 +02:00 committed by Commit Bot
parent 86f25d3bcd
commit ed23be91b8
7 changed files with 170 additions and 107 deletions

View file

@ -137,6 +137,8 @@ rtc_source_set("rtc_base_approved_generic") {
"flags.h",
"format_macros.h",
"function_view.h",
"histogram_percentile_counter.cc",
"histogram_percentile_counter.h",
"ignore_wundef.h",
"location.cc",
"location.h",
@ -895,6 +897,7 @@ if (rtc_include_tests) {
"event_unittest.cc",
"file_unittest.cc",
"function_view_unittest.cc",
"histogram_percentile_counter_unittest.cc",
"logging_unittest.cc",
"md5digest_unittest.cc",
"mod_ops_unittest.cc",

View 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

View 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_

View 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));
}

View file

@ -821,69 +821,4 @@ void ReceiveStatisticsProxy::ContentSpecificStats::Add(
frame_counts.delta_frames += other.frame_counts.delta_frames;
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

View file

@ -21,6 +21,7 @@
#include "common_video/include/frame_callback.h"
#include "modules/video_coding/include/video_coding_defines.h"
#include "rtc_base/criticalsection.h"
#include "rtc_base/histogram_percentile_counter.h"
#include "rtc_base/moving_max_counter.h"
#include "rtc_base/rate_statistics.h"
#include "rtc_base/ratetracker.h"
@ -95,25 +96,6 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
// Implements CallStatsObserver.
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:
struct SampleCounter {
SampleCounter() : sum(0), num_samples(0) {}
@ -146,7 +128,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
SampleCounter received_height;
SampleCounter qp_counter;
FrameCounts frame_counts;
HistogramPercentileCounter interframe_delay_percentiles;
rtc::HistogramPercentileCounter interframe_delay_percentiles;
};
void UpdateHistograms() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_);

View file

@ -999,26 +999,4 @@ TEST_P(ReceiveStatisticsProxyTest, StatsAreSlicedOnSimulcastAndExperiment) {
"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