| Index: base/metrics/histogram.cc
|
| diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
|
| index 1526cd8a26ec0162c327538aa9f1350893549ce1..a3089327203c9a7ff4a80ae4dad41b2b9e1dc4a4 100644
|
| --- a/base/metrics/histogram.cc
|
| +++ b/base/metrics/histogram.cc
|
| @@ -53,48 +53,6 @@ scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name,
|
| bucket_count, flags);
|
| }
|
|
|
| -Histogram::Histogram(const std::string& name, Sample minimum,
|
| - Sample maximum, size_t bucket_count)
|
| - : histogram_name_(name),
|
| - declared_min_(minimum),
|
| - declared_max_(maximum),
|
| - bucket_count_(bucket_count),
|
| - flags_(kNoFlags),
|
| - ranges_(bucket_count + 1, 0),
|
| - range_checksum_(0),
|
| - sample_() {
|
| - Initialize();
|
| -}
|
| -
|
| -Histogram::Histogram(const std::string& name, TimeDelta minimum,
|
| - TimeDelta maximum, size_t bucket_count)
|
| - : histogram_name_(name),
|
| - declared_min_(static_cast<int> (minimum.InMilliseconds())),
|
| - declared_max_(static_cast<int> (maximum.InMilliseconds())),
|
| - bucket_count_(bucket_count),
|
| - flags_(kNoFlags),
|
| - ranges_(bucket_count + 1, 0),
|
| - range_checksum_(0),
|
| - sample_() {
|
| - Initialize();
|
| -}
|
| -
|
| -Histogram::~Histogram() {
|
| - if (StatisticsRecorder::dump_on_exit()) {
|
| - std::string output;
|
| - WriteAscii(true, "\n", &output);
|
| - LOG(INFO) << output;
|
| - }
|
| -
|
| - // Just to make sure most derived class did this properly...
|
| - DCHECK(ValidateBucketRanges());
|
| - DCHECK(HasValidRangeChecksum());
|
| -}
|
| -
|
| -bool Histogram::PrintEmptyBucket(size_t index) const {
|
| - return true;
|
| -}
|
| -
|
| void Histogram::Add(int value) {
|
| if (value > kSampleType_MAX - 1)
|
| value = kSampleType_MAX - 1;
|
| @@ -190,31 +148,223 @@ void Histogram::WriteAscii(bool graph_it, const std::string& newline,
|
| DCHECK_EQ(sample_count, past);
|
| }
|
|
|
| -bool Histogram::ValidateBucketRanges() const {
|
| - // Standard assertions that all bucket ranges should satisfy.
|
| - DCHECK_EQ(bucket_count_ + 1, ranges_.size());
|
| - DCHECK_EQ(0, ranges_[0]);
|
| - DCHECK_EQ(declared_min(), ranges_[1]);
|
| - DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
|
| - DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
|
| +// static
|
| +std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
|
| + const SampleSet& snapshot) {
|
| + DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
|
| +
|
| + Pickle pickle;
|
| + pickle.WriteString(histogram.histogram_name());
|
| + pickle.WriteInt(histogram.declared_min());
|
| + pickle.WriteInt(histogram.declared_max());
|
| + pickle.WriteSize(histogram.bucket_count());
|
| + pickle.WriteInt(histogram.range_checksum());
|
| + pickle.WriteInt(histogram.histogram_type());
|
| + pickle.WriteInt(histogram.flags());
|
| +
|
| + snapshot.Serialize(&pickle);
|
| + return std::string(static_cast<const char*>(pickle.data()), pickle.size());
|
| +}
|
| +
|
| +// static
|
| +bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
|
| + if (histogram_info.empty()) {
|
| + return false;
|
| + }
|
| +
|
| + Pickle pickle(histogram_info.data(),
|
| + static_cast<int>(histogram_info.size()));
|
| + std::string histogram_name;
|
| + int declared_min;
|
| + int declared_max;
|
| + size_t bucket_count;
|
| + int range_checksum;
|
| + int histogram_type;
|
| + int pickle_flags;
|
| + SampleSet sample;
|
| +
|
| + void* iter = NULL;
|
| + if (!pickle.ReadString(&iter, &histogram_name) ||
|
| + !pickle.ReadInt(&iter, &declared_min) ||
|
| + !pickle.ReadInt(&iter, &declared_max) ||
|
| + !pickle.ReadSize(&iter, &bucket_count) ||
|
| + !pickle.ReadInt(&iter, &range_checksum) ||
|
| + !pickle.ReadInt(&iter, &histogram_type) ||
|
| + !pickle.ReadInt(&iter, &pickle_flags) ||
|
| + !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
|
| + LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
|
| + return false;
|
| + }
|
| + DCHECK(pickle_flags & kIPCSerializationSourceFlag);
|
| + // Since these fields may have come from an untrusted renderer, do additional
|
| + // checks above and beyond those in Histogram::Initialize()
|
| + if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
|
| + INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
|
| + LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
|
| + return false;
|
| + }
|
| +
|
| + Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
|
| +
|
| + DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
|
| +
|
| + scoped_refptr<Histogram> render_histogram(NULL);
|
| +
|
| + if (histogram_type == HISTOGRAM) {
|
| + render_histogram = Histogram::FactoryGet(
|
| + histogram_name, declared_min, declared_max, bucket_count, flags);
|
| + } else if (histogram_type == LINEAR_HISTOGRAM) {
|
| + render_histogram = LinearHistogram::FactoryGet(
|
| + histogram_name, declared_min, declared_max, bucket_count, flags);
|
| + } else if (histogram_type == BOOLEAN_HISTOGRAM) {
|
| + render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
|
| + } else {
|
| + LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
|
| + << histogram_type;
|
| + return false;
|
| + }
|
| +
|
| + DCHECK_EQ(render_histogram->declared_min(), declared_min);
|
| + DCHECK_EQ(render_histogram->declared_max(), declared_max);
|
| + DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
|
| + DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
|
| + DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
|
| +
|
| + if (render_histogram->flags() & kIPCSerializationSourceFlag) {
|
| + DVLOG(1) << "Single process mode, histogram observed and not copied: "
|
| + << histogram_name;
|
| + } else {
|
| + DCHECK_EQ(flags & render_histogram->flags(), flags);
|
| + render_histogram->AddSampleSet(sample);
|
| + }
|
| +
|
| return true;
|
| }
|
|
|
| -void Histogram::Initialize() {
|
| - sample_.Resize(*this);
|
| - if (declared_min_ < 1)
|
| - declared_min_ = 1;
|
| - if (declared_max_ > kSampleType_MAX - 1)
|
| - declared_max_ = kSampleType_MAX - 1;
|
| - DCHECK_LE(declared_min_, declared_max_);
|
| - DCHECK_GT(bucket_count_, 1u);
|
| - size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
|
| - DCHECK_LE(bucket_count_, maximal_bucket_count);
|
| - DCHECK_EQ(0, ranges_[0]);
|
| - ranges_[bucket_count_] = kSampleType_MAX;
|
| - InitializeBucketRange();
|
| +//------------------------------------------------------------------------------
|
| +// Methods for the validating a sample and a related histogram.
|
| +//------------------------------------------------------------------------------
|
| +
|
| +Histogram::Inconsistencies Histogram::FindCorruption(
|
| + const SampleSet& snapshot) const {
|
| + int inconsistencies = NO_INCONSISTENCIES;
|
| + Sample previous_range = -1; // Bottom range is always 0.
|
| + Sample checksum = 0;
|
| + int64 count = 0;
|
| + for (size_t index = 0; index < bucket_count(); ++index) {
|
| + count += snapshot.counts(index);
|
| + int new_range = ranges(index);
|
| + checksum += new_range;
|
| + if (previous_range >= new_range)
|
| + inconsistencies |= BUCKET_ORDER_ERROR;
|
| + previous_range = new_range;
|
| + }
|
| +
|
| + if (checksum != range_checksum_)
|
| + inconsistencies |= RANGE_CHECKSUM_ERROR;
|
| +
|
| + int64 delta64 = snapshot.redundant_count() - count;
|
| + if (delta64 != 0) {
|
| + int delta = static_cast<int>(delta64);
|
| + if (delta != delta64)
|
| + delta = INT_MAX; // Flag all giant errors as INT_MAX.
|
| + // Since snapshots of histograms are taken asynchronously relative to
|
| + // sampling (and snapped from different threads), it is pretty likely that
|
| + // we'll catch a redundant count that doesn't match the sample count. We
|
| + // allow for a certain amount of slop before flagging this as an
|
| + // inconsistency. Even with an inconsistency, we'll snapshot it again (for
|
| + // UMA in about a half hour, so we'll eventually get the data, if it was
|
| + // not the result of a corruption. If histograms show that 1 is "too tight"
|
| + // then we may try to use 2 or 3 for this slop value.
|
| + const int kCommonRaceBasedCountMismatch = 1;
|
| + if (delta > 0) {
|
| + UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
|
| + if (delta > kCommonRaceBasedCountMismatch)
|
| + inconsistencies |= COUNT_HIGH_ERROR;
|
| + } else {
|
| + DCHECK_GT(0, delta);
|
| + UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
|
| + if (-delta > kCommonRaceBasedCountMismatch)
|
| + inconsistencies |= COUNT_LOW_ERROR;
|
| + }
|
| + }
|
| + return static_cast<Inconsistencies>(inconsistencies);
|
| +}
|
| +
|
| +Histogram::ClassType Histogram::histogram_type() const {
|
| + return HISTOGRAM;
|
| +}
|
| +
|
| +Histogram::Sample Histogram::ranges(size_t i) const {
|
| + return ranges_[i];
|
| +}
|
| +
|
| +size_t Histogram::bucket_count() const {
|
| + return bucket_count_;
|
| +}
|
| +
|
| +// Do a safe atomic snapshot of sample data.
|
| +// This implementation assumes we are on a safe single thread.
|
| +void Histogram::SnapshotSample(SampleSet* sample) const {
|
| + // Note locking not done in this version!!!
|
| + *sample = sample_;
|
| +}
|
| +
|
| +bool Histogram::HasConstructorArguments(Sample minimum,
|
| + Sample maximum,
|
| + size_t bucket_count) {
|
| + return ((minimum == declared_min_) && (maximum == declared_max_) &&
|
| + (bucket_count == bucket_count_));
|
| +}
|
| +
|
| +bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
|
| + TimeDelta maximum,
|
| + size_t bucket_count) {
|
| + return ((minimum.InMilliseconds() == declared_min_) &&
|
| + (maximum.InMilliseconds() == declared_max_) &&
|
| + (bucket_count == bucket_count_));
|
| +}
|
| +
|
| +Histogram::Histogram(const std::string& name, Sample minimum,
|
| + Sample maximum, size_t bucket_count)
|
| + : histogram_name_(name),
|
| + declared_min_(minimum),
|
| + declared_max_(maximum),
|
| + bucket_count_(bucket_count),
|
| + flags_(kNoFlags),
|
| + ranges_(bucket_count + 1, 0),
|
| + range_checksum_(0),
|
| + sample_() {
|
| + Initialize();
|
| +}
|
| +
|
| +Histogram::Histogram(const std::string& name, TimeDelta minimum,
|
| + TimeDelta maximum, size_t bucket_count)
|
| + : histogram_name_(name),
|
| + declared_min_(static_cast<int> (minimum.InMilliseconds())),
|
| + declared_max_(static_cast<int> (maximum.InMilliseconds())),
|
| + bucket_count_(bucket_count),
|
| + flags_(kNoFlags),
|
| + ranges_(bucket_count + 1, 0),
|
| + range_checksum_(0),
|
| + sample_() {
|
| + Initialize();
|
| +}
|
| +
|
| +Histogram::~Histogram() {
|
| + if (StatisticsRecorder::dump_on_exit()) {
|
| + std::string output;
|
| + WriteAscii(true, "\n", &output);
|
| + LOG(INFO) << output;
|
| + }
|
| +
|
| + // Just to make sure most derived class did this properly...
|
| DCHECK(ValidateBucketRanges());
|
| - StatisticsRecorder::Register(this);
|
| + DCHECK(HasValidRangeChecksum());
|
| +}
|
| +
|
| +bool Histogram::PrintEmptyBucket(size_t index) const {
|
| + return true;
|
| }
|
|
|
| // Calculate what range of values are held in each bucket.
|
| @@ -295,6 +445,53 @@ void Histogram::ResetRangeChecksum() {
|
| range_checksum_ = CalculateRangeChecksum();
|
| }
|
|
|
| +const std::string Histogram::GetAsciiBucketRange(size_t i) const {
|
| + std::string result;
|
| + if (kHexRangePrintingFlag & flags_)
|
| + StringAppendF(&result, "%#x", ranges(i));
|
| + else
|
| + StringAppendF(&result, "%d", ranges(i));
|
| + return result;
|
| +}
|
| +
|
| +// Update histogram data with new sample.
|
| +void Histogram::Accumulate(Sample value, Count count, size_t index) {
|
| + // Note locking not done in this version!!!
|
| + sample_.Accumulate(value, count, index);
|
| +}
|
| +
|
| +void Histogram::SetBucketRange(size_t i, Sample value) {
|
| + DCHECK_GT(bucket_count_, i);
|
| + ranges_[i] = value;
|
| +}
|
| +
|
| +bool Histogram::ValidateBucketRanges() const {
|
| + // Standard assertions that all bucket ranges should satisfy.
|
| + DCHECK_EQ(bucket_count_ + 1, ranges_.size());
|
| + DCHECK_EQ(0, ranges_[0]);
|
| + DCHECK_EQ(declared_min(), ranges_[1]);
|
| + DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
|
| + DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
|
| + return true;
|
| +}
|
| +
|
| +void Histogram::Initialize() {
|
| + sample_.Resize(*this);
|
| + if (declared_min_ < 1)
|
| + declared_min_ = 1;
|
| + if (declared_max_ > kSampleType_MAX - 1)
|
| + declared_max_ = kSampleType_MAX - 1;
|
| + DCHECK_LE(declared_min_, declared_max_);
|
| + DCHECK_GT(bucket_count_, 1u);
|
| + size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
|
| + DCHECK_LE(bucket_count_, maximal_bucket_count);
|
| + DCHECK_EQ(0, ranges_[0]);
|
| + ranges_[bucket_count_] = kSampleType_MAX;
|
| + InitializeBucketRange();
|
| + DCHECK(ValidateBucketRanges());
|
| + StatisticsRecorder::Register(this);
|
| +}
|
| +
|
| bool Histogram::HasValidRangeChecksum() const {
|
| return CalculateRangeChecksum() == range_checksum_;
|
| }
|
| @@ -309,49 +506,6 @@ Histogram::Sample Histogram::CalculateRangeChecksum() const {
|
| }
|
|
|
| //------------------------------------------------------------------------------
|
| -// The following two methods can be overridden to provide a thread safe
|
| -// version of this class. The cost of locking is low... but an error in each
|
| -// of these methods has minimal impact. For now, I'll leave this unlocked,
|
| -// and I don't believe I can loose more than a count or two.
|
| -// The vectors are NOT reallocated, so there is no risk of them moving around.
|
| -
|
| -// Update histogram data with new sample.
|
| -void Histogram::Accumulate(Sample value, Count count, size_t index) {
|
| - // Note locking not done in this version!!!
|
| - sample_.Accumulate(value, count, index);
|
| -}
|
| -
|
| -// Do a safe atomic snapshot of sample data.
|
| -// This implementation assumes we are on a safe single thread.
|
| -void Histogram::SnapshotSample(SampleSet* sample) const {
|
| - // Note locking not done in this version!!!
|
| - *sample = sample_;
|
| -}
|
| -
|
| -bool Histogram::HasConstructorArguments(Sample minimum,
|
| - Sample maximum,
|
| - size_t bucket_count) {
|
| - return ((minimum == declared_min_) && (maximum == declared_max_) &&
|
| - (bucket_count == bucket_count_));
|
| -}
|
| -
|
| -bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
|
| - TimeDelta maximum,
|
| - size_t bucket_count) {
|
| - return ((minimum.InMilliseconds() == declared_min_) &&
|
| - (maximum.InMilliseconds() == declared_max_) &&
|
| - (bucket_count == bucket_count_));
|
| -}
|
| -
|
| -//------------------------------------------------------------------------------
|
| -// Accessor methods
|
| -
|
| -void Histogram::SetBucketRange(size_t i, Sample value) {
|
| - DCHECK_GT(bucket_count_, i);
|
| - ranges_[i] = value;
|
| -}
|
| -
|
| -//------------------------------------------------------------------------------
|
| // Private methods
|
|
|
| double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
|
| @@ -400,15 +554,6 @@ void Histogram::WriteAsciiBucketContext(const int64 past,
|
| }
|
| }
|
|
|
| -const std::string Histogram::GetAsciiBucketRange(size_t i) const {
|
| - std::string result;
|
| - if (kHexRangePrintingFlag & flags_)
|
| - StringAppendF(&result, "%#x", ranges(i));
|
| - else
|
| - StringAppendF(&result, "%d", ranges(i));
|
| - return result;
|
| -}
|
| -
|
| void Histogram::WriteAsciiBucketValue(Count current, double scaled_sum,
|
| std::string* output) const {
|
| StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
|
| @@ -428,161 +573,6 @@ void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
|
| output->append(" ");
|
| }
|
|
|
| -// static
|
| -std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
|
| - const SampleSet& snapshot) {
|
| - DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
|
| -
|
| - Pickle pickle;
|
| - pickle.WriteString(histogram.histogram_name());
|
| - pickle.WriteInt(histogram.declared_min());
|
| - pickle.WriteInt(histogram.declared_max());
|
| - pickle.WriteSize(histogram.bucket_count());
|
| - pickle.WriteInt(histogram.range_checksum());
|
| - pickle.WriteInt(histogram.histogram_type());
|
| - pickle.WriteInt(histogram.flags());
|
| -
|
| - snapshot.Serialize(&pickle);
|
| - return std::string(static_cast<const char*>(pickle.data()), pickle.size());
|
| -}
|
| -
|
| -// static
|
| -bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
|
| - if (histogram_info.empty()) {
|
| - return false;
|
| - }
|
| -
|
| - Pickle pickle(histogram_info.data(),
|
| - static_cast<int>(histogram_info.size()));
|
| - std::string histogram_name;
|
| - int declared_min;
|
| - int declared_max;
|
| - size_t bucket_count;
|
| - int range_checksum;
|
| - int histogram_type;
|
| - int pickle_flags;
|
| - SampleSet sample;
|
| -
|
| - void* iter = NULL;
|
| - if (!pickle.ReadString(&iter, &histogram_name) ||
|
| - !pickle.ReadInt(&iter, &declared_min) ||
|
| - !pickle.ReadInt(&iter, &declared_max) ||
|
| - !pickle.ReadSize(&iter, &bucket_count) ||
|
| - !pickle.ReadInt(&iter, &range_checksum) ||
|
| - !pickle.ReadInt(&iter, &histogram_type) ||
|
| - !pickle.ReadInt(&iter, &pickle_flags) ||
|
| - !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
|
| - LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
|
| - return false;
|
| - }
|
| - DCHECK(pickle_flags & kIPCSerializationSourceFlag);
|
| - // Since these fields may have come from an untrusted renderer, do additional
|
| - // checks above and beyond those in Histogram::Initialize()
|
| - if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
|
| - INT_MAX / sizeof(Count) <= bucket_count || bucket_count < 2) {
|
| - LOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
|
| - return false;
|
| - }
|
| -
|
| - Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
|
| -
|
| - DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
|
| -
|
| - scoped_refptr<Histogram> render_histogram(NULL);
|
| -
|
| - if (histogram_type == HISTOGRAM) {
|
| - render_histogram = Histogram::FactoryGet(
|
| - histogram_name, declared_min, declared_max, bucket_count, flags);
|
| - } else if (histogram_type == LINEAR_HISTOGRAM) {
|
| - render_histogram = LinearHistogram::FactoryGet(
|
| - histogram_name, declared_min, declared_max, bucket_count, flags);
|
| - } else if (histogram_type == BOOLEAN_HISTOGRAM) {
|
| - render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
|
| - } else {
|
| - LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
|
| - << histogram_type;
|
| - return false;
|
| - }
|
| -
|
| - DCHECK_EQ(render_histogram->declared_min(), declared_min);
|
| - DCHECK_EQ(render_histogram->declared_max(), declared_max);
|
| - DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
|
| - DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
|
| - DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
|
| -
|
| - if (render_histogram->flags() & kIPCSerializationSourceFlag) {
|
| - DVLOG(1) << "Single process mode, histogram observed and not copied: "
|
| - << histogram_name;
|
| - } else {
|
| - DCHECK_EQ(flags & render_histogram->flags(), flags);
|
| - render_histogram->AddSampleSet(sample);
|
| - }
|
| -
|
| - return true;
|
| -}
|
| -
|
| -//------------------------------------------------------------------------------
|
| -// Methods for the validating a sample and a related histogram.
|
| -//------------------------------------------------------------------------------
|
| -
|
| -Histogram::Inconsistencies Histogram::FindCorruption(
|
| - const SampleSet& snapshot) const {
|
| - int inconsistencies = NO_INCONSISTENCIES;
|
| - Sample previous_range = -1; // Bottom range is always 0.
|
| - Sample checksum = 0;
|
| - int64 count = 0;
|
| - for (size_t index = 0; index < bucket_count(); ++index) {
|
| - count += snapshot.counts(index);
|
| - int new_range = ranges(index);
|
| - checksum += new_range;
|
| - if (previous_range >= new_range)
|
| - inconsistencies |= BUCKET_ORDER_ERROR;
|
| - previous_range = new_range;
|
| - }
|
| -
|
| - if (checksum != range_checksum_)
|
| - inconsistencies |= RANGE_CHECKSUM_ERROR;
|
| -
|
| - int64 delta64 = snapshot.redundant_count() - count;
|
| - if (delta64 != 0) {
|
| - int delta = static_cast<int>(delta64);
|
| - if (delta != delta64)
|
| - delta = INT_MAX; // Flag all giant errors as INT_MAX.
|
| - // Since snapshots of histograms are taken asynchronously relative to
|
| - // sampling (and snapped from different threads), it is pretty likely that
|
| - // we'll catch a redundant count that doesn't match the sample count. We
|
| - // allow for a certain amount of slop before flagging this as an
|
| - // inconsistency. Even with an inconsistency, we'll snapshot it again (for
|
| - // UMA in about a half hour, so we'll eventually get the data, if it was
|
| - // not the result of a corruption. If histograms show that 1 is "too tight"
|
| - // then we may try to use 2 or 3 for this slop value.
|
| - const int kCommonRaceBasedCountMismatch = 1;
|
| - if (delta > 0) {
|
| - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
|
| - if (delta > kCommonRaceBasedCountMismatch)
|
| - inconsistencies |= COUNT_HIGH_ERROR;
|
| - } else {
|
| - DCHECK_GT(0, delta);
|
| - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
|
| - if (-delta > kCommonRaceBasedCountMismatch)
|
| - inconsistencies |= COUNT_LOW_ERROR;
|
| - }
|
| - }
|
| - return static_cast<Inconsistencies>(inconsistencies);
|
| -}
|
| -
|
| -Histogram::ClassType Histogram::histogram_type() const {
|
| - return HISTOGRAM;
|
| -}
|
| -
|
| -Histogram::Sample Histogram::ranges(size_t i) const {
|
| - return ranges_[i];
|
| -}
|
| -
|
| -size_t Histogram::bucket_count() const {
|
| - return bucket_count_;
|
| -}
|
| -
|
| //------------------------------------------------------------------------------
|
| // Methods for the Histogram::SampleSet class
|
| //------------------------------------------------------------------------------
|
| @@ -700,6 +690,9 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
|
| // buckets.
|
| //------------------------------------------------------------------------------
|
|
|
| +LinearHistogram::~LinearHistogram() {
|
| +}
|
| +
|
| scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
|
| Sample minimum,
|
| Sample maximum,
|
| @@ -733,7 +726,15 @@ scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet(
|
| bucket_count, flags);
|
| }
|
|
|
| -LinearHistogram::~LinearHistogram() {
|
| +Histogram::ClassType LinearHistogram::histogram_type() const {
|
| + return LINEAR_HISTOGRAM;
|
| +}
|
| +
|
| +void LinearHistogram::SetRangeDescriptions(
|
| + const DescriptionPair descriptions[]) {
|
| + for (int i =0; descriptions[i].description; ++i) {
|
| + bucket_description_[descriptions[i].sample] = descriptions[i].description;
|
| + }
|
| }
|
|
|
| LinearHistogram::LinearHistogram(const std::string& name,
|
| @@ -757,30 +758,6 @@ LinearHistogram::LinearHistogram(const std::string& name,
|
| DCHECK(ValidateBucketRanges());
|
| }
|
|
|
| -Histogram::ClassType LinearHistogram::histogram_type() const {
|
| - return LINEAR_HISTOGRAM;
|
| -}
|
| -
|
| -void LinearHistogram::SetRangeDescriptions(
|
| - const DescriptionPair descriptions[]) {
|
| - for (int i =0; descriptions[i].description; ++i) {
|
| - bucket_description_[descriptions[i].sample] = descriptions[i].description;
|
| - }
|
| -}
|
| -
|
| -const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
|
| - int range = ranges(i);
|
| - BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
|
| - if (it == bucket_description_.end())
|
| - return Histogram::GetAsciiBucketRange(i);
|
| - return it->second;
|
| -}
|
| -
|
| -bool LinearHistogram::PrintEmptyBucket(size_t index) const {
|
| - return bucket_description_.find(ranges(index)) == bucket_description_.end();
|
| -}
|
| -
|
| -
|
| void LinearHistogram::InitializeBucketRange() {
|
| DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here.
|
| double min = declared_min();
|
| @@ -802,6 +779,19 @@ double LinearHistogram::GetBucketSize(Count current, size_t i) const {
|
| return current/denominator;
|
| }
|
|
|
| +const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
|
| + int range = ranges(i);
|
| + BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
|
| + if (it == bucket_description_.end())
|
| + return Histogram::GetAsciiBucketRange(i);
|
| + return it->second;
|
| +}
|
| +
|
| +bool LinearHistogram::PrintEmptyBucket(size_t index) const {
|
| + return bucket_description_.find(ranges(index)) == bucket_description_.end();
|
| +}
|
| +
|
| +
|
| //------------------------------------------------------------------------------
|
| // This section provides implementation for BooleanHistogram.
|
| //------------------------------------------------------------------------------
|
|
|