Add implementation in metrics.h that uses atomic pointer.
Update test implementation (test/histograms.h) to be more similar a real implementation (where histogram get functions return a Histogram pointer). Add check that the name of a histogram does not change. BUG=webrtc:5283 Review URL: https://codereview.webrtc.org/1528403003 Cr-Commit-Position: refs/heads/master@{#11161}
This commit is contained in:
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "webrtc/base/atomicops.h"
|
||||||
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/common_types.h"
|
#include "webrtc/common_types.h"
|
||||||
|
|
||||||
// Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
|
// Macros for allowing WebRTC clients (e.g. Chrome) to gather and aggregate
|
||||||
@ -58,17 +60,29 @@
|
|||||||
|
|
||||||
|
|
||||||
// Macros for adding samples to a named histogram.
|
// Macros for adding samples to a named histogram.
|
||||||
//
|
|
||||||
// NOTE: this is a temporary solution.
|
|
||||||
// The aim is to mimic the behaviour in Chromium's src/base/metrics/histograms.h
|
|
||||||
// However as atomics are not supported in webrtc, this is for now a modified
|
|
||||||
// and temporary solution. Note that the histogram is constructed/found for
|
|
||||||
// each call. Therefore, for now only use this implementation for metrics
|
|
||||||
// that do not need to be updated frequently.
|
|
||||||
// TODO(asapersson): Change implementation when atomics are supported.
|
|
||||||
// Also consider changing string to const char* when switching to atomics.
|
|
||||||
|
|
||||||
// Histogram for counters.
|
// Histogram for counters (exponentially spaced buckets).
|
||||||
|
#define RTC_HISTOGRAM_COUNTS_100(name, sample) \
|
||||||
|
RTC_HISTOGRAM_COUNTS(name, sample, 1, 100, 50)
|
||||||
|
|
||||||
|
#define RTC_HISTOGRAM_COUNTS_200(name, sample) \
|
||||||
|
RTC_HISTOGRAM_COUNTS(name, sample, 1, 200, 50)
|
||||||
|
|
||||||
|
#define RTC_HISTOGRAM_COUNTS_1000(name, sample) \
|
||||||
|
RTC_HISTOGRAM_COUNTS(name, sample, 1, 1000, 50)
|
||||||
|
|
||||||
|
#define RTC_HISTOGRAM_COUNTS_10000(name, sample) \
|
||||||
|
RTC_HISTOGRAM_COUNTS(name, sample, 1, 10000, 50)
|
||||||
|
|
||||||
|
#define RTC_HISTOGRAM_COUNTS_100000(name, sample) \
|
||||||
|
RTC_HISTOGRAM_COUNTS(name, sample, 1, 100000, 50)
|
||||||
|
|
||||||
|
#define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \
|
||||||
|
RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
|
||||||
|
webrtc::metrics::HistogramFactoryGetCounts(name, min, max, bucket_count))
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
// TODO(asapersson): Remove.
|
||||||
#define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
|
#define RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample) \
|
||||||
RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50)
|
RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, 1, 100, 50)
|
||||||
|
|
||||||
@ -86,26 +100,59 @@
|
|||||||
|
|
||||||
#define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
|
#define RTC_HISTOGRAM_COUNTS_SPARSE(name, sample, min, max, bucket_count) \
|
||||||
RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \
|
RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \
|
||||||
webrtc::metrics::HistogramFactoryGetCounts( \
|
webrtc::metrics::HistogramFactoryGetCounts(name, min, max, bucket_count))
|
||||||
name, min, max, bucket_count))
|
|
||||||
|
|
||||||
// Histogram for percentage.
|
// Histogram for percentage (evenly spaced buckets).
|
||||||
|
#define RTC_HISTOGRAM_PERCENTAGE(name, sample) \
|
||||||
|
RTC_HISTOGRAM_ENUMERATION(name, sample, 101)
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
// TODO(asapersson): Remove.
|
||||||
#define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
|
#define RTC_HISTOGRAM_PERCENTAGE_SPARSE(name, sample) \
|
||||||
RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101)
|
RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, 101)
|
||||||
|
|
||||||
// Histogram for enumerators.
|
// Histogram for enumerators (evenly spaced buckets).
|
||||||
// |boundary| should be above the max enumerator sample.
|
// |boundary| should be above the max enumerator sample.
|
||||||
|
#define RTC_HISTOGRAM_ENUMERATION(name, sample, boundary) \
|
||||||
|
RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \
|
||||||
|
webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
// TODO(asapersson): Remove.
|
||||||
#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
|
#define RTC_HISTOGRAM_ENUMERATION_SPARSE(name, sample, boundary) \
|
||||||
RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \
|
RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, \
|
||||||
webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
|
webrtc::metrics::HistogramFactoryGetEnumeration(name, boundary))
|
||||||
|
|
||||||
#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(constant_name, sample, \
|
// The name of the histogram should not vary.
|
||||||
|
// TODO(asapersson): Consider changing string to const char*.
|
||||||
|
#define RTC_HISTOGRAM_COMMON_BLOCK(constant_name, sample, \
|
||||||
factory_get_invocation) \
|
factory_get_invocation) \
|
||||||
do { \
|
do { \
|
||||||
webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \
|
static webrtc::metrics::Histogram* atomic_histogram_pointer = nullptr; \
|
||||||
|
webrtc::metrics::Histogram* histogram_pointer = \
|
||||||
|
rtc::AtomicOps::AcquireLoadPtr(&atomic_histogram_pointer); \
|
||||||
|
if (!histogram_pointer) { \
|
||||||
|
histogram_pointer = factory_get_invocation; \
|
||||||
|
webrtc::metrics::Histogram* prev_pointer = \
|
||||||
|
rtc::AtomicOps::CompareAndSwapPtr( \
|
||||||
|
&atomic_histogram_pointer, \
|
||||||
|
static_cast<webrtc::metrics::Histogram*>(nullptr), \
|
||||||
|
histogram_pointer); \
|
||||||
|
RTC_DCHECK(prev_pointer == nullptr || \
|
||||||
|
prev_pointer == histogram_pointer); \
|
||||||
|
} \
|
||||||
webrtc::metrics::HistogramAdd(histogram_pointer, constant_name, sample); \
|
webrtc::metrics::HistogramAdd(histogram_pointer, constant_name, sample); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
// The histogram is constructed/found for each call.
|
||||||
|
// May be used for histograms with infrequent updates.
|
||||||
|
#define RTC_HISTOGRAM_COMMON_BLOCK_SLOW(name, sample, factory_get_invocation) \
|
||||||
|
do { \
|
||||||
|
webrtc::metrics::Histogram* histogram_pointer = factory_get_invocation; \
|
||||||
|
webrtc::metrics::HistogramAdd(histogram_pointer, name, sample); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace metrics {
|
namespace metrics {
|
||||||
|
|
||||||
|
91
webrtc/system_wrappers/source/metrics_unittest.cc
Normal file
91
webrtc/system_wrappers/source/metrics_unittest.cc
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 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 "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "webrtc/system_wrappers/include/metrics.h"
|
||||||
|
#include "webrtc/test/histogram.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
namespace {
|
||||||
|
const int kSample = 22;
|
||||||
|
const std::string kName = "Name";
|
||||||
|
|
||||||
|
void AddSparseSample(const std::string& name, int sample) {
|
||||||
|
RTC_HISTOGRAM_COUNTS_SPARSE_100(name, sample);
|
||||||
|
}
|
||||||
|
#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||||
|
void AddSample(const std::string& name, int sample) {
|
||||||
|
RTC_HISTOGRAM_COUNTS_100(name, sample);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(MetricsTest, InitiallyNoSamples) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
EXPECT_EQ(0, test::NumHistogramSamples(kName));
|
||||||
|
EXPECT_EQ(-1, test::LastHistogramSample(kName));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MetricsTest, RtcHistogramPercent_AddSample) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
RTC_HISTOGRAM_PERCENTAGE(kName, kSample);
|
||||||
|
EXPECT_EQ(1, test::NumHistogramSamples(kName));
|
||||||
|
EXPECT_EQ(kSample, test::LastHistogramSample(kName));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MetricsTest, RtcHistogramEnumeration_AddSample) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
RTC_HISTOGRAM_ENUMERATION(kName, kSample, kSample + 1);
|
||||||
|
EXPECT_EQ(1, test::NumHistogramSamples(kName));
|
||||||
|
EXPECT_EQ(kSample, test::LastHistogramSample(kName));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MetricsTest, RtcHistogramCountsSparse_AddSample) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
RTC_HISTOGRAM_COUNTS_SPARSE_100(kName, kSample);
|
||||||
|
EXPECT_EQ(1, test::NumHistogramSamples(kName));
|
||||||
|
EXPECT_EQ(kSample, test::LastHistogramSample(kName));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MetricsTest, RtcHistogramCounts_AddSample) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
RTC_HISTOGRAM_COUNTS_100(kName, kSample);
|
||||||
|
EXPECT_EQ(1, test::NumHistogramSamples(kName));
|
||||||
|
EXPECT_EQ(kSample, test::LastHistogramSample(kName));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MetricsTest, RtcHistogramCounts_AddMultipleSamples) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
const int kNumSamples = 10;
|
||||||
|
for (int i = 0; i < kNumSamples; ++i) {
|
||||||
|
RTC_HISTOGRAM_COUNTS_100(kName, i);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(kNumSamples, test::NumHistogramSamples(kName));
|
||||||
|
EXPECT_EQ(kNumSamples - 1, test::LastHistogramSample(kName));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MetricsTest, RtcHistogramSparse_NonConstantNameWorks) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
AddSparseSample("Name1", kSample);
|
||||||
|
AddSparseSample("Name2", kSample);
|
||||||
|
EXPECT_EQ(1, test::NumHistogramSamples("Name1"));
|
||||||
|
EXPECT_EQ(1, test::NumHistogramSamples("Name2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||||
|
TEST(MetricsTest, RtcHistogram_FailsForNonConstantName) {
|
||||||
|
test::ClearHistograms();
|
||||||
|
AddSample("Name1", kSample);
|
||||||
|
EXPECT_DEATH(AddSample("Name2", kSample), "");
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||||
|
|
||||||
|
} // namespace webrtc
|
@ -15,6 +15,7 @@
|
|||||||
'dependencies': [
|
'dependencies': [
|
||||||
'<(DEPTH)/testing/gtest.gyp:gtest',
|
'<(DEPTH)/testing/gtest.gyp:gtest',
|
||||||
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
|
'<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
|
||||||
|
'<(webrtc_root)/test/test.gyp:histogram',
|
||||||
'<(webrtc_root)/test/test.gyp:test_support_main',
|
'<(webrtc_root)/test/test.gyp:test_support_main',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
@ -29,6 +30,7 @@
|
|||||||
'source/data_log_helpers_unittest.cc',
|
'source/data_log_helpers_unittest.cc',
|
||||||
'source/data_log_c_helpers_unittest.c',
|
'source/data_log_c_helpers_unittest.c',
|
||||||
'source/data_log_c_helpers_unittest.h',
|
'source/data_log_c_helpers_unittest.h',
|
||||||
|
'source/metrics_unittest.cc',
|
||||||
'source/ntp_time_unittest.cc',
|
'source/ntp_time_unittest.cc',
|
||||||
'source/rtp_to_ntp_unittest.cc',
|
'source/rtp_to_ntp_unittest.cc',
|
||||||
'source/scoped_vector_unittest.cc',
|
'source/scoped_vector_unittest.cc',
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "webrtc/base/checks.h"
|
||||||
#include "webrtc/base/criticalsection.h"
|
#include "webrtc/base/criticalsection.h"
|
||||||
#include "webrtc/base/thread_annotations.h"
|
#include "webrtc/base/thread_annotations.h"
|
||||||
#include "webrtc/system_wrappers/include/metrics.h"
|
#include "webrtc/system_wrappers/include/metrics.h"
|
||||||
@ -22,10 +23,10 @@
|
|||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace {
|
namespace {
|
||||||
struct SampleInfo {
|
struct SampleInfo {
|
||||||
SampleInfo(int sample)
|
SampleInfo(const std::string& name) : name_(name), last_(-1), total_(0) {}
|
||||||
: last(sample), total(1) {}
|
const std::string name_;
|
||||||
int last; // Last added sample.
|
int last_; // Last added sample.
|
||||||
int total; // Total number of added samples.
|
int total_; // Total number of added samples.
|
||||||
};
|
};
|
||||||
|
|
||||||
rtc::CriticalSection histogram_crit_;
|
rtc::CriticalSection histogram_crit_;
|
||||||
@ -36,21 +37,33 @@ std::map<std::string, SampleInfo> histograms_ GUARDED_BY(histogram_crit_);
|
|||||||
|
|
||||||
namespace metrics {
|
namespace metrics {
|
||||||
Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max,
|
Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max,
|
||||||
int bucket_count) { return NULL; }
|
int bucket_count) {
|
||||||
|
rtc::CritScope cs(&histogram_crit_);
|
||||||
|
if (histograms_.find(name) == histograms_.end()) {
|
||||||
|
histograms_.insert(std::make_pair(name, SampleInfo(name)));
|
||||||
|
}
|
||||||
|
auto it = histograms_.find(name);
|
||||||
|
return reinterpret_cast<Histogram*>(&it->second);
|
||||||
|
}
|
||||||
|
|
||||||
Histogram* HistogramFactoryGetEnumeration(const std::string& name,
|
Histogram* HistogramFactoryGetEnumeration(const std::string& name,
|
||||||
int boundary) { return NULL; }
|
int boundary) {
|
||||||
|
rtc::CritScope cs(&histogram_crit_);
|
||||||
|
if (histograms_.find(name) == histograms_.end()) {
|
||||||
|
histograms_.insert(std::make_pair(name, SampleInfo(name)));
|
||||||
|
}
|
||||||
|
auto it = histograms_.find(name);
|
||||||
|
return reinterpret_cast<Histogram*>(&it->second);
|
||||||
|
}
|
||||||
|
|
||||||
void HistogramAdd(
|
void HistogramAdd(
|
||||||
Histogram* histogram_pointer, const std::string& name, int sample) {
|
Histogram* histogram_pointer, const std::string& name, int sample) {
|
||||||
rtc::CritScope cs(&histogram_crit_);
|
rtc::CritScope cs(&histogram_crit_);
|
||||||
auto it = histograms_.find(name);
|
SampleInfo* ptr = reinterpret_cast<SampleInfo*>(histogram_pointer);
|
||||||
if (it == histograms_.end()) {
|
// The name should not vary.
|
||||||
histograms_.insert(std::make_pair(name, SampleInfo(sample)));
|
RTC_CHECK(ptr->name_ == name);
|
||||||
return;
|
ptr->last_ = sample;
|
||||||
}
|
++ptr->total_;
|
||||||
it->second.last = sample;
|
|
||||||
++it->second.total;
|
|
||||||
}
|
}
|
||||||
} // namespace metrics
|
} // namespace metrics
|
||||||
|
|
||||||
@ -61,7 +74,7 @@ int LastHistogramSample(const std::string& name) {
|
|||||||
if (it == histograms_.end()) {
|
if (it == histograms_.end()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return it->second.last;
|
return it->second.last_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NumHistogramSamples(const std::string& name) {
|
int NumHistogramSamples(const std::string& name) {
|
||||||
@ -70,13 +83,15 @@ int NumHistogramSamples(const std::string& name) {
|
|||||||
if (it == histograms_.end()) {
|
if (it == histograms_.end()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return it->second.total;
|
return it->second.total_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearHistograms() {
|
void ClearHistograms() {
|
||||||
rtc::CritScope cs(&histogram_crit_);
|
rtc::CritScope cs(&histogram_crit_);
|
||||||
histograms_.clear();
|
for (auto& it : histograms_) {
|
||||||
|
it.second.last_ = -1;
|
||||||
|
it.second.total_ = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ int LastHistogramSample(const std::string& name);
|
|||||||
// Returns the number of added samples to a histogram.
|
// Returns the number of added samples to a histogram.
|
||||||
int NumHistogramSamples(const std::string& name);
|
int NumHistogramSamples(const std::string& name);
|
||||||
|
|
||||||
// Removes all histograms.
|
// Removes all histogram samples.
|
||||||
void ClearHistograms();
|
void ClearHistograms();
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
Reference in New Issue
Block a user