Commit 30226c80 authored by bcwhite's avatar bcwhite Committed by Commit bot

Collect information about failing histogram factory calls.

Some tests need to be disabled because they create the same histogram with different parameters, a condition which does not always crash in the calling code but does with this CL.

This CL will be reverted once the necessary information has been collected, including re-enabling of any tests.

SHERIFFS: If a test breaks in the waterfall, you can either revert this CL or disable the test.  I'll re-enable it when reverting this after the necessary data has been collected.

BUG=588946

Committed: https://crrev.com/ce1315b94863f40d6323fa488490ed866aae4ed4
Cr-Commit-Position: refs/heads/master@{#378957}

Committed: https://crrev.com/63f1c5d846f6dac2cf148b81961c38b88ff1bd86
Cr-Commit-Position: refs/heads/master@{#379323}

Committed: https://crrev.com/89dca78efa00acb8fc8749adcc1a08a24eb105d5
Cr-Commit-Position: refs/heads/master@{#379489}

Committed: https://crrev.com/1375777f66fcf8edd3f393dadd9d9de6a7409030
Cr-Commit-Position: refs/heads/master@{#379690}

Committed: https://crrev.com/0abc5c2d2cb7ac70e26eab73d7e3f61f0472461e
Cr-Commit-Position: refs/heads/master@{#380070}

Committed: https://crrev.com/1d50ab3eec1dab7d3a6c70ec85b8937d5073b66d
Cr-Commit-Position: refs/heads/master@{#380474}

Committed: https://crrev.com/29601c49ec14ecb8cdfac577288b814e4c425bfa
Cr-Commit-Position: refs/heads/master@{#380889}

Review URL: https://codereview.chromium.org/1719363002

Cr-Commit-Position: refs/heads/master@{#381774}
parent fbf8325c
...@@ -153,10 +153,21 @@ HistogramBase* Histogram::Factory::Build() { ...@@ -153,10 +153,21 @@ HistogramBase* Histogram::Factory::Build() {
PersistentHistogramAllocator::ImportGlobalHistograms(); PersistentHistogramAllocator::ImportGlobalHistograms();
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_); HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
// crbug.com/588946 debugging. See comment at end of function.
const BucketRanges* created_ranges =
reinterpret_cast<const BucketRanges*>(0xDEADBEEF);
const BucketRanges* registered_ranges =
reinterpret_cast<const BucketRanges*>(0xDEADBEEF);
scoped_ptr<HistogramBase> tentative_histogram;
PersistentHistogramAllocator* allocator =
reinterpret_cast<PersistentHistogramAllocator*>(0xDEADBEEF);
PersistentHistogramAllocator::Reference histogram_ref = 0xDEADBEEF;
if (!histogram) { if (!histogram) {
// To avoid racy destruction at shutdown, the following will be leaked. // To avoid racy destruction at shutdown, the following will be leaked.
const BucketRanges* created_ranges = CreateRanges(); created_ranges = CreateRanges();
const BucketRanges* registered_ranges = registered_ranges =
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
// In most cases, the bucket-count, minimum, and maximum values are known // In most cases, the bucket-count, minimum, and maximum values are known
...@@ -169,15 +180,15 @@ HistogramBase* Histogram::Factory::Build() { ...@@ -169,15 +180,15 @@ HistogramBase* Histogram::Factory::Build() {
minimum_ = registered_ranges->range(1); minimum_ = registered_ranges->range(1);
maximum_ = registered_ranges->range(bucket_count_ - 1); maximum_ = registered_ranges->range(bucket_count_ - 1);
} }
CHECK_LT(0, minimum_);
CHECK_LT(0, maximum_);
// Try to create the histogram using a "persistent" allocator. As of // Try to create the histogram using a "persistent" allocator. As of
// 2016-02-25, the availability of such is controlled by a base::Feature // 2016-02-25, the availability of such is controlled by a base::Feature
// that is off by default. If the allocator doesn't exist or if // that is off by default. If the allocator doesn't exist or if
// allocating from it fails, code below will allocate the histogram from // allocating from it fails, code below will allocate the histogram from
// the process heap. // the process heap.
PersistentHistogramAllocator::Reference histogram_ref = 0; allocator =
scoped_ptr<HistogramBase> tentative_histogram;
PersistentHistogramAllocator* allocator =
PersistentHistogramAllocator::GetGlobalAllocator(); PersistentHistogramAllocator::GetGlobalAllocator();
if (allocator) { if (allocator) {
tentative_histogram = allocator->AllocateHistogram( tentative_histogram = allocator->AllocateHistogram(
...@@ -188,16 +199,33 @@ HistogramBase* Histogram::Factory::Build() { ...@@ -188,16 +199,33 @@ HistogramBase* Histogram::Factory::Build() {
registered_ranges, registered_ranges,
flags_, flags_,
&histogram_ref); &histogram_ref);
CHECK_LT(0, minimum_);
CHECK_LT(0, maximum_);
CHECK_EQ(
minimum_,
static_cast<Histogram*>(tentative_histogram.get())->declared_min_);
CHECK_EQ(
maximum_,
static_cast<Histogram*>(tentative_histogram.get())->declared_max_);
} }
// Handle the case where no persistent allocator is present or the // Handle the case where no persistent allocator is present or the
// persistent allocation fails (perhaps because it is full). // persistent allocation fails (perhaps because it is full).
if (!tentative_histogram) { if (!tentative_histogram) {
DCHECK(!histogram_ref); // Should never have been set. // DCHECK(!histogram_ref); // Should never have been set.
DCHECK(!allocator); // Shouldn't have failed. // DCHECK(!allocator); // Shouldn't have failed.
flags_ &= ~HistogramBase::kIsPersistent; flags_ &= ~HistogramBase::kIsPersistent;
tentative_histogram = HeapAlloc(registered_ranges); tentative_histogram = HeapAlloc(registered_ranges);
tentative_histogram->SetFlags(flags_); tentative_histogram->SetFlags(flags_);
CHECK_LT(0, minimum_);
CHECK_LT(0, maximum_);
CHECK_EQ(
minimum_,
static_cast<Histogram*>(tentative_histogram.get())->declared_min_);
CHECK_EQ(
maximum_,
static_cast<Histogram*>(tentative_histogram.get())->declared_max_);
} }
FillHistogram(tentative_histogram.get()); FillHistogram(tentative_histogram.get());
...@@ -211,7 +239,7 @@ HistogramBase* Histogram::Factory::Build() { ...@@ -211,7 +239,7 @@ HistogramBase* Histogram::Factory::Build() {
tentative_histogram.release()); tentative_histogram.release());
// Persistent histograms need some follow-up processing. // Persistent histograms need some follow-up processing.
if (histogram_ref) { if (histogram_ref != 0xDEADBEEF) {
allocator->FinalizeHistogram(histogram_ref, allocator->FinalizeHistogram(histogram_ref,
histogram == tentative_histogram_ptr); histogram == tentative_histogram_ptr);
} }
...@@ -224,6 +252,15 @@ HistogramBase* Histogram::Factory::Build() { ...@@ -224,6 +252,15 @@ HistogramBase* Histogram::Factory::Build() {
} }
DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_; DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_;
bool bad_args = false;
HistogramBase* existing_histogram = histogram;
HistogramType existing_type = histogram->GetHistogramType();
const char* existing_name = histogram->histogram_name().c_str();
Sample existing_minimum = static_cast<Histogram*>(histogram)->declared_min_;
Sample existing_maximum = static_cast<Histogram*>(histogram)->declared_max_;
uint32_t existing_bucket_count =
static_cast<Histogram*>(histogram)->bucket_count();
if (bucket_count_ != 0 && if (bucket_count_ != 0 &&
!histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) { !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) {
// The construction arguments do not match the existing histogram. This can // The construction arguments do not match the existing histogram. This can
...@@ -233,8 +270,45 @@ HistogramBase* Histogram::Factory::Build() { ...@@ -233,8 +270,45 @@ HistogramBase* Histogram::Factory::Build() {
// on dereference, but extension/Pepper APIs will guard against NULL and not // on dereference, but extension/Pepper APIs will guard against NULL and not
// crash. // crash.
DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments"; DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments";
return nullptr; bad_args = true;
histogram = nullptr;
}
#if !DCHECK_IS_ON() && defined(OS_WIN) // Affect only Windows release builds.
// For the moment, crash here so that collected crash reports have access
// to the construction values in order to figure out why this is failing.
// TODO(bcwhite): Remove this once crbug.com/588946 is resolved. Also remove
// from beta-branch because we don't want crashes due to misbehaving
// extensions (see comment above).
if (!histogram) {
HistogramType histogram_type = histogram_type_;
HistogramBase::Sample minimum = minimum_;
HistogramBase::Sample maximum = maximum_;
uint32_t bucket_count = bucket_count_;
int32_t flags = flags_;
CHECK(histogram) << name_ << ": bad-args=" << bad_args;
base::debug::Alias(&histogram_type);
base::debug::Alias(&minimum);
base::debug::Alias(&maximum);
base::debug::Alias(&bucket_count);
base::debug::Alias(&flags);
base::debug::Alias(&created_ranges);
base::debug::Alias(&registered_ranges);
base::debug::Alias(&histogram_ref);
base::debug::Alias(&tentative_histogram);
base::debug::Alias(&allocator);
base::debug::Alias(&tentative_histogram);
} }
#endif
// Down here so vars are always "used".
base::debug::Alias(&bad_args);
base::debug::Alias(&existing_histogram);
base::debug::Alias(&existing_type);
base::debug::Alias(&existing_name);
base::debug::Alias(&existing_minimum);
base::debug::Alias(&existing_maximum);
base::debug::Alias(&existing_bucket_count);
return histogram; return histogram;
} }
...@@ -497,8 +571,12 @@ Histogram::Histogram(const std::string& name, ...@@ -497,8 +571,12 @@ Histogram::Histogram(const std::string& name,
bucket_ranges_(ranges), bucket_ranges_(ranges),
declared_min_(minimum), declared_min_(minimum),
declared_max_(maximum) { declared_max_(maximum) {
CHECK_LT(0, minimum);
CHECK_LT(0, maximum);
if (ranges) if (ranges)
samples_.reset(new SampleVector(HashMetricName(name), ranges)); samples_.reset(new SampleVector(HashMetricName(name), ranges));
CHECK_EQ(minimum, declared_min_);
CHECK_EQ(maximum, declared_max_);
} }
Histogram::Histogram(const std::string& name, Histogram::Histogram(const std::string& name,
...@@ -514,12 +592,16 @@ Histogram::Histogram(const std::string& name, ...@@ -514,12 +592,16 @@ Histogram::Histogram(const std::string& name,
bucket_ranges_(ranges), bucket_ranges_(ranges),
declared_min_(minimum), declared_min_(minimum),
declared_max_(maximum) { declared_max_(maximum) {
CHECK_LT(0, minimum);
CHECK_LT(0, maximum);
if (ranges) { if (ranges) {
samples_.reset(new SampleVector(HashMetricName(name), samples_.reset(new SampleVector(HashMetricName(name),
counts, counts_size, meta, ranges)); counts, counts_size, meta, ranges));
logged_samples_.reset(new SampleVector(samples_->id(), logged_counts, logged_samples_.reset(new SampleVector(samples_->id(), logged_counts,
counts_size, logged_meta, ranges)); counts_size, logged_meta, ranges));
} }
CHECK_EQ(minimum, declared_min_);
CHECK_EQ(maximum, declared_max_);
} }
Histogram::~Histogram() { Histogram::~Histogram() {
......
...@@ -574,7 +574,7 @@ TEST_P(HistogramTest, CustomHistogramSerializeInfo) { ...@@ -574,7 +574,7 @@ TEST_P(HistogramTest, CustomHistogramSerializeInfo) {
EXPECT_FALSE(iter.SkipBytes(1)); EXPECT_FALSE(iter.SkipBytes(1));
} }
TEST_P(HistogramTest, BadConstruction) { TEST_P(HistogramTest, DISABLED_BadConstruction) {
HistogramBase* histogram = Histogram::FactoryGet( HistogramBase* histogram = Histogram::FactoryGet(
"BadConstruction", 0, 100, 8, HistogramBase::kNoFlags); "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8)); EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8));
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "base/metrics/metrics_hashes.h" #include "base/metrics/metrics_hashes.h"
#include "base/debug/alias.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/md5.h" #include "base/md5.h"
#include "base/sys_byteorder.h" #include "base/sys_byteorder.h"
...@@ -15,16 +16,42 @@ namespace { ...@@ -15,16 +16,42 @@ namespace {
// Converts the 8-byte prefix of an MD5 hash into a uint64_t value. // Converts the 8-byte prefix of an MD5 hash into a uint64_t value.
inline uint64_t DigestToUInt64(const base::MD5Digest& digest) { inline uint64_t DigestToUInt64(const base::MD5Digest& digest) {
uint64_t value; uint64_t value;
DCHECK_GE(sizeof(digest.a), sizeof(value)); CHECK_GE(sizeof(digest.a), sizeof(value));
memcpy(&value, digest.a, sizeof(value)); memcpy(&value, digest.a, sizeof(value));
return base::NetToHost64(value); uint64_t hash = base::NetToHost64(value);
CHECK_NE(0U, hash);
base::debug::Alias(&hash);
base::debug::Alias(&value);
base::debug::Alias(&digest);
return hash;
} }
} // namespace } // namespace
uint64_t HashMetricName(base::StringPiece name) { uint64_t HashMetricName(base::StringPiece name) {
base::MD5Digest digest; base::MD5Digest digest = {{
0x0F, 0x0E, 0x0D, 0x0C, 0x00, 0x0D, 0x0E, 0x02,
0x0D, 0x0E, 0x0A, 0x0D, 0x0B, 0x0E, 0x0E, 0x0F
}};
base::MD5Sum(name.data(), name.size(), &digest); base::MD5Sum(name.data(), name.size(), &digest);
CHECK(
digest.a[0] != 0x0F ||
digest.a[1] != 0x0E ||
digest.a[2] != 0x0D ||
digest.a[3] != 0x0C ||
digest.a[4] != 0x00 ||
digest.a[5] != 0x0D ||
digest.a[6] != 0x0E ||
digest.a[7] != 0x02 ||
digest.a[8] != 0x0D ||
digest.a[9] != 0x0E ||
digest.a[10] != 0x0A ||
digest.a[11] != 0x0D ||
digest.a[12] != 0x0B ||
digest.a[13] != 0x0E ||
digest.a[14] != 0x0E ||
digest.a[15] != 0x0F);
base::debug::Alias(&name);
return DigestToUInt64(digest); return DigestToUInt64(digest);
} }
......
...@@ -295,6 +295,12 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram( ...@@ -295,6 +295,12 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
// validated below; the local copy is to ensure that the contents cannot // validated below; the local copy is to ensure that the contents cannot
// be externally changed between validation and use. // be externally changed between validation and use.
PersistentHistogramData histogram_data = *histogram_data_ptr; PersistentHistogramData histogram_data = *histogram_data_ptr;
CHECK_EQ(histogram_data.histogram_type, histogram_data_ptr->histogram_type);
CHECK_EQ(histogram_data.flags, histogram_data_ptr->flags);
CHECK_EQ(histogram_data.minimum, histogram_data_ptr->minimum);
CHECK_EQ(histogram_data.maximum, histogram_data_ptr->maximum);
CHECK_EQ(histogram_data.bucket_count, histogram_data_ptr->bucket_count);
CHECK_EQ(histogram_data.ranges_checksum, histogram_data_ptr->ranges_checksum);
HistogramBase::Sample* ranges_data = HistogramBase::Sample* ranges_data =
memory_allocator_->GetAsObject<HistogramBase::Sample>( memory_allocator_->GetAsObject<HistogramBase::Sample>(
...@@ -345,6 +351,8 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram( ...@@ -345,6 +351,8 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
HistogramBase::AtomicCount* logged_data = HistogramBase::AtomicCount* logged_data =
counts_data + histogram_data.bucket_count; counts_data + histogram_data.bucket_count;
CHECK_LT(0, histogram_data.minimum);
CHECK_LT(0, histogram_data.maximum);
std::string name(histogram_data_ptr->name); std::string name(histogram_data_ptr->name);
scoped_ptr<HistogramBase> histogram; scoped_ptr<HistogramBase> histogram;
switch (histogram_data.histogram_type) { switch (histogram_data.histogram_type) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/metrics/statistics_recorder.h" #include "base/metrics/statistics_recorder.h"
#include "base/at_exit.h" #include "base/at_exit.h"
#include "base/debug/alias.h"
#include "base/debug/leak_annotations.h" #include "base/debug/leak_annotations.h"
#include "base/json/string_escape.h" #include "base/json/string_escape.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -132,13 +133,17 @@ HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate( ...@@ -132,13 +133,17 @@ HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
histogram_to_return = histogram; histogram_to_return = histogram;
} else { } else {
// We already have one histogram with this name. // We already have one histogram with this name.
DCHECK_EQ(histogram->histogram_name(), CHECK_EQ(histogram->histogram_name(),
it->second->histogram_name()) << "hash collision"; it->second->histogram_name()) << "hash collision";
histogram_to_return = it->second; histogram_to_return = it->second;
histogram_to_delete = histogram; histogram_to_delete = histogram;
} }
base::debug::Alias(&it);
base::debug::Alias(&name);
base::debug::Alias(&name_hash);
} }
} }
base::debug::Alias(&histogram);
delete histogram_to_delete; delete histogram_to_delete;
return histogram_to_return; return histogram_to_return;
} }
...@@ -288,10 +293,22 @@ HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) { ...@@ -288,10 +293,22 @@ HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
if (histograms_ == NULL) if (histograms_ == NULL)
return NULL; return NULL;
HistogramMap::iterator it = histograms_->find(HashMetricName(name)); const uint64_t lookup_hash = HashMetricName(name);
HistogramMap::iterator it = histograms_->find(lookup_hash);
if (histograms_->end() == it) if (histograms_->end() == it)
return NULL; return NULL;
DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
const uint64_t existing_hash = it->first;
const char* existing_name = it->second->histogram_name().c_str();
HistogramMap* histograms = histograms_;
CHECK_EQ(name, it->second->histogram_name()) << "hash collision";
base::debug::Alias(&lookup_hash);
base::debug::Alias(&existing_hash);
base::debug::Alias(&name);
base::debug::Alias(&existing_name);
base::debug::Alias(&it);
base::debug::Alias(&histograms);
return it->second; return it->second;
} }
......
...@@ -128,7 +128,7 @@ void ValidateHistograms(const RecordedHistogram* recorded, ...@@ -128,7 +128,7 @@ void ValidateHistograms(const RecordedHistogram* recorded,
} // anonymous namespace } // anonymous namespace
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Metrics) { IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_Metrics) {
base::UserActionTester user_action_tester; base::UserActionTester user_action_tester;
base::FieldTrialList::CreateFieldTrial("apitestfieldtrial2", "group1"); base::FieldTrialList::CreateFieldTrial("apitestfieldtrial2", "group1");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment