summaryrefslogtreecommitdiff
path: root/chromium/base/metrics
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-31 16:33:43 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-06 16:33:22 +0000
commitda51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch)
tree4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/base/metrics
parentc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff)
downloadqtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/base/metrics')
-rw-r--r--chromium/base/metrics/field_trial.cc24
-rw-r--r--chromium/base/metrics/field_trial.h26
-rw-r--r--chromium/base/metrics/field_trial_unittest.cc71
-rw-r--r--chromium/base/metrics/histogram.cc10
-rw-r--r--chromium/base/metrics/histogram_flattener.h4
-rw-r--r--chromium/base/metrics/histogram_functions.cc9
-rw-r--r--chromium/base/metrics/histogram_functions.h29
-rw-r--r--chromium/base/metrics/histogram_functions_unittest.cc30
-rw-r--r--chromium/base/metrics/histogram_macros.h26
-rw-r--r--chromium/base/metrics/histogram_macros_internal.h12
-rw-r--r--chromium/base/metrics/histogram_samples.cc5
-rw-r--r--chromium/base/metrics/histogram_snapshot_manager.h16
-rw-r--r--chromium/base/metrics/persistent_histogram_allocator.cc3
-rw-r--r--chromium/base/metrics/persistent_memory_allocator.cc11
-rw-r--r--chromium/base/metrics/record_histogram_checker.h2
-rw-r--r--chromium/base/metrics/single_sample_metrics.h8
-rw-r--r--chromium/base/metrics/sparse_histogram_unittest.cc33
-rw-r--r--chromium/base/metrics/statistics_recorder.cc544
-rw-r--r--chromium/base/metrics/statistics_recorder.h310
-rw-r--r--chromium/base/metrics/statistics_recorder_unittest.cc225
20 files changed, 643 insertions, 755 deletions
diff --git a/chromium/base/metrics/field_trial.cc b/chromium/base/metrics/field_trial.cc
index 72f25a9013e..7f7b372da00 100644
--- a/chromium/base/metrics/field_trial.cc
+++ b/chromium/base/metrics/field_trial.cc
@@ -199,7 +199,7 @@ void AddFeatureAndFieldTrialFlags(const char* enable_features_switch,
cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
std::string field_trial_states;
- FieldTrialList::AllStatesToString(&field_trial_states);
+ FieldTrialList::AllStatesToString(&field_trial_states, false);
if (!field_trial_states.empty()) {
cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
field_trial_states);
@@ -456,18 +456,9 @@ bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
return true;
}
-bool FieldTrial::GetState(State* field_trial_state) {
- if (!enable_field_trial_)
- return false;
- FinalizeGroupChoice();
- field_trial_state->trial_name = &trial_name_;
- field_trial_state->group_name = &group_name_;
- field_trial_state->activated = group_reported_;
- return true;
-}
-
-bool FieldTrial::GetStateWhileLocked(State* field_trial_state) {
- if (!enable_field_trial_)
+bool FieldTrial::GetStateWhileLocked(State* field_trial_state,
+ bool include_expired) {
+ if (!include_expired && !enable_field_trial_)
return false;
FinalizeGroupChoiceImpl(true);
field_trial_state->trial_name = &trial_name_;
@@ -648,14 +639,15 @@ void FieldTrialList::StatesToString(std::string* output) {
}
// static
-void FieldTrialList::AllStatesToString(std::string* output) {
+void FieldTrialList::AllStatesToString(std::string* output,
+ bool include_expired) {
if (!global_)
return;
AutoLock auto_lock(global_->lock_);
for (const auto& registered : global_->registered_) {
FieldTrial::State trial;
- if (!registered.second->GetStateWhileLocked(&trial))
+ if (!registered.second->GetStateWhileLocked(&trial, include_expired))
continue;
DCHECK_EQ(std::string::npos,
trial.trial_name->find(kPersistentStringSeparator));
@@ -1335,7 +1327,7 @@ void FieldTrialList::AddToAllocatorWhileLocked(
return;
FieldTrial::State trial_state;
- if (!field_trial->GetStateWhileLocked(&trial_state))
+ if (!field_trial->GetStateWhileLocked(&trial_state, false))
return;
// Or if we've already added it. We must check after GetState since it can
diff --git a/chromium/base/metrics/field_trial.h b/chromium/base/metrics/field_trial.h
index 19387a5f4c7..f794803f315 100644
--- a/chromium/base/metrics/field_trial.h
+++ b/chromium/base/metrics/field_trial.h
@@ -320,15 +320,13 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
bool GetActiveGroup(ActiveGroup* active_group) const;
// Returns the trial name and selected group name for this field trial via
- // the output parameter |field_trial_state|, but only if the trial has not
- // been disabled. In that case, true is returned and |field_trial_state| is
- // filled in; otherwise, the result is false and |field_trial_state| is left
- // untouched.
- bool GetState(State* field_trial_state);
-
- // Does the same thing as above, but is deadlock-free if the caller is holding
- // a lock.
- bool GetStateWhileLocked(State* field_trial_state);
+ // the output parameter |field_trial_state| for all the studies when
+ // |bool include_expired| is true. In case when |bool include_expired| is
+ // false, if the trial has not been disabled true is returned and
+ // |field_trial_state| is filled in; otherwise, the result is false and
+ // |field_trial_state| is left untouched.
+ // This function is deadlock-free if the caller is holding a lock.
+ bool GetStateWhileLocked(State* field_trial_state, bool include_expired);
// Returns the group_name. A winner need not have been chosen.
std::string group_name_internal() const { return group_name_; }
@@ -506,11 +504,11 @@ class BASE_EXPORT FieldTrialList {
// resurrection in another process. This allows randomization to be done in
// one process, and secondary processes can be synchronized on the result.
// The resulting string contains the name and group name pairs of all
- // registered FieldTrials which have not been disabled, with "/" used
- // to separate all names and to terminate the string. All activated trials
- // have their name prefixed with "*". This string is parsed by
- // |CreateTrialsFromString()|.
- static void AllStatesToString(std::string* output);
+ // registered FieldTrials including disabled based on |include_expired|,
+ // with "/" used to separate all names and to terminate the string. All
+ // activated trials have their name prefixed with "*". This string is parsed
+ // by |CreateTrialsFromString()|.
+ static void AllStatesToString(std::string* output, bool include_expired);
// Fills in the supplied vector |active_groups| (which must be empty when
// called) with a snapshot of all registered FieldTrials for which the group
diff --git a/chromium/base/metrics/field_trial_unittest.cc b/chromium/base/metrics/field_trial_unittest.cc
index 42c3ba1e436..56f727840d2 100644
--- a/chromium/base/metrics/field_trial_unittest.cc
+++ b/chromium/base/metrics/field_trial_unittest.cc
@@ -86,8 +86,7 @@ class FieldTrialTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(FieldTrialTest);
};
-// Test registration, and also check that destructors are called for trials
-// (and that Valgrind doesn't catch us leaking).
+// Test registration, and also check that destructors are called for trials.
TEST_F(FieldTrialTest, Registration) {
const char name1[] = "name 1 test";
const char name2[] = "name 2 test";
@@ -334,36 +333,6 @@ TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) {
EXPECT_EQ("Z", active_groups[1].group_name);
}
-TEST_F(FieldTrialTest, AllGroups) {
- FieldTrial::State field_trial_state;
- std::string one_winner("One Winner");
- scoped_refptr<FieldTrial> trial =
- CreateFieldTrial(one_winner, 10, "Default", nullptr);
- std::string winner("Winner");
- trial->AppendGroup(winner, 10);
- EXPECT_TRUE(trial->GetState(&field_trial_state));
- EXPECT_EQ(one_winner, *field_trial_state.trial_name);
- EXPECT_EQ(winner, *field_trial_state.group_name);
- trial->group();
- EXPECT_TRUE(trial->GetState(&field_trial_state));
- EXPECT_EQ(one_winner, *field_trial_state.trial_name);
- EXPECT_EQ(winner, *field_trial_state.group_name);
-
- std::string multi_group("MultiGroup");
- scoped_refptr<FieldTrial> multi_group_trial =
- CreateFieldTrial(multi_group, 9, "Default", nullptr);
-
- multi_group_trial->AppendGroup("Me", 3);
- multi_group_trial->AppendGroup("You", 3);
- multi_group_trial->AppendGroup("Them", 3);
- EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
- // Finalize the group selection by accessing the selected group.
- multi_group_trial->group();
- EXPECT_TRUE(multi_group_trial->GetState(&field_trial_state));
- EXPECT_EQ(multi_group, *field_trial_state.trial_name);
- EXPECT_EQ(multi_group_trial->group_name(), *field_trial_state.group_name);
-}
-
TEST_F(FieldTrialTest, ActiveGroupsNotFinalized) {
const char kTrialName[] = "TestTrial";
const char kSecondaryGroupName[] = "SecondaryGroup";
@@ -469,7 +438,7 @@ TEST_F(FieldTrialTest, SaveAll) {
scoped_refptr<FieldTrial> trial =
CreateFieldTrial("Some name", 10, "Default some name", nullptr);
EXPECT_EQ("", trial->group_name_internal());
- FieldTrialList::AllStatesToString(&save_string);
+ FieldTrialList::AllStatesToString(&save_string, false);
EXPECT_EQ("Some name/Default some name/", save_string);
// Getting all states should have finalized the trial.
EXPECT_EQ("Default some name", trial->group_name_internal());
@@ -480,7 +449,7 @@ TEST_F(FieldTrialTest, SaveAll) {
trial->AppendGroup("Winner", 10);
// Finalize the group selection by accessing the selected group.
trial->group();
- FieldTrialList::AllStatesToString(&save_string);
+ FieldTrialList::AllStatesToString(&save_string, false);
EXPECT_EQ("Some name/Default some name/*trial2/Winner/", save_string);
save_string.clear();
@@ -491,7 +460,7 @@ TEST_F(FieldTrialTest, SaveAll) {
// Finalize the group selection by accessing the selected group.
trial2->group();
- FieldTrialList::AllStatesToString(&save_string);
+ FieldTrialList::AllStatesToString(&save_string, false);
// We assume names are alphabetized... though this is not critical.
EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/",
save_string);
@@ -501,9 +470,29 @@ TEST_F(FieldTrialTest, SaveAll) {
scoped_refptr<FieldTrial> trial3 =
CreateFieldTrial("zzz", 10, "default", nullptr);
- FieldTrialList::AllStatesToString(&save_string);
+ FieldTrialList::AllStatesToString(&save_string, false);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
+ save_string);
+
+ // Create expired study.
+ int default_group_number = -1;
+ scoped_refptr<FieldTrial> expired_trial =
+ FieldTrialList::FactoryGetFieldTrial(
+ "Expired trial name", 1000000000, "Default group",
+ OneYearBeforeBuildTime(), 1, 1, base::FieldTrial::SESSION_RANDOMIZED,
+ &default_group_number);
+ expired_trial->AppendGroup("Expired trial group name", 999999999);
+
+ save_string.clear();
+ FieldTrialList::AllStatesToString(&save_string, false);
EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
save_string);
+ save_string.clear();
+ FieldTrialList::AllStatesToString(&save_string, true);
+ EXPECT_EQ(
+ "Expired trial name/Default group/"
+ "Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
+ save_string);
}
TEST_F(FieldTrialTest, Restore) {
@@ -1109,7 +1098,7 @@ TEST(FieldTrialTestWithoutList, StatesStringFormat) {
scoped_refptr<FieldTrial> trial3 =
CreateFieldTrial("zzz", 10, "default", nullptr);
- FieldTrialList::AllStatesToString(&save_string);
+ FieldTrialList::AllStatesToString(&save_string, false);
}
// Starting with a new blank FieldTrialList.
@@ -1192,7 +1181,7 @@ TEST(FieldTrialListTest, AddTrialsToAllocator) {
FieldTrialList field_trial_list(nullptr);
FieldTrialList::CreateFieldTrial("Trial1", "Group1");
FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded();
- FieldTrialList::AllStatesToString(&save_string);
+ FieldTrialList::AllStatesToString(&save_string, false);
handle = base::SharedMemory::DuplicateHandle(
field_trial_list.field_trial_allocator_->shared_memory()->handle());
}
@@ -1203,7 +1192,7 @@ TEST(FieldTrialListTest, AddTrialsToAllocator) {
shm.get()->Map(4 << 10);
FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
std::string check_string;
- FieldTrialList::AllStatesToString(&check_string);
+ FieldTrialList::AllStatesToString(&check_string, false);
EXPECT_EQ(save_string, check_string);
}
@@ -1241,7 +1230,7 @@ TEST(FieldTrialListTest, DoNotAddSimulatedFieldTrialsToAllocator) {
shm.get()->Map(4 << 10);
FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
std::string check_string;
- FieldTrialList::AllStatesToString(&check_string);
+ FieldTrialList::AllStatesToString(&check_string, false);
ASSERT_EQ(check_string.find("Simulated"), std::string::npos);
}
@@ -1325,7 +1314,7 @@ TEST(FieldTrialListTest, ClearParamsFromSharedMemory) {
shm.get()->Map(4 << 10);
FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
std::string check_string;
- FieldTrialList::AllStatesToString(&check_string);
+ FieldTrialList::AllStatesToString(&check_string, false);
EXPECT_EQ("*Trial1/Group1/", check_string);
}
diff --git a/chromium/base/metrics/histogram.cc b/chromium/base/metrics/histogram.cc
index 40e7bcc860a..488facd066d 100644
--- a/chromium/base/metrics/histogram.cc
+++ b/chromium/base/metrics/histogram.cc
@@ -19,10 +19,9 @@
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
-#include "base/debug/crash_logging.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/metrics_hashes.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
@@ -438,8 +437,8 @@ bool Histogram::InspectConstructionArguments(StringPiece name,
}
if (!check_okay) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Histogram.BadConstructionArguments",
- static_cast<Sample>(HashMetricName(name)));
+ UmaHistogramSparse("Histogram.BadConstructionArguments",
+ static_cast<Sample>(HashMetricName(name)));
}
return check_okay;
@@ -575,9 +574,6 @@ bool Histogram::ValidateHistogramContents(bool crash_if_invalid,
// Abort if a problem is found (except "flags", which could legally be zero).
std::string debug_string = base::StringPrintf(
"%s/%" PRIu32 "#%d", histogram_name(), bad_fields, identifier);
-#if !defined(OS_NACL)
- base::debug::ScopedCrashKey crash_key("bad_histogram", debug_string);
-#endif
CHECK(false) << debug_string;
debug::Alias(&bad_fields);
return false;
diff --git a/chromium/base/metrics/histogram_flattener.h b/chromium/base/metrics/histogram_flattener.h
index 22d9a92d32b..6a5e3f42988 100644
--- a/chromium/base/metrics/histogram_flattener.h
+++ b/chromium/base/metrics/histogram_flattener.h
@@ -23,8 +23,8 @@ class BASE_EXPORT HistogramFlattener {
const HistogramSamples& snapshot) = 0;
protected:
- HistogramFlattener() {}
- virtual ~HistogramFlattener() {}
+ HistogramFlattener() = default;
+ virtual ~HistogramFlattener() = default;
private:
DISALLOW_COPY_AND_ASSIGN(HistogramFlattener);
diff --git a/chromium/base/metrics/histogram_functions.cc b/chromium/base/metrics/histogram_functions.cc
index 4c1a4b57ed2..47eec7dbbfd 100644
--- a/chromium/base/metrics/histogram_functions.cc
+++ b/chromium/base/metrics/histogram_functions.cc
@@ -6,13 +6,14 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/time/time.h"
namespace base {
void UmaHistogramBoolean(const std::string& name, bool sample) {
HistogramBase* histogram = BooleanHistogram::FactoryGet(
- name, base::HistogramBase::kUmaTargetedHistogramFlag);
+ name, HistogramBase::kUmaTargetedHistogramFlag);
histogram->Add(sample);
}
@@ -100,4 +101,10 @@ void UmaHistogramMemoryLargeMB(const std::string& name, int sample) {
UmaHistogramCustomCounts(name, sample, 1, 64000, 100);
}
+void UmaHistogramSparse(const std::string& name, int sample) {
+ HistogramBase* histogram = SparseHistogram::FactoryGet(
+ name, HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(sample);
+}
+
} // namespace base
diff --git a/chromium/base/metrics/histogram_functions.h b/chromium/base/metrics/histogram_functions.h
index 46986283880..c9632fa26f0 100644
--- a/chromium/base/metrics/histogram_functions.h
+++ b/chromium/base/metrics/histogram_functions.h
@@ -110,6 +110,35 @@ BASE_EXPORT void UmaHistogramMemoryMB(const std::string& name, int sample);
// Used to measure common MB-granularity memory stats. Range is up to ~64G.
BASE_EXPORT void UmaHistogramMemoryLargeMB(const std::string& name, int sample);
+// For recording sparse histograms.
+// The |sample| can be a negative or non-negative number.
+//
+// Sparse histograms are well suited for recording counts of exact sample values
+// that are sparsely distributed over a relatively large range, in cases where
+// ultra-fast performance is not critical. For instance, Sqlite.Version.* are
+// sparse because for any given database, there's going to be exactly one
+// version logged.
+//
+// Performance:
+// ------------
+// Sparse histograms are typically more memory-efficient but less time-efficient
+// than other histograms. Essentially, they sparse histograms use a map rather
+// than a vector for their backing storage; they also require lock acquisition
+// to increment a sample, whereas other histogram do not. Hence, each increment
+// operation is a bit slower than for other histograms. But, if the data is
+// sparse, then they use less memory client-side, because they allocate buckets
+// on demand rather than preallocating.
+//
+// Data size:
+// ----------
+// Note that server-side, we still need to load all buckets, across all users,
+// at once. Thus, please avoid exploding such histograms, i.e. uploading many
+// many distinct values to the server (across all users). Concretely, keep the
+// number of distinct values <= 100 ideally, definitely <= 1000. If you have no
+// guarantees on the range of your data, use clamping, e.g.:
+// UmaHistogramSparse("MyHistogram", ClampToRange(value, 0, 200));
+BASE_EXPORT void UmaHistogramSparse(const std::string& name, int sample);
+
} // namespace base
#endif // BASE_METRICS_HISTOGRAM_FUNCTIONS_H_
diff --git a/chromium/base/metrics/histogram_functions_unittest.cc b/chromium/base/metrics/histogram_functions_unittest.cc
index 7bfd202e2dc..37206747572 100644
--- a/chromium/base/metrics/histogram_functions_unittest.cc
+++ b/chromium/base/metrics/histogram_functions_unittest.cc
@@ -7,6 +7,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/test/histogram_tester.h"
#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -17,7 +18,7 @@ enum UmaHistogramTestingEnum {
UMA_HISTOGRAM_TESTING_ENUM_THIRD
};
-TEST(HistogramFunctionsTest, HistogramExactLinear) {
+TEST(HistogramFunctionsTest, ExactLinear) {
std::string histogram("Testing.UMA.HistogramExactLinear");
HistogramTester tester;
UmaHistogramExactLinear(histogram, 10, 100);
@@ -37,7 +38,7 @@ TEST(HistogramFunctionsTest, HistogramExactLinear) {
tester.ExpectTotalCount(histogram, 5);
}
-TEST(HistogramFunctionsTest, HistogramEnumeration) {
+TEST(HistogramFunctionsTest, Enumeration) {
std::string histogram("Testing.UMA.HistogramEnumeration");
HistogramTester tester;
UmaHistogramEnumeration(histogram, UMA_HISTOGRAM_TESTING_ENUM_FIRST,
@@ -53,7 +54,7 @@ TEST(HistogramFunctionsTest, HistogramEnumeration) {
tester.ExpectTotalCount(histogram, 2);
}
-TEST(HistogramFunctionsTest, HistogramBoolean) {
+TEST(HistogramFunctionsTest, Boolean) {
std::string histogram("Testing.UMA.HistogramBoolean");
HistogramTester tester;
UmaHistogramBoolean(histogram, true);
@@ -63,7 +64,7 @@ TEST(HistogramFunctionsTest, HistogramBoolean) {
tester.ExpectTotalCount(histogram, 2);
}
-TEST(HistogramFunctionsTest, HistogramPercentage) {
+TEST(HistogramFunctionsTest, Percentage) {
std::string histogram("Testing.UMA.HistogramPercentage");
HistogramTester tester;
UmaHistogramPercentage(histogram, 50);
@@ -74,7 +75,7 @@ TEST(HistogramFunctionsTest, HistogramPercentage) {
tester.ExpectTotalCount(histogram, 2);
}
-TEST(HistogramFunctionsTest, HistogramCounts) {
+TEST(HistogramFunctionsTest, Counts) {
std::string histogram("Testing.UMA.HistogramCount.Custom");
HistogramTester tester;
UmaHistogramCustomCounts(histogram, 10, 1, 100, 10);
@@ -89,7 +90,7 @@ TEST(HistogramFunctionsTest, HistogramCounts) {
tester.ExpectTotalCount(histogram, 5);
}
-TEST(HistogramFunctionsTest, HistogramTimes) {
+TEST(HistogramFunctionsTest, Times) {
std::string histogram("Testing.UMA.HistogramTimes");
HistogramTester tester;
UmaHistogramTimes(histogram, TimeDelta::FromSeconds(1));
@@ -106,4 +107,21 @@ TEST(HistogramFunctionsTest, HistogramTimes) {
tester.ExpectTotalCount(histogram, 4);
}
+TEST(HistogramFunctionsTest, Sparse_SupportsLargeRange) {
+ std::string histogram("Testing.UMA.HistogramSparse");
+ HistogramTester tester;
+ UmaHistogramSparse(histogram, 0);
+ UmaHistogramSparse(histogram, 123456789);
+ UmaHistogramSparse(histogram, 123456789);
+ EXPECT_THAT(tester.GetAllSamples(histogram),
+ testing::ElementsAre(Bucket(0, 1), Bucket(123456789, 2)));
+}
+
+TEST(HistogramFunctionsTest, Sparse_SupportsNegativeValues) {
+ std::string histogram("Testing.UMA.HistogramSparse");
+ HistogramTester tester;
+ UmaHistogramSparse(histogram, -1);
+ tester.ExpectUniqueSample(histogram, -1, 1);
+}
+
} // namespace base.
diff --git a/chromium/base/metrics/histogram_macros.h b/chromium/base/metrics/histogram_macros.h
index 891d2a40bff..083bae753cb 100644
--- a/chromium/base/metrics/histogram_macros.h
+++ b/chromium/base/metrics/histogram_macros.h
@@ -249,32 +249,6 @@
base::HistogramBase::kUmaStabilityHistogramFlag)
//------------------------------------------------------------------------------
-// Sparse histograms.
-
-// Sparse histograms are well suited for recording counts of exact sample values
-// that are sparsely distributed over a large range.
-//
-// UMA_HISTOGRAM_SPARSE_SLOWLY is good for sparsely distributed and/or
-// infrequently recorded values since the implementation is slower
-// and takes more memory. For sparse data, sparse histograms have the advantage
-// of using less memory client-side, because they allocate buckets on demand
-// rather than preallocating. However, server-side, we still need to load all
-// buckets, across all users, at once.
-
-// Thus, please avoid exploding such histograms, i.e. uploading many many
-// distinct values to the server (across all users). Concretely, keep the number
-// of distinct values <= 100 at best, definitely <= 1000. If you have no
-// guarantees on the range of your data, use capping, e.g.:
-// UMA_HISTOGRAM_SPARSE_SLOWLY("MyHistogram",
-// std::max(0, std::min(200, value)));
-//
-// For instance, Sqlite.Version.* are sparse because for any given database,
-// there's going to be exactly one version logged.
-// The |sample| can be a negative or non-negative number.
-#define UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample) \
- INTERNAL_HISTOGRAM_SPARSE_SLOWLY(name, sample)
-
-//------------------------------------------------------------------------------
// Histogram instantiation helpers.
// Support a collection of histograms, perhaps one for each entry in an
diff --git a/chromium/base/metrics/histogram_macros_internal.h b/chromium/base/metrics/histogram_macros_internal.h
index 15e191712ac..84defae32f6 100644
--- a/chromium/base/metrics/histogram_macros_internal.h
+++ b/chromium/base/metrics/histogram_macros_internal.h
@@ -180,16 +180,4 @@
base::TimeTicks constructed_; \
} scoped_histogram_timer_##key
-// Macro for sparse histogram.
-// The implementation is more costly to add values to, and each value
-// stored has more overhead, compared to the other histogram types. However it
-// may be more efficient in memory if the total number of sample values is small
-// compared to the range of their values.
-#define INTERNAL_HISTOGRAM_SPARSE_SLOWLY(name, sample) \
- do { \
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( \
- name, base::HistogramBase::kUmaTargetedHistogramFlag); \
- histogram->Add(sample); \
- } while (0)
-
#endif // BASE_METRICS_HISTOGRAM_MACROS_INTERNAL_H_
diff --git a/chromium/base/metrics/histogram_samples.cc b/chromium/base/metrics/histogram_samples.cc
index 7703580538f..6830637c06d 100644
--- a/chromium/base/metrics/histogram_samples.cc
+++ b/chromium/base/metrics/histogram_samples.cc
@@ -7,6 +7,7 @@
#include <limits>
#include "base/compiler_specific.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
@@ -258,8 +259,8 @@ void HistogramSamples::RecordNegativeSample(NegativeSampleReason reason,
MAX_NEGATIVE_SAMPLE_REASONS);
UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.NegativeSamples.Increment", increment, 1,
1 << 30, 100);
- UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.NegativeSamples.Histogram",
- static_cast<int32_t>(id()));
+ UmaHistogramSparse("UMA.NegativeSamples.Histogram",
+ static_cast<int32_t>(id()));
}
SampleCountIterator::~SampleCountIterator() = default;
diff --git a/chromium/base/metrics/histogram_snapshot_manager.h b/chromium/base/metrics/histogram_snapshot_manager.h
index 51bf92c7b55..e2a404fa541 100644
--- a/chromium/base/metrics/histogram_snapshot_manager.h
+++ b/chromium/base/metrics/histogram_snapshot_manager.h
@@ -28,10 +28,10 @@ class HistogramFlattener;
// corruption, this class also validates as much redundancy as it can before
// calling for the marginal change (a.k.a., delta) in a histogram to be
// recorded.
-class BASE_EXPORT HistogramSnapshotManager {
+class BASE_EXPORT HistogramSnapshotManager final {
public:
explicit HistogramSnapshotManager(HistogramFlattener* histogram_flattener);
- virtual ~HistogramSnapshotManager();
+ ~HistogramSnapshotManager();
// Snapshot all histograms, and ask |histogram_flattener_| to record the
// delta. |flags_to_set| is used to set flags for each histogram.
@@ -39,15 +39,13 @@ class BASE_EXPORT HistogramSnapshotManager {
// Only histograms that have all the flags specified by the argument will be
// chosen. If all histograms should be recorded, set it to
// |Histogram::kNoFlags|.
- template <class ForwardHistogramIterator>
- void PrepareDeltas(ForwardHistogramIterator begin,
- ForwardHistogramIterator end,
+ void PrepareDeltas(const std::vector<HistogramBase*>& histograms,
HistogramBase::Flags flags_to_set,
HistogramBase::Flags required_flags) {
- for (ForwardHistogramIterator it = begin; it != end; ++it) {
- (*it)->SetFlags(flags_to_set);
- if (((*it)->flags() & required_flags) == required_flags)
- PrepareDelta(*it);
+ for (HistogramBase* const histogram : histograms) {
+ histogram->SetFlags(flags_to_set);
+ if ((histogram->flags() & required_flags) == required_flags)
+ PrepareDelta(histogram);
}
}
diff --git a/chromium/base/metrics/persistent_histogram_allocator.cc b/chromium/base/metrics/persistent_histogram_allocator.cc
index 79a903eb183..6178b21a48d 100644
--- a/chromium/base/metrics/persistent_histogram_allocator.cc
+++ b/chromium/base/metrics/persistent_histogram_allocator.cc
@@ -1090,9 +1090,6 @@ GlobalHistogramAllocator::GlobalHistogramAllocator(
std::unique_ptr<PersistentMemoryAllocator> memory)
: PersistentHistogramAllocator(std::move(memory)),
import_iterator_(this) {
- // Make sure the StatisticsRecorder is initialized to prevent duplicate
- // histograms from being created. It's safe to call this multiple times.
- StatisticsRecorder::Initialize();
}
void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() {
diff --git a/chromium/base/metrics/persistent_memory_allocator.cc b/chromium/base/metrics/persistent_memory_allocator.cc
index be107c39474..065c0282921 100644
--- a/chromium/base/metrics/persistent_memory_allocator.cc
+++ b/chromium/base/metrics/persistent_memory_allocator.cc
@@ -8,6 +8,7 @@
#include <algorithm>
#if defined(OS_WIN)
+#include <windows.h>
#include "winbase.h"
#elif defined(OS_POSIX)
#include <sys/mman.h>
@@ -16,7 +17,7 @@
#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/sparse_histogram.h"
#include "base/numerics/safe_conversions.h"
#include "base/sys_info.h"
@@ -966,8 +967,8 @@ LocalPersistentMemoryAllocator::AllocateLocalMemory(size_t size) {
::VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (address)
return Memory(address, MEM_VIRTUAL);
- UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LocalPersistentMemoryAllocator.Failures.Win",
- ::GetLastError());
+ UmaHistogramSparse("UMA.LocalPersistentMemoryAllocator.Failures.Win",
+ ::GetLastError());
#elif defined(OS_POSIX)
// MAP_ANON is deprecated on Linux but MAP_ANONYMOUS is not universal on Mac.
// MAP_SHARED is not available on Linux <2.4 but required on Mac.
@@ -975,8 +976,8 @@ LocalPersistentMemoryAllocator::AllocateLocalMemory(size_t size) {
MAP_ANON | MAP_SHARED, -1, 0);
if (address != MAP_FAILED)
return Memory(address, MEM_VIRTUAL);
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "UMA.LocalPersistentMemoryAllocator.Failures.Posix", errno);
+ UmaHistogramSparse("UMA.LocalPersistentMemoryAllocator.Failures.Posix",
+ errno);
#else
#error This architecture is not (yet) supported.
#endif
diff --git a/chromium/base/metrics/record_histogram_checker.h b/chromium/base/metrics/record_histogram_checker.h
index 686bf676c63..75bc336d18e 100644
--- a/chromium/base/metrics/record_histogram_checker.h
+++ b/chromium/base/metrics/record_histogram_checker.h
@@ -15,7 +15,7 @@ namespace base {
// the given histogram should be recorded.
class BASE_EXPORT RecordHistogramChecker {
public:
- virtual ~RecordHistogramChecker() {}
+ virtual ~RecordHistogramChecker() = default;
// Returns true iff the given histogram should be recorded.
// This method may be called on any thread, so it should not mutate any state.
diff --git a/chromium/base/metrics/single_sample_metrics.h b/chromium/base/metrics/single_sample_metrics.h
index 6bfd7cb0db1..b966cb1ac5f 100644
--- a/chromium/base/metrics/single_sample_metrics.h
+++ b/chromium/base/metrics/single_sample_metrics.h
@@ -17,7 +17,7 @@ namespace base {
// and destroyed from the same thread as construction.
class BASE_EXPORT SingleSampleMetric {
public:
- virtual ~SingleSampleMetric() {}
+ virtual ~SingleSampleMetric() = default;
virtual void SetSample(HistogramBase::Sample sample) = 0;
};
@@ -34,7 +34,7 @@ class BASE_EXPORT SingleSampleMetric {
// base/metrics/histogram.h for full parameter definitions.
class BASE_EXPORT SingleSampleMetricsFactory {
public:
- virtual ~SingleSampleMetricsFactory() {}
+ virtual ~SingleSampleMetricsFactory() = default;
// Returns the factory provided by SetFactory(), or if no factory has been set
// a default factory will be provided (future calls to SetFactory() will fail
@@ -63,8 +63,8 @@ class BASE_EXPORT SingleSampleMetricsFactory {
class BASE_EXPORT DefaultSingleSampleMetricsFactory
: public SingleSampleMetricsFactory {
public:
- DefaultSingleSampleMetricsFactory() {}
- ~DefaultSingleSampleMetricsFactory() override {}
+ DefaultSingleSampleMetricsFactory() = default;
+ ~DefaultSingleSampleMetricsFactory() override = default;
// SingleSampleMetricsFactory:
std::unique_ptr<SingleSampleMetric> CreateCustomCountsMetric(
diff --git a/chromium/base/metrics/sparse_histogram_unittest.cc b/chromium/base/metrics/sparse_histogram_unittest.cc
index eeba150bf14..5f333e07eef 100644
--- a/chromium/base/metrics/sparse_histogram_unittest.cc
+++ b/chromium/base/metrics/sparse_histogram_unittest.cc
@@ -8,7 +8,7 @@
#include <string>
#include "base/metrics/histogram_base.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/metrics_hashes.h"
#include "base/metrics/persistent_histogram_allocator.h"
@@ -17,6 +17,7 @@
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
#include "base/strings/stringprintf.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -172,15 +173,15 @@ TEST_P(SparseHistogramTest, AddCount_LargeCountsDontOverflow) {
}
TEST_P(SparseHistogramTest, MacroBasicTest) {
- UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
- UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200);
- UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
+ UmaHistogramSparse("Sparse", 100);
+ UmaHistogramSparse("Sparse", 200);
+ UmaHistogramSparse("Sparse", 100);
- StatisticsRecorder::Histograms histograms;
- StatisticsRecorder::GetHistograms(&histograms);
+ const StatisticsRecorder::Histograms histograms =
+ StatisticsRecorder::GetHistograms();
- ASSERT_EQ(1U, histograms.size());
- HistogramBase* sparse_histogram = histograms[0];
+ ASSERT_THAT(histograms, testing::SizeIs(1));
+ const HistogramBase* const sparse_histogram = histograms[0];
EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType());
EXPECT_EQ("Sparse", StringPiece(sparse_histogram->histogram_name()));
@@ -201,18 +202,14 @@ TEST_P(SparseHistogramTest, MacroInLoopTest) {
// Unlike the macros in histogram.h, SparseHistogram macros can have a
// variable as histogram name.
for (int i = 0; i < 2; i++) {
- std::string name = StringPrintf("Sparse%d", i + 1);
- UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100);
+ UmaHistogramSparse(StringPrintf("Sparse%d", i), 100);
}
- StatisticsRecorder::Histograms histograms;
- StatisticsRecorder::GetHistograms(&histograms);
- ASSERT_EQ(2U, histograms.size());
-
- std::string name1 = histograms[0]->histogram_name();
- std::string name2 = histograms[1]->histogram_name();
- EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) ||
- ("Sparse2" == name1 && "Sparse1" == name2));
+ const StatisticsRecorder::Histograms histograms =
+ StatisticsRecorder::GetHistograms();
+ ASSERT_THAT(histograms, testing::SizeIs(2));
+ EXPECT_STREQ(histograms[0]->histogram_name(), "Sparse0");
+ EXPECT_STREQ(histograms[1]->histogram_name(), "Sparse1");
}
TEST_P(SparseHistogramTest, Serialize) {
diff --git a/chromium/base/metrics/statistics_recorder.cc b/chromium/base/metrics/statistics_recorder.cc
index a21adc09a0c..60e430eb72a 100644
--- a/chromium/base/metrics/statistics_recorder.cc
+++ b/chromium/base/metrics/statistics_recorder.cc
@@ -20,184 +20,138 @@
#include "base/strings/stringprintf.h"
#include "base/values.h"
+namespace base {
namespace {
-// Initialize histogram statistics gathering system.
-base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
- LAZY_INSTANCE_INITIALIZER;
-
bool HistogramNameLesser(const base::HistogramBase* a,
const base::HistogramBase* b) {
- return a->histogram_name() < b->histogram_name();
+ return strcmp(a->histogram_name(), b->histogram_name()) < 0;
}
} // namespace
-namespace base {
+// static
+LazyInstance<Lock>::Leaky StatisticsRecorder::lock_;
-StatisticsRecorder::~StatisticsRecorder() {
- DCHECK(histograms_);
- DCHECK(ranges_);
+// static
+StatisticsRecorder* StatisticsRecorder::top_ = nullptr;
- // Clean out what this object created and then restore what existed before.
- Reset();
- base::AutoLock auto_lock(lock_.Get());
- histograms_ = existing_histograms_.release();
- callbacks_ = existing_callbacks_.release();
- ranges_ = existing_ranges_.release();
- providers_ = existing_providers_.release();
- record_checker_ = existing_record_checker_.release();
+// static
+bool StatisticsRecorder::is_vlog_initialized_ = false;
+
+size_t StatisticsRecorder::BucketRangesHash::operator()(
+ const BucketRanges* const a) const {
+ return a->checksum();
}
-// static
-void StatisticsRecorder::Initialize() {
- // Tests sometimes create local StatisticsRecorders in order to provide a
- // contained environment of histograms that can be later discarded. If a
- // true global instance gets created in this environment then it will
- // eventually get disconnected when the local instance destructs and
- // restores the previous state, resulting in no StatisticsRecorder at all.
- // The global lazy instance, however, will remain valid thus ensuring that
- // another never gets installed via this method. If a |histograms_| map
- // exists then assume the StatisticsRecorder is already "initialized".
- if (histograms_)
- return;
+bool StatisticsRecorder::BucketRangesEqual::operator()(
+ const BucketRanges* const a,
+ const BucketRanges* const b) const {
+ return a->Equals(b);
+}
- // Ensure that an instance of the StatisticsRecorder object is created.
- g_statistics_recorder_.Get();
+StatisticsRecorder::~StatisticsRecorder() {
+ const AutoLock auto_lock(lock_.Get());
+ DCHECK_EQ(this, top_);
+ top_ = previous_;
}
// static
-bool StatisticsRecorder::IsActive() {
- base::AutoLock auto_lock(lock_.Get());
- return histograms_ != nullptr;
+void StatisticsRecorder::EnsureGlobalRecorderWhileLocked() {
+ lock_.Get().AssertAcquired();
+ if (top_)
+ return;
+
+ const StatisticsRecorder* const p = new StatisticsRecorder;
+ // The global recorder is never deleted.
+ ANNOTATE_LEAKING_OBJECT_PTR(p);
+ DCHECK_EQ(p, top_);
}
// static
void StatisticsRecorder::RegisterHistogramProvider(
const WeakPtr<HistogramProvider>& provider) {
- providers_->push_back(provider);
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ top_->providers_.push_back(provider);
}
// static
HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
HistogramBase* histogram) {
- HistogramBase* histogram_to_delete = nullptr;
- HistogramBase* histogram_to_return = nullptr;
- {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_) {
- histogram_to_return = histogram;
-
- // As per crbug.com/79322 the histograms are intentionally leaked, so we
- // need to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used
- // only once for an object, the duplicates should not be annotated.
- // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
- // twice |if (!histograms_)|.
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
- } else {
- const char* name = histogram->histogram_name();
- StringPiece name_piece(name);
- HistogramMap::iterator it = histograms_->find(name_piece);
- if (histograms_->end() == it) {
- // |name_piece| is guaranteed to never change or be deallocated so long
- // as the histogram is alive (which is forever).
- (*histograms_)[name_piece] = histogram;
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
- // If there are callbacks for this histogram, we set the kCallbackExists
- // flag.
- auto callback_iterator = callbacks_->find(name);
- if (callback_iterator != callbacks_->end()) {
- if (!callback_iterator->second.is_null())
- histogram->SetFlags(HistogramBase::kCallbackExists);
- else
- histogram->ClearFlags(HistogramBase::kCallbackExists);
- }
- histogram_to_return = histogram;
- } else if (histogram == it->second) {
- // The histogram was registered before.
- histogram_to_return = histogram;
- } else {
- // We already have one histogram with this name.
- DCHECK_EQ(StringPiece(histogram->histogram_name()),
- StringPiece(it->second->histogram_name()))
- << "hash collision";
- histogram_to_return = it->second;
- histogram_to_delete = histogram;
- }
+ // Declared before |auto_lock| to ensure correct destruction order.
+ std::unique_ptr<HistogramBase> histogram_deleter;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+
+ const char* const name = histogram->histogram_name();
+ HistogramBase*& registered = top_->histograms_[name];
+
+ if (!registered) {
+ // |name| is guaranteed to never change or be deallocated so long
+ // as the histogram is alive (which is forever).
+ registered = histogram;
+ ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
+ // If there are callbacks for this histogram, we set the kCallbackExists
+ // flag.
+ const auto callback_iterator = top_->callbacks_.find(name);
+ if (callback_iterator != top_->callbacks_.end()) {
+ if (!callback_iterator->second.is_null())
+ histogram->SetFlags(HistogramBase::kCallbackExists);
+ else
+ histogram->ClearFlags(HistogramBase::kCallbackExists);
}
+ return histogram;
+ }
+
+ if (histogram == registered) {
+ // The histogram was registered before.
+ return histogram;
}
- delete histogram_to_delete;
- return histogram_to_return;
+
+ // We already have one histogram with this name.
+ histogram_deleter.reset(histogram);
+ return registered;
}
// static
const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
const BucketRanges* ranges) {
DCHECK(ranges->HasValidChecksum());
+
+ // Declared before |auto_lock| to ensure correct destruction order.
std::unique_ptr<const BucketRanges> ranges_deleter;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- base::AutoLock auto_lock(lock_.Get());
- if (!ranges_) {
+ const BucketRanges* const registered = *top_->ranges_.insert(ranges).first;
+ if (registered == ranges) {
ANNOTATE_LEAKING_OBJECT_PTR(ranges);
- return ranges;
- }
-
- std::list<const BucketRanges*>* checksum_matching_list;
- RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
- if (ranges_->end() == ranges_it) {
- // Add a new matching list to map.
- checksum_matching_list = new std::list<const BucketRanges*>();
- ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
- (*ranges_)[ranges->checksum()] = checksum_matching_list;
} else {
- checksum_matching_list = ranges_it->second;
+ ranges_deleter.reset(ranges);
}
- for (const BucketRanges* existing_ranges : *checksum_matching_list) {
- if (existing_ranges->Equals(ranges)) {
- if (existing_ranges == ranges) {
- return ranges;
- } else {
- ranges_deleter.reset(ranges);
- return existing_ranges;
- }
- }
- }
- // We haven't found a BucketRanges which has the same ranges. Register the
- // new BucketRanges.
- checksum_matching_list->push_front(ranges);
- return ranges;
+ return registered;
}
// static
void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
std::string* output) {
- if (!IsActive())
- return;
-
- Histograms snapshot;
- GetSnapshot(query, &snapshot);
- std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
- for (const HistogramBase* histogram : snapshot) {
+ for (const HistogramBase* const histogram : GetSnapshot(query)) {
histogram->WriteHTMLGraph(output);
- output->append("<br><hr><br>");
+ *output += "<br><hr><br>";
}
}
// static
void StatisticsRecorder::WriteGraph(const std::string& query,
std::string* output) {
- if (!IsActive())
- return;
if (query.length())
StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
else
output->append("Collections of all histograms\n");
- Histograms snapshot;
- GetSnapshot(query, &snapshot);
- std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
- for (const HistogramBase* histogram : snapshot) {
+ for (const HistogramBase* const histogram : GetSnapshot(query)) {
histogram->WriteAscii(output);
output->append("\n");
}
@@ -205,19 +159,11 @@ void StatisticsRecorder::WriteGraph(const std::string& query,
// static
std::string StatisticsRecorder::ToJSON(JSONVerbosityLevel verbosity_level) {
- if (!IsActive())
- return std::string();
-
- std::string output("{");
- Histograms snapshot;
- GetSnapshot(std::string(), &snapshot);
- output += "\"histograms\":[";
- bool first_histogram = true;
- for (const HistogramBase* histogram : snapshot) {
- if (first_histogram)
- first_histogram = false;
- else
- output += ",";
+ std::string output = "{\"histograms\":[";
+ const char* sep = "";
+ for (const HistogramBase* const histogram : GetHistograms()) {
+ output += sep;
+ sep = ",";
std::string json;
histogram->WriteJSON(&json, verbosity_level);
output += json;
@@ -227,28 +173,13 @@ std::string StatisticsRecorder::ToJSON(JSONVerbosityLevel verbosity_level) {
}
// static
-void StatisticsRecorder::GetHistograms(Histograms* output) {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return;
-
- for (const auto& entry : *histograms_) {
- output->push_back(entry.second);
- }
-}
-
-// static
-void StatisticsRecorder::GetBucketRanges(
- std::vector<const BucketRanges*>* output) {
- base::AutoLock auto_lock(lock_.Get());
- if (!ranges_)
- return;
-
- for (const auto& entry : *ranges_) {
- for (auto* range_entry : *entry.second) {
- output->push_back(range_entry);
- }
- }
+std::vector<const BucketRanges*> StatisticsRecorder::GetBucketRanges() {
+ std::vector<const BucketRanges*> out;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ out.reserve(top_->ranges_.size());
+ out.assign(top_->ranges_.begin(), top_->ranges_.end());
+ return out;
}
// static
@@ -258,23 +189,25 @@ HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
// will acquire the lock at that time.
ImportGlobalPersistentHistograms();
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return nullptr;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- HistogramMap::iterator it = histograms_->find(name);
- if (histograms_->end() == it)
- return nullptr;
- return it->second;
+ const HistogramMap::const_iterator it = top_->histograms_.find(name);
+ return it != top_->histograms_.end() ? it->second : nullptr;
}
// static
-void StatisticsRecorder::ImportProvidedHistograms() {
- if (!providers_)
- return;
+StatisticsRecorder::HistogramProviders
+StatisticsRecorder::GetHistogramProviders() {
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ return top_->providers_;
+}
+// static
+void StatisticsRecorder::ImportProvidedHistograms() {
// Merge histogram data from each provider in turn.
- for (const WeakPtr<HistogramProvider>& provider : *providers_) {
+ for (const WeakPtr<HistogramProvider>& provider : GetHistogramProviders()) {
// Weak-pointer may be invalid if the provider was destructed, though they
// generally never are.
if (provider)
@@ -288,42 +221,14 @@ void StatisticsRecorder::PrepareDeltas(
HistogramBase::Flags flags_to_set,
HistogramBase::Flags required_flags,
HistogramSnapshotManager* snapshot_manager) {
- if (include_persistent)
- ImportGlobalPersistentHistograms();
-
- auto known = GetKnownHistograms(include_persistent);
- snapshot_manager->PrepareDeltas(known.begin(), known.end(), flags_to_set,
- required_flags);
+ snapshot_manager->PrepareDeltas(GetKnownHistograms(include_persistent),
+ flags_to_set, required_flags);
}
// static
void StatisticsRecorder::InitLogOnShutdown() {
- if (!histograms_)
- return;
-
- base::AutoLock auto_lock(lock_.Get());
- g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock();
-}
-
-// static
-void StatisticsRecorder::GetSnapshot(const std::string& query,
- Histograms* snapshot) {
- // This must be called *before* the lock is acquired below because it will
- // call back into this object to register histograms. Those called methods
- // will acquire the lock at that time.
- ImportGlobalPersistentHistograms();
-
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return;
-
- // Need a c-string query for comparisons against c-string histogram name.
- const char* query_string = query.c_str();
-
- for (const auto& entry : *histograms_) {
- if (strstr(entry.second->histogram_name(), query_string) != nullptr)
- snapshot->push_back(entry.second);
- }
+ const AutoLock auto_lock(lock_.Get());
+ InitLogOnShutdownWhileLocked();
}
// static
@@ -331,16 +236,14 @@ bool StatisticsRecorder::SetCallback(
const std::string& name,
const StatisticsRecorder::OnSampleCallback& cb) {
DCHECK(!cb.is_null());
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return false;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- if (ContainsKey(*callbacks_, name))
+ if (!top_->callbacks_.insert({name, cb}).second)
return false;
- callbacks_->insert(std::make_pair(name, cb));
- auto it = histograms_->find(name);
- if (it != histograms_->end())
+ const HistogramMap::const_iterator it = top_->histograms_.find(name);
+ if (it != top_->histograms_.end())
it->second->SetFlags(HistogramBase::kCallbackExists);
return true;
@@ -348,199 +251,162 @@ bool StatisticsRecorder::SetCallback(
// static
void StatisticsRecorder::ClearCallback(const std::string& name) {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- callbacks_->erase(name);
+ top_->callbacks_.erase(name);
// We also clear the flag from the histogram (if it exists).
- auto it = histograms_->find(name);
- if (it != histograms_->end())
+ const HistogramMap::const_iterator it = top_->histograms_.find(name);
+ if (it != top_->histograms_.end())
it->second->ClearFlags(HistogramBase::kCallbackExists);
}
// static
StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
const std::string& name) {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return OnSampleCallback();
-
- auto callback_iterator = callbacks_->find(name);
- return callback_iterator != callbacks_->end() ? callback_iterator->second
- : OnSampleCallback();
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ const auto it = top_->callbacks_.find(name);
+ return it != top_->callbacks_.end() ? it->second : OnSampleCallback();
}
// static
size_t StatisticsRecorder::GetHistogramCount() {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return 0;
- return histograms_->size();
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ return top_->histograms_.size();
}
// static
void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) {
- if (!histograms_)
- return;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- HistogramMap::iterator found = histograms_->find(name);
- if (found == histograms_->end())
+ const HistogramMap::iterator found = top_->histograms_.find(name);
+ if (found == top_->histograms_.end())
return;
- HistogramBase* base = found->second;
+ HistogramBase* const base = found->second;
if (base->GetHistogramType() != SPARSE_HISTOGRAM) {
// When forgetting a histogram, it's likely that other information is
// also becoming invalid. Clear the persistent reference that may no
// longer be valid. There's no danger in this as, at worst, duplicates
// will be created in persistent memory.
- Histogram* histogram = static_cast<Histogram*>(base);
- histogram->bucket_ranges()->set_persistent_reference(0);
+ static_cast<Histogram*>(base)->bucket_ranges()->set_persistent_reference(0);
}
- histograms_->erase(found);
+ top_->histograms_.erase(found);
}
// static
std::unique_ptr<StatisticsRecorder>
StatisticsRecorder::CreateTemporaryForTesting() {
+ const AutoLock auto_lock(lock_.Get());
return WrapUnique(new StatisticsRecorder());
}
// static
-void StatisticsRecorder::UninitializeForTesting() {
- // Stop now if it's never been initialized.
- if (!histograms_)
- return;
-
- // Get the global instance and destruct it. It's held in static memory so
- // can't "delete" it; call the destructor explicitly.
- DCHECK(g_statistics_recorder_.private_instance_);
- g_statistics_recorder_.Get().~StatisticsRecorder();
-
- // Now the ugly part. There's no official way to release a LazyInstance once
- // created so it's necessary to clear out an internal variable which
- // shouldn't be publicly visible but is for initialization reasons.
- g_statistics_recorder_.private_instance_ = 0;
-}
-
-// static
void StatisticsRecorder::SetRecordChecker(
std::unique_ptr<RecordHistogramChecker> record_checker) {
- record_checker_ = record_checker.release();
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ top_->record_checker_ = std::move(record_checker);
}
// static
bool StatisticsRecorder::ShouldRecordHistogram(uint64_t histogram_hash) {
- return !record_checker_ || record_checker_->ShouldRecord(histogram_hash);
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ return !top_->record_checker_ ||
+ top_->record_checker_->ShouldRecord(histogram_hash);
}
// static
-std::vector<HistogramBase*> StatisticsRecorder::GetKnownHistograms(
- bool include_persistent) {
- std::vector<HistogramBase*> known;
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_ || histograms_->empty())
- return known;
-
- known.reserve(histograms_->size());
- for (const auto& h : *histograms_) {
- if (!include_persistent &&
- (h.second->flags() & HistogramBase::kIsPersistent)) {
- continue;
+template <typename Predicate>
+StatisticsRecorder::Histograms StatisticsRecorder::GetHistogramsWithPredicate(
+ const Predicate predicate) {
+ // This must be called *before* the lock is acquired below because it will
+ // call back into this object to register histograms. Those called methods
+ // will acquire the lock at that time.
+ ImportGlobalPersistentHistograms();
+
+ Histograms out;
+
+ {
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ out.reserve(top_->histograms_.size());
+ for (const auto& entry : top_->histograms_) {
+ const HistogramBase* const histogram = entry.second;
+ DCHECK(histogram);
+ if (predicate(*histogram))
+ out.push_back(entry.second);
}
- known.push_back(h.second);
}
- return known;
+ std::sort(out.begin(), out.end(), &HistogramNameLesser);
+ return out;
}
// static
-void StatisticsRecorder::ImportGlobalPersistentHistograms() {
- if (!histograms_)
- return;
-
- // Import histograms from known persistent storage. Histograms could have
- // been added by other processes and they must be fetched and recognized
- // locally. If the persistent memory segment is not shared between processes,
- // this call does nothing.
- GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
- if (allocator)
- allocator->ImportHistogramsToStatisticsRecorder();
+StatisticsRecorder::Histograms StatisticsRecorder::GetHistograms() {
+ return GetHistogramsWithPredicate([](const HistogramBase&) { return true; });
}
-// This singleton instance should be started during the single threaded portion
-// of main(), and hence it is not thread safe. It initializes globals to
-// provide support for all future calls.
-StatisticsRecorder::StatisticsRecorder() {
- base::AutoLock auto_lock(lock_.Get());
-
- existing_histograms_.reset(histograms_);
- existing_callbacks_.reset(callbacks_);
- existing_ranges_.reset(ranges_);
- existing_providers_.reset(providers_);
- existing_record_checker_.reset(record_checker_);
-
- histograms_ = new HistogramMap;
- callbacks_ = new CallbackMap;
- ranges_ = new RangesMap;
- providers_ = new HistogramProviders;
- record_checker_ = nullptr;
-
- InitLogOnShutdownWithoutLock();
-}
-
-void StatisticsRecorder::InitLogOnShutdownWithoutLock() {
- if (!vlog_initialized_ && VLOG_IS_ON(1)) {
- vlog_initialized_ = true;
- AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
- }
+// static
+StatisticsRecorder::Histograms StatisticsRecorder::GetKnownHistograms(
+ bool include_persistent) {
+ return GetHistogramsWithPredicate(
+ [include_persistent](const HistogramBase& histogram) {
+ return include_persistent ||
+ (histogram.flags() & HistogramBase::kIsPersistent) == 0;
+ });
}
// static
-void StatisticsRecorder::Reset() {
- std::unique_ptr<HistogramMap> histograms_deleter;
- std::unique_ptr<CallbackMap> callbacks_deleter;
- std::unique_ptr<RangesMap> ranges_deleter;
- std::unique_ptr<HistogramProviders> providers_deleter;
- std::unique_ptr<RecordHistogramChecker> record_checker_deleter;
- {
- base::AutoLock auto_lock(lock_.Get());
- histograms_deleter.reset(histograms_);
- callbacks_deleter.reset(callbacks_);
- ranges_deleter.reset(ranges_);
- providers_deleter.reset(providers_);
- record_checker_deleter.reset(record_checker_);
- histograms_ = nullptr;
- callbacks_ = nullptr;
- ranges_ = nullptr;
- providers_ = nullptr;
- record_checker_ = nullptr;
- }
- // We are going to leak the histograms and the ranges.
+StatisticsRecorder::Histograms StatisticsRecorder::GetSnapshot(
+ const std::string& query) {
+ // Need a C-string query for comparisons against C-string histogram name.
+ const char* const query_string = query.c_str();
+ return GetHistogramsWithPredicate(
+ [query_string](const HistogramBase& histogram) {
+ return strstr(histogram.histogram_name(), query_string) != nullptr;
+ });
}
// static
-void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
- std::string output;
- StatisticsRecorder::WriteGraph(std::string(), &output);
- VLOG(1) << output;
+void StatisticsRecorder::ImportGlobalPersistentHistograms() {
+ // Import histograms from known persistent storage. Histograms could have been
+ // added by other processes and they must be fetched and recognized locally.
+ // If the persistent memory segment is not shared between processes, this call
+ // does nothing.
+ if (GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get())
+ allocator->ImportHistogramsToStatisticsRecorder();
}
-
-// static
-StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = nullptr;
-// static
-StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = nullptr;
-// static
-StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = nullptr;
-// static
-StatisticsRecorder::HistogramProviders* StatisticsRecorder::providers_;
-// static
-RecordHistogramChecker* StatisticsRecorder::record_checker_ = nullptr;
-// static
-base::LazyInstance<base::Lock>::Leaky StatisticsRecorder::lock_ =
- LAZY_INSTANCE_INITIALIZER;
+// This singleton instance should be started during the single threaded portion
+// of main(), and hence it is not thread safe. It initializes globals to provide
+// support for all future calls.
+StatisticsRecorder::StatisticsRecorder() {
+ lock_.Get().AssertAcquired();
+ previous_ = top_;
+ top_ = this;
+ InitLogOnShutdownWhileLocked();
+}
+
+// static
+void StatisticsRecorder::InitLogOnShutdownWhileLocked() {
+ lock_.Get().AssertAcquired();
+ if (!is_vlog_initialized_ && VLOG_IS_ON(1)) {
+ is_vlog_initialized_ = true;
+ const auto dump_to_vlog = [](void*) {
+ std::string output;
+ WriteGraph("", &output);
+ VLOG(1) << output;
+ };
+ AtExitManager::RegisterCallback(dump_to_vlog, nullptr);
+ }
+}
} // namespace base
diff --git a/chromium/base/metrics/statistics_recorder.h b/chromium/base/metrics/statistics_recorder.h
index 49ccaf51917..c994b7e257d 100644
--- a/chromium/base/metrics/statistics_recorder.h
+++ b/chromium/base/metrics/statistics_recorder.h
@@ -12,10 +12,10 @@
#include <stdint.h>
-#include <list>
-#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "base/base_export.h"
@@ -34,37 +34,19 @@ namespace base {
class BucketRanges;
class HistogramSnapshotManager;
+// In-memory recorder of usage statistics (aka metrics, aka histograms).
+//
+// All the public methods are static and act on a global recorder. This global
+// recorder is internally synchronized and all the static methods are thread
+// safe.
+//
+// StatisticsRecorder doesn't have any public constructor. For testing purpose,
+// you can create a temporary recorder using the factory method
+// CreateTemporaryForTesting(). This temporary recorder becomes the global one
+// until deleted. When this temporary recorder is deleted, it restores the
+// previous global one.
class BASE_EXPORT StatisticsRecorder {
public:
- // A class used as a key for the histogram map below. It always references
- // a string owned outside of this class, likely in the value of the map.
- class StringKey : public StringPiece {
- public:
- // Constructs the StringKey using various sources. The source must live
- // at least as long as the created object.
- StringKey(const std::string& str) : StringPiece(str) {}
- StringKey(StringPiece str) : StringPiece(str) {}
-
- // Though StringPiece is better passed by value than by reference, in
- // this case it's being passed many times and likely already been stored
- // in memory (not just registers) so the benefit of pass-by-value is
- // negated.
- bool operator<(const StringKey& rhs) const {
- // Since order is unimportant in the map and string comparisons can be
- // slow, use the length as the primary sort value.
- if (length() < rhs.length())
- return true;
- if (length() > rhs.length())
- return false;
-
- // Fall back to an actual string comparison. The lengths are the same
- // so a simple memory-compare is sufficient. This is slightly more
- // efficient than calling operator<() for StringPiece which would
- // again have to check lengths before calling wordmemcmp().
- return wordmemcmp(data(), rhs.data(), length()) < 0;
- }
- };
-
// An interface class that allows the StatisticsRecorder to forcibly merge
// histograms from providers when necessary.
class HistogramProvider {
@@ -73,58 +55,82 @@ class BASE_EXPORT StatisticsRecorder {
virtual void MergeHistogramDeltas() = 0;
};
- typedef std::map<StringKey, HistogramBase*> HistogramMap;
typedef std::vector<HistogramBase*> Histograms;
- typedef std::vector<WeakPtr<HistogramProvider>> HistogramProviders;
+ // Restores the previous global recorder.
+ //
+ // When several temporary recorders are created using
+ // CreateTemporaryForTesting(), these recorders must be deleted in reverse
+ // order of creation.
+ //
+ // This method is thread safe.
+ //
+ // Precondition: The recorder being deleted is the current global recorder.
~StatisticsRecorder();
- // Initializes the StatisticsRecorder system. Safe to call multiple times.
- static void Initialize();
-
- // Find out if histograms can now be registered into our list.
- static bool IsActive();
-
- // Register a provider of histograms that can be called to merge those into
- // the global StatisticsRecorder. Calls to ImportProvidedHistograms() will
- // fetch from registered providers.
+ // Registers a provider of histograms that can be called to merge those into
+ // the global recorder. Calls to ImportProvidedHistograms() will fetch from
+ // registered providers.
+ //
+ // This method is thread safe.
static void RegisterHistogramProvider(
const WeakPtr<HistogramProvider>& provider);
- // Register, or add a new histogram to the collection of statistics. If an
+ // Registers or adds a new histogram to the collection of statistics. If an
// identically named histogram is already registered, then the argument
- // |histogram| will deleted. The returned value is always the registered
+ // |histogram| will be deleted. The returned value is always the registered
// histogram (either the argument, or the pre-existing registered histogram).
+ //
+ // This method is thread safe.
static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);
- // Register, or add a new BucketRanges. If an identically BucketRanges is
- // already registered, then the argument |ranges| will deleted. The returned
- // value is always the registered BucketRanges (either the argument, or the
- // pre-existing one).
+ // Registers or adds a new BucketRanges. If an equivalent BucketRanges is
+ // already registered, then the argument |ranges| will be deleted. The
+ // returned value is always the registered BucketRanges (either the argument,
+ // or the pre-existing one).
+ //
+ // This method is thread safe.
static const BucketRanges* RegisterOrDeleteDuplicateRanges(
const BucketRanges* ranges);
// Methods for appending histogram data to a string. Only histograms which
// have |query| as a substring are written to |output| (an empty string will
// process all registered histograms).
+ //
+ // These methods are thread safe.
static void WriteHTMLGraph(const std::string& query, std::string* output);
static void WriteGraph(const std::string& query, std::string* output);
// Returns the histograms with |verbosity_level| as the serialization
// verbosity.
+ //
+ // This method is thread safe.
static std::string ToJSON(JSONVerbosityLevel verbosity_level);
- // Method for extracting histograms which were marked for use by UMA.
- static void GetHistograms(Histograms* output);
-
- // Method for extracting BucketRanges used by all histograms registered.
- static void GetBucketRanges(std::vector<const BucketRanges*>* output);
-
- // Find a histogram by name. It matches the exact name. This method is thread
- // safe. It returns NULL if a matching histogram is not found.
+ // Gets existing histograms.
+ //
+ // The returned histograms are sorted by name.
+ //
+ // Ownership of the individual histograms remains with the StatisticsRecorder.
+ //
+ // This method is thread safe.
+ static Histograms GetHistograms();
+
+ // Gets BucketRanges used by all histograms registered. The order of returned
+ // BucketRanges is not guaranteed.
+ //
+ // This method is thread safe.
+ static std::vector<const BucketRanges*> GetBucketRanges();
+
+ // Finds a histogram by name. Matches the exact name. Returns a null pointer
+ // if a matching histogram is not found.
+ //
+ // This method is thread safe.
static HistogramBase* FindHistogram(base::StringPiece name);
- // Imports histograms from providers. This must be called on the UI thread.
+ // Imports histograms from providers.
+ //
+ // This method must be called on the UI thread.
static void ImportProvidedHistograms();
// Snapshots all histograms via |snapshot_manager|. |flags_to_set| is used to
@@ -137,128 +143,180 @@ class BASE_EXPORT StatisticsRecorder {
HistogramBase::Flags required_flags,
HistogramSnapshotManager* snapshot_manager);
- // GetSnapshot copies some of the pointers to registered histograms into the
- // caller supplied vector (Histograms). Only histograms which have |query| as
- // a substring are copied (an empty string will process all registered
- // histograms).
- static void GetSnapshot(const std::string& query, Histograms* snapshot);
+ // Gets registered histograms. Only histograms which have |query| as a
+ // substring in their name are extracted. An empty query returns all
+ // registered histograms.
+ //
+ // The returned histograms are sorted by name.
+ //
+ // Ownership of the individual histograms remains with the StatisticsRecorder.
+ //
+ // This method is thread safe.
+ static Histograms GetSnapshot(const std::string& query);
typedef base::Callback<void(HistogramBase::Sample)> OnSampleCallback;
- // SetCallback sets the callback to notify when a new sample is recorded on
- // the histogram referred to by |histogram_name|. The call to this method can
- // be be done before or after the histogram is created. This method is thread
- // safe. The return value is whether or not the callback was successfully set.
+ // Sets the callback to notify when a new sample is recorded on the histogram
+ // referred to by |histogram_name|. Can be called before or after the
+ // histogram is created. Returns whether the callback was successfully set.
+ //
+ // This method is thread safe.
static bool SetCallback(const std::string& histogram_name,
const OnSampleCallback& callback);
- // ClearCallback clears any callback set on the histogram referred to by
- // |histogram_name|. This method is thread safe.
+ // Clears any callback set on the histogram referred to by |histogram_name|.
+ //
+ // This method is thread safe.
static void ClearCallback(const std::string& histogram_name);
- // FindCallback retrieves the callback for the histogram referred to by
- // |histogram_name|, or a null callback if no callback exists for this
- // histogram. This method is thread safe.
+ // Retrieves the callback for the histogram referred to by |histogram_name|,
+ // or a null callback if no callback exists for this histogram.
+ //
+ // This method is thread safe.
static OnSampleCallback FindCallback(const std::string& histogram_name);
// Returns the number of known histograms.
+ //
+ // This method is thread safe.
static size_t GetHistogramCount();
// Initializes logging histograms with --v=1. Safe to call multiple times.
// Is called from ctor but for browser it seems that it is more useful to
// start logging after statistics recorder, so we need to init log-on-shutdown
// later.
+ //
+ // This method is thread safe.
static void InitLogOnShutdown();
// Removes a histogram from the internal set of known ones. This can be
// necessary during testing persistent histograms where the underlying
// memory is being released.
+ //
+ // This method is thread safe.
static void ForgetHistogramForTesting(base::StringPiece name);
- // Creates a local StatisticsRecorder object for testing purposes. All new
- // histograms will be registered in it until it is destructed or pushed
- // aside for the lifetime of yet another SR object. The destruction of the
- // returned object will re-activate the previous one. Always release SR
- // objects in the opposite order to which they're created.
+ // Creates a temporary StatisticsRecorder object for testing purposes. All new
+ // histograms will be registered in it until it is destructed or pushed aside
+ // for the lifetime of yet another StatisticsRecorder object. The destruction
+ // of the returned object will re-activate the previous one.
+ // StatisticsRecorder objects must be deleted in the opposite order to which
+ // they're created.
+ //
+ // This method is thread safe.
static std::unique_ptr<StatisticsRecorder> CreateTemporaryForTesting()
WARN_UNUSED_RESULT;
- // Resets any global instance of the statistics-recorder that was created
- // by a call to Initialize().
- static void UninitializeForTesting();
-
// Sets the record checker for determining if a histogram should be recorded.
// Record checker doesn't affect any already recorded histograms, so this
// method must be called very early, before any threads have started.
// Record checker methods can be called on any thread, so they shouldn't
// mutate any state.
+ //
// TODO(iburak): This is not yet hooked up to histogram recording
// infrastructure.
static void SetRecordChecker(
std::unique_ptr<RecordHistogramChecker> record_checker);
- // Returns true iff the given histogram should be recorded based on
- // the ShouldRecord() method of the record checker.
- // If the record checker is not set, returns true.
+ // Checks if the given histogram should be recorded based on the
+ // ShouldRecord() method of the record checker. If the record checker is not
+ // set, returns true.
+ //
+ // This method is thread safe.
static bool ShouldRecordHistogram(uint64_t histogram_hash);
private:
+ typedef std::vector<WeakPtr<HistogramProvider>> HistogramProviders;
+
+ typedef std::unordered_map<StringPiece, HistogramBase*, StringPieceHash>
+ HistogramMap;
+
// We keep a map of callbacks to histograms, so that as histograms are
// created, we can set the callback properly.
- typedef std::map<std::string, OnSampleCallback> CallbackMap;
+ typedef std::unordered_map<std::string, OnSampleCallback> CallbackMap;
+
+ struct BucketRangesHash {
+ size_t operator()(const BucketRanges* a) const;
+ };
+
+ struct BucketRangesEqual {
+ bool operator()(const BucketRanges* a, const BucketRanges* b) const;
+ };
- // We keep all |bucket_ranges_| in a map, from checksum to a list of
- // |bucket_ranges_|. Checksum is calculated from the |ranges_| in
- // |bucket_ranges_|.
- typedef std::map<uint32_t, std::list<const BucketRanges*>*> RangesMap;
+ typedef std::
+ unordered_set<const BucketRanges*, BucketRangesHash, BucketRangesEqual>
+ RangesMap;
- friend struct LazyInstanceTraitsBase<StatisticsRecorder>;
friend class StatisticsRecorderTest;
FRIEND_TEST_ALL_PREFIXES(StatisticsRecorderTest, IterationTest);
- // Fetch set of existing histograms. Ownership of the individual histograms
- // remains with the StatisticsRecorder.
- static std::vector<HistogramBase*> GetKnownHistograms(
- bool include_persistent);
-
- // Imports histograms from global persistent memory. The global lock must
- // not be held during this call.
+ // Initializes the global recorder if it doesn't already exist. Safe to call
+ // multiple times.
+ //
+ // Precondition: The global lock is already acquired.
+ static void EnsureGlobalRecorderWhileLocked();
+
+ // Gets existing histograms matching |predicate|. |Predicate| must have the
+ // signature bool(const HistogramBase&).
+ //
+ // The returned histograms are sorted by name.
+ //
+ // Ownership of the individual histograms remains with the StatisticsRecorder.
+ //
+ // This method is thread safe.
+ template <typename Predicate>
+ static Histograms GetHistogramsWithPredicate(Predicate predicate);
+
+ // Gets existing histograms.
+ //
+ // The returned histograms are sorted by name.
+ //
+ // Ownership of the individual histograms remains with the StatisticsRecorder.
+ //
+ // This method is thread safe.
+ static Histograms GetKnownHistograms(bool include_persistent);
+
+ // Gets histogram providers.
+ //
+ // This method is thread safe.
+ static HistogramProviders GetHistogramProviders();
+
+ // Imports histograms from global persistent memory.
+ //
+ // Precondition: The global lock must not be held during this call.
static void ImportGlobalPersistentHistograms();
- // The constructor just initializes static members. Usually client code should
- // use Initialize to do this. But in test code, you can friend this class and
- // call the constructor to get a clean StatisticsRecorder.
+ // Constructs a new StatisticsRecorder and sets it as the current global
+ // recorder.
+ //
+ // Precondition: The global lock is already acquired.
StatisticsRecorder();
// Initialize implementation but without lock. Caller should guard
// StatisticsRecorder by itself if needed (it isn't in unit tests).
- void InitLogOnShutdownWithoutLock();
-
- // These are copies of everything that existed when the (test) Statistics-
- // Recorder was created. The global ones have to be moved aside to create a
- // clean environment.
- std::unique_ptr<HistogramMap> existing_histograms_;
- std::unique_ptr<CallbackMap> existing_callbacks_;
- std::unique_ptr<RangesMap> existing_ranges_;
- std::unique_ptr<HistogramProviders> existing_providers_;
- std::unique_ptr<RecordHistogramChecker> existing_record_checker_;
-
- bool vlog_initialized_ = false;
-
- static void Reset();
- static void DumpHistogramsToVlog(void* instance);
-
- static HistogramMap* histograms_;
- static CallbackMap* callbacks_;
- static RangesMap* ranges_;
- static HistogramProviders* providers_;
- static RecordHistogramChecker* record_checker_;
-
- // Lock protects access to above maps. This is a LazyInstance to avoid races
- // when the above methods are used before Initialize(). Previously each method
- // would do |if (!lock_) return;| which would race with
- // |lock_ = new Lock;| in StatisticsRecorder(). http://crbug.com/672852.
- static base::LazyInstance<base::Lock>::Leaky lock_;
+ //
+ // Precondition: The global lock is already acquired.
+ static void InitLogOnShutdownWhileLocked();
+
+ HistogramMap histograms_;
+ CallbackMap callbacks_;
+ RangesMap ranges_;
+ HistogramProviders providers_;
+ std::unique_ptr<RecordHistogramChecker> record_checker_;
+
+ // Previous global recorder that existed when this one was created.
+ StatisticsRecorder* previous_ = nullptr;
+
+ // Global lock for internal synchronization.
+ static LazyInstance<Lock>::Leaky lock_;
+
+ // Current global recorder. This recorder is used by static methods. When a
+ // new global recorder is created by CreateTemporaryForTesting(), then the
+ // previous global recorder is referenced by top_->previous_.
+ static StatisticsRecorder* top_;
+
+ // Tracks whether InitLogOnShutdownWhileLocked() has registered a logging
+ // function that will be called when the program finishes.
+ static bool is_vlog_initialized_;
DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
};
diff --git a/chromium/base/metrics/statistics_recorder_unittest.cc b/chromium/base/metrics/statistics_recorder_unittest.cc
index 92d1bba602e..79ab7bf6b13 100644
--- a/chromium/base/metrics/statistics_recorder_unittest.cc
+++ b/chromium/base/metrics/statistics_recorder_unittest.cc
@@ -20,6 +20,7 @@
#include "base/metrics/record_histogram_checker.h"
#include "base/metrics/sparse_histogram.h"
#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -30,9 +31,7 @@ class LogStateSaver {
public:
LogStateSaver() : old_min_log_level_(logging::GetMinLogLevel()) {}
- ~LogStateSaver() {
- logging::SetMinLogLevel(old_min_log_level_);
- }
+ ~LogStateSaver() { logging::SetMinLogLevel(old_min_log_level_); }
private:
int old_min_log_level_;
@@ -55,6 +54,11 @@ class OddRecordHistogramChecker : public base::RecordHistogramChecker {
namespace base {
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+
class StatisticsRecorderTest : public testing::TestWithParam<bool> {
protected:
const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB
@@ -70,8 +74,8 @@ class StatisticsRecorderTest : public testing::TestWithParam<bool> {
// Use persistent memory for histograms if so indicated by test parameter.
if (use_persistent_histogram_allocator_) {
- GlobalHistogramAllocator::CreateWithLocalMemory(
- kAllocatorMemorySize, 0, "StatisticsRecorderTest");
+ GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0,
+ "StatisticsRecorderTest");
}
}
@@ -82,15 +86,19 @@ class StatisticsRecorderTest : public testing::TestWithParam<bool> {
void InitializeStatisticsRecorder() {
DCHECK(!statistics_recorder_);
- StatisticsRecorder::UninitializeForTesting();
statistics_recorder_ = StatisticsRecorder::CreateTemporaryForTesting();
}
+ // Deletes the global recorder if there is any. This is used by test
+ // NotInitialized to ensure a clean global state.
void UninitializeStatisticsRecorder() {
statistics_recorder_.reset();
- StatisticsRecorder::UninitializeForTesting();
+ delete StatisticsRecorder::top_;
+ DCHECK(!StatisticsRecorder::top_);
}
+ bool HasGlobalRecorder() { return StatisticsRecorder::top_ != nullptr; }
+
Histogram* CreateHistogram(const char* name,
HistogramBase::Sample min,
HistogramBase::Sample max,
@@ -102,18 +110,13 @@ class StatisticsRecorderTest : public testing::TestWithParam<bool> {
return new Histogram(name, min, max, registered_ranges);
}
- void DeleteHistogram(HistogramBase* histogram) {
- delete histogram;
- }
+ void InitLogOnShutdown() { StatisticsRecorder::InitLogOnShutdown(); }
- void InitLogOnShutdown() {
- DCHECK(statistics_recorder_);
- statistics_recorder_->InitLogOnShutdownWithoutLock();
- }
+ bool IsVLogInitialized() { return StatisticsRecorder::is_vlog_initialized_; }
- bool VLogInitialized() {
- DCHECK(statistics_recorder_);
- return statistics_recorder_->vlog_initialized_;
+ void ResetVLogInitialized() {
+ UninitializeStatisticsRecorder();
+ StatisticsRecorder::is_vlog_initialized_ = false;
}
const bool use_persistent_histogram_allocator_;
@@ -132,30 +135,25 @@ INSTANTIATE_TEST_CASE_P(Allocator, StatisticsRecorderTest, testing::Bool());
TEST_P(StatisticsRecorderTest, NotInitialized) {
UninitializeStatisticsRecorder();
+ EXPECT_FALSE(HasGlobalRecorder());
- ASSERT_FALSE(StatisticsRecorder::IsActive());
+ HistogramBase* const histogram =
+ CreateHistogram("TestHistogram", 1, 1000, 10);
+ EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicate(histogram),
+ histogram);
+ EXPECT_TRUE(HasGlobalRecorder());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), ElementsAre(histogram));
- StatisticsRecorder::Histograms registered_histograms;
- std::vector<const BucketRanges*> registered_ranges;
-
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(0u, registered_histograms.size());
-
- Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
-
- // When StatisticsRecorder is not initialized, register is a noop.
- EXPECT_EQ(histogram,
- StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
- // Manually delete histogram that was not registered.
- DeleteHistogram(histogram);
+ UninitializeStatisticsRecorder();
+ EXPECT_FALSE(HasGlobalRecorder());
- // RegisterOrDeleteDuplicateRanges is a no-op.
- BucketRanges* ranges = new BucketRanges(3);
+ BucketRanges* const ranges = new BucketRanges(3);
ranges->ResetChecksum();
- EXPECT_EQ(ranges,
- StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
- StatisticsRecorder::GetBucketRanges(&registered_ranges);
- EXPECT_EQ(0u, registered_ranges.size());
+ EXPECT_EQ(StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges),
+ ranges);
+ EXPECT_TRUE(HasGlobalRecorder());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(),
+ UnorderedElementsAre(ranges));
}
TEST_P(StatisticsRecorderTest, RegisterBucketRanges) {
@@ -171,15 +169,15 @@ TEST_P(StatisticsRecorderTest, RegisterBucketRanges) {
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
EXPECT_EQ(ranges2,
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2));
- StatisticsRecorder::GetBucketRanges(&registered_ranges);
- ASSERT_EQ(2u, registered_ranges.size());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(),
+ UnorderedElementsAre(ranges1, ranges2));
// Register some ranges again.
EXPECT_EQ(ranges1,
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
- registered_ranges.clear();
- StatisticsRecorder::GetBucketRanges(&registered_ranges);
- ASSERT_EQ(2u, registered_ranges.size());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(),
+ UnorderedElementsAre(ranges1, ranges2));
+
// Make sure the ranges is still the one we know.
ASSERT_EQ(3u, ranges1->size());
EXPECT_EQ(0, ranges1->range(0));
@@ -191,31 +189,40 @@ TEST_P(StatisticsRecorderTest, RegisterBucketRanges) {
ranges3->ResetChecksum();
EXPECT_EQ(ranges1, // returning ranges1
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
- registered_ranges.clear();
- StatisticsRecorder::GetBucketRanges(&registered_ranges);
- ASSERT_EQ(2u, registered_ranges.size());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(),
+ UnorderedElementsAre(ranges1, ranges2));
}
TEST_P(StatisticsRecorderTest, RegisterHistogram) {
// Create a Histogram that was not registered.
- Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
+ Histogram* const histogram1 = CreateHistogram("TestHistogram1", 1, 1000, 10);
- StatisticsRecorder::Histograms registered_histograms;
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(0u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), IsEmpty());
// Register the Histogram.
- EXPECT_EQ(histogram,
- StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(1u, registered_histograms.size());
+ EXPECT_EQ(histogram1,
+ StatisticsRecorder::RegisterOrDeleteDuplicate(histogram1));
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), ElementsAre(histogram1));
// Register the same Histogram again.
- EXPECT_EQ(histogram,
- StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(1u, registered_histograms.size());
+ EXPECT_EQ(histogram1,
+ StatisticsRecorder::RegisterOrDeleteDuplicate(histogram1));
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), ElementsAre(histogram1));
+
+ // Register another Histogram with the same name.
+ Histogram* const histogram2 = CreateHistogram("TestHistogram1", 1, 1000, 10);
+ EXPECT_NE(histogram1, histogram2);
+ EXPECT_EQ(histogram1,
+ StatisticsRecorder::RegisterOrDeleteDuplicate(histogram2));
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), ElementsAre(histogram1));
+
+ // Register another Histogram with a different name.
+ Histogram* const histogram3 = CreateHistogram("TestHistogram0", 1, 1000, 10);
+ EXPECT_NE(histogram1, histogram3);
+ EXPECT_EQ(histogram3,
+ StatisticsRecorder::RegisterOrDeleteDuplicate(histogram3));
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(),
+ ElementsAre(histogram3, histogram1));
}
TEST_P(StatisticsRecorderTest, FindHistogram) {
@@ -257,63 +264,45 @@ TEST_P(StatisticsRecorderTest, GetSnapshot) {
Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
- StatisticsRecorder::Histograms snapshot;
- StatisticsRecorder::GetSnapshot("Test", &snapshot);
- EXPECT_EQ(3u, snapshot.size());
-
- snapshot.clear();
- StatisticsRecorder::GetSnapshot("1", &snapshot);
- EXPECT_EQ(1u, snapshot.size());
-
- snapshot.clear();
- StatisticsRecorder::GetSnapshot("hello", &snapshot);
- EXPECT_EQ(0u, snapshot.size());
+ EXPECT_THAT(StatisticsRecorder::GetSnapshot("Test"), SizeIs(3));
+ EXPECT_THAT(StatisticsRecorder::GetSnapshot("1"), SizeIs(1));
+ EXPECT_THAT(StatisticsRecorder::GetSnapshot("hello"), IsEmpty());
}
TEST_P(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
- StatisticsRecorder::Histograms registered_histograms;
-
- StatisticsRecorder::GetHistograms(&registered_histograms);
- ASSERT_EQ(0u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), IsEmpty());
// Create a histogram.
- HistogramBase* histogram = Histogram::FactoryGet(
+ HistogramBase* const histogram1 = Histogram::FactoryGet(
"TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(1u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), ElementsAre(histogram1));
// Get an existing histogram.
- HistogramBase* histogram2 = Histogram::FactoryGet(
+ HistogramBase* const histogram2 = Histogram::FactoryGet(
"TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(1u, registered_histograms.size());
- EXPECT_EQ(histogram, histogram2);
+ EXPECT_EQ(histogram1, histogram2);
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), ElementsAre(histogram1));
// Create a LinearHistogram.
- histogram = LinearHistogram::FactoryGet(
+ HistogramBase* const histogram3 = LinearHistogram::FactoryGet(
"TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(2u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(),
+ ElementsAre(histogram1, histogram3));
// Create a BooleanHistogram.
- histogram = BooleanHistogram::FactoryGet(
+ HistogramBase* const histogram4 = BooleanHistogram::FactoryGet(
"TestBooleanHistogram", HistogramBase::kNoFlags);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(3u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(),
+ ElementsAre(histogram4, histogram1, histogram3));
// Create a CustomHistogram.
std::vector<int> custom_ranges;
custom_ranges.push_back(1);
custom_ranges.push_back(5);
- histogram = CustomHistogram::FactoryGet(
+ HistogramBase* const histogram5 = CustomHistogram::FactoryGet(
"TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(4u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(),
+ ElementsAre(histogram4, histogram5, histogram1, histogram3));
}
TEST_P(StatisticsRecorderTest, RegisterHistogramWithMacros) {
@@ -331,35 +320,25 @@ TEST_P(StatisticsRecorderTest, RegisterHistogramWithMacros) {
// The histogram we got from macro is the same as from FactoryGet.
LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
+ registered_histograms = StatisticsRecorder::GetHistograms();
ASSERT_EQ(1u, registered_histograms.size());
EXPECT_EQ(histogram, registered_histograms[0]);
LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1));
LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
- registered_histograms.clear();
- StatisticsRecorder::GetHistograms(&registered_histograms);
- EXPECT_EQ(3u, registered_histograms.size());
+ EXPECT_THAT(StatisticsRecorder::GetHistograms(), SizeIs(3));
}
TEST_P(StatisticsRecorderTest, BucketRangesSharing) {
- std::vector<const BucketRanges*> ranges;
- StatisticsRecorder::GetBucketRanges(&ranges);
- EXPECT_EQ(0u, ranges.size());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), IsEmpty());
Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags);
Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags);
-
- StatisticsRecorder::GetBucketRanges(&ranges);
- EXPECT_EQ(1u, ranges.size());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), SizeIs(1));
Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags);
-
- ranges.clear();
- StatisticsRecorder::GetBucketRanges(&ranges);
- EXPECT_EQ(2u, ranges.size());
+ EXPECT_THAT(StatisticsRecorder::GetBucketRanges(), SizeIs(2));
}
TEST_P(StatisticsRecorderTest, ToJSON) {
@@ -423,9 +402,9 @@ TEST_P(StatisticsRecorderTest, IterationTest) {
Histogram::FactoryGet("IterationTest1", 1, 64, 16, HistogramBase::kNoFlags);
Histogram::FactoryGet("IterationTest2", 1, 64, 16, HistogramBase::kNoFlags);
- EXPECT_EQ(2U, StatisticsRecorder::GetKnownHistograms(true).size());
- EXPECT_EQ(use_persistent_histogram_allocator_ ? 0U : 2U,
- StatisticsRecorder::GetKnownHistograms(false).size());
+ EXPECT_THAT(StatisticsRecorder::GetKnownHistograms(true), SizeIs(2));
+ EXPECT_THAT(StatisticsRecorder::GetKnownHistograms(false),
+ SizeIs(use_persistent_histogram_allocator_ ? 0 : 2));
// Create a new global allocator using the same memory as the old one. Any
// old one is kept around so the memory doesn't get released.
@@ -442,11 +421,11 @@ TEST_P(StatisticsRecorderTest, IterationTest) {
InitializeStatisticsRecorder();
StatisticsRecorder::ImportGlobalPersistentHistograms();
- EXPECT_EQ(use_persistent_histogram_allocator_ ? 2U : 0U,
- StatisticsRecorder::GetKnownHistograms(true).size());
+ EXPECT_THAT(StatisticsRecorder::GetKnownHistograms(true),
+ SizeIs(use_persistent_histogram_allocator_ ? 2 : 0));
StatisticsRecorder::ImportGlobalPersistentHistograms();
- EXPECT_EQ(0U, StatisticsRecorder::GetKnownHistograms(false).size());
+ EXPECT_THAT(StatisticsRecorder::GetKnownHistograms(false), IsEmpty());
}
namespace {
@@ -624,33 +603,33 @@ TEST_P(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
}
TEST_P(StatisticsRecorderTest, LogOnShutdownNotInitialized) {
- UninitializeStatisticsRecorder();
+ ResetVLogInitialized();
logging::SetMinLogLevel(logging::LOG_WARNING);
InitializeStatisticsRecorder();
EXPECT_FALSE(VLOG_IS_ON(1));
- EXPECT_FALSE(VLogInitialized());
+ EXPECT_FALSE(IsVLogInitialized());
InitLogOnShutdown();
- EXPECT_FALSE(VLogInitialized());
+ EXPECT_FALSE(IsVLogInitialized());
}
TEST_P(StatisticsRecorderTest, LogOnShutdownInitializedExplicitly) {
- UninitializeStatisticsRecorder();
+ ResetVLogInitialized();
logging::SetMinLogLevel(logging::LOG_WARNING);
InitializeStatisticsRecorder();
EXPECT_FALSE(VLOG_IS_ON(1));
- EXPECT_FALSE(VLogInitialized());
+ EXPECT_FALSE(IsVLogInitialized());
logging::SetMinLogLevel(logging::LOG_VERBOSE);
EXPECT_TRUE(VLOG_IS_ON(1));
InitLogOnShutdown();
- EXPECT_TRUE(VLogInitialized());
+ EXPECT_TRUE(IsVLogInitialized());
}
TEST_P(StatisticsRecorderTest, LogOnShutdownInitialized) {
- UninitializeStatisticsRecorder();
+ ResetVLogInitialized();
logging::SetMinLogLevel(logging::LOG_VERBOSE);
InitializeStatisticsRecorder();
EXPECT_TRUE(VLOG_IS_ON(1));
- EXPECT_TRUE(VLogInitialized());
+ EXPECT_TRUE(IsVLogInitialized());
}
class TestHistogramProvider : public StatisticsRecorder::HistogramProvider {