summaryrefslogtreecommitdiffstats
path: root/base/metrics
diff options
context:
space:
mode:
authorkaiwang@chromium.org <kaiwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 21:52:44 +0000
committerkaiwang@chromium.org <kaiwang@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-11 21:52:44 +0000
commitc50c21d07c17ade9e6a9b0a67eb505bea7bb8134 (patch)
treefc064c9b90ea4bbf97f016a0028e60d9b3cb9fb3 /base/metrics
parent02e33f8aea28a9ca82c87acb422d3fcceb1f9888 (diff)
downloadchromium_src-c50c21d07c17ade9e6a9b0a67eb505bea7bb8134.zip
chromium_src-c50c21d07c17ade9e6a9b0a67eb505bea7bb8134.tar.gz
chromium_src-c50c21d07c17ade9e6a9b0a67eb505bea7bb8134.tar.bz2
Serialize/Deserialize support in HistogramBase
BUG=139612,167343 Review URL: https://chromiumcodereview.appspot.com/11682003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176449 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/metrics')
-rw-r--r--base/metrics/histogram.cc299
-rw-r--r--base/metrics/histogram.h62
-rw-r--r--base/metrics/histogram_base.cc45
-rw-r--r--base/metrics/histogram_base.h28
-rw-r--r--base/metrics/histogram_base_unittest.cc172
-rw-r--r--base/metrics/histogram_unittest.cc124
-rw-r--r--base/metrics/sample_map.cc5
-rw-r--r--base/metrics/sample_map.h2
-rw-r--r--base/metrics/sparse_histogram.cc42
-rw-r--r--base/metrics/sparse_histogram.h22
-rw-r--r--base/metrics/sparse_histogram_unittest.cc29
-rw-r--r--base/metrics/statistics_recorder.h1
12 files changed, 622 insertions, 209 deletions
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 795ea3a..d5da371 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -30,6 +30,54 @@ using std::vector;
namespace base {
+namespace {
+
+bool ReadHistogramArguments(PickleIterator* iter,
+ string* histogram_name,
+ int* flags,
+ int* declared_min,
+ int* declared_max,
+ uint64* bucket_count,
+ uint32* range_checksum) {
+ if (!iter->ReadString(histogram_name) ||
+ !iter->ReadInt(flags) ||
+ !iter->ReadInt(declared_min) ||
+ !iter->ReadInt(declared_max) ||
+ !iter->ReadUInt64(bucket_count) ||
+ !iter->ReadUInt32(range_checksum)) {
+ DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
+ return false;
+ }
+
+ // 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(HistogramBase::Count) <= *bucket_count ||
+ *bucket_count < 2) {
+ DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
+ return false;
+ }
+
+ // We use the arguments to find or create the local version of the histogram
+ // in this process, so we need to clear the IPC flag.
+ DCHECK(*flags & HistogramBase::kIPCSerializationSourceFlag);
+ *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+ return true;
+}
+
+bool ValidateRangeChecksum(const HistogramBase& histogram,
+ uint32 range_checksum) {
+ const Histogram& casted_histogram =
+ static_cast<const Histogram&>(histogram);
+
+ return casted_histogram.bucket_ranges()->checksum() == range_checksum;
+}
+
+} // namespace
+
typedef HistogramBase::Count Count;
typedef HistogramBase::Sample Sample;
@@ -153,117 +201,6 @@ void Histogram::AddBoolean(bool value) {
DCHECK(false);
}
-void Histogram::AddSamples(const HistogramSamples& samples) {
- samples_->Add(samples);
-}
-
-bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
- return samples_->AddFromPickle(iter);
-}
-
-// static
-string Histogram::SerializeHistogramInfo(const Histogram& histogram,
- const HistogramSamples& snapshot) {
- DCHECK(histogram.bucket_ranges()->HasValidChecksum());
-
- Pickle pickle;
- pickle.WriteString(histogram.histogram_name());
- pickle.WriteInt(histogram.declared_min());
- pickle.WriteInt(histogram.declared_max());
- pickle.WriteUInt64(histogram.bucket_count());
- pickle.WriteUInt32(histogram.bucket_ranges()->checksum());
- pickle.WriteInt(histogram.GetHistogramType());
- pickle.WriteInt(histogram.flags());
-
- histogram.SerializeRanges(&pickle);
-
- snapshot.Serialize(&pickle);
-
- return string(static_cast<const char*>(pickle.data()), pickle.size());
-}
-
-// static
-bool Histogram::DeserializeHistogramInfo(const string& histogram_info) {
- if (histogram_info.empty()) {
- return false;
- }
-
- Pickle pickle(histogram_info.data(),
- static_cast<int>(histogram_info.size()));
- string histogram_name;
- int declared_min;
- int declared_max;
- uint64 bucket_count;
- uint32 range_checksum;
- int histogram_type;
- int pickle_flags;
-
- PickleIterator iter(pickle);
- if (!iter.ReadString(&histogram_name) ||
- !iter.ReadInt(&declared_min) ||
- !iter.ReadInt(&declared_max) ||
- !iter.ReadUInt64(&bucket_count) ||
- !iter.ReadUInt32(&range_checksum) ||
- !iter.ReadInt(&histogram_type) ||
- !iter.ReadInt(&pickle_flags)) {
- DLOG(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) {
- DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
- return false;
- }
-
- Flags flags = static_cast<Flags>(pickle_flags & ~kIPCSerializationSourceFlag);
-
- 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 if (histogram_type == CUSTOM_HISTOGRAM) {
- vector<Sample> sample_ranges(bucket_count);
- if (!CustomHistogram::DeserializeRanges(&iter, &sample_ranges)) {
- DLOG(ERROR) << "Pickle error decoding ranges: " << histogram_name;
- return false;
- }
- render_histogram =
- CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags);
- } else {
- DLOG(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->GetHistogramType(), histogram_type);
-
- if (render_histogram->bucket_ranges()->checksum() != range_checksum) {
- return false;
- }
-
- if (render_histogram->flags() & kIPCSerializationSourceFlag) {
- DVLOG(1) << "Single process mode, histogram observed and not copied: "
- << histogram_name;
- return true;
- }
-
- DCHECK_EQ(flags & render_histogram->flags(), flags);
- return render_histogram->AddSamplesFromPickle(&iter);
-}
-
// static
const int Histogram::kCommonRaceBasedCountMismatch = 5;
@@ -363,6 +300,14 @@ scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
return SnapshotSampleVector().PassAs<HistogramSamples>();
}
+void Histogram::AddSamples(const HistogramSamples& samples) {
+ samples_->Add(samples);
+}
+
+bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
+ return samples_->AddFromPickle(iter);
+}
+
// The following methods provide a graphical histogram display.
void Histogram::WriteHTMLGraph(string* output) const {
// TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
@@ -375,6 +320,16 @@ void Histogram::WriteAscii(string* output) const {
WriteAsciiImpl(true, "\n", output);
}
+bool Histogram::SerializeInfoImpl(Pickle* pickle) const {
+ DCHECK(bucket_ranges()->HasValidChecksum());
+ return pickle->WriteString(histogram_name()) &&
+ pickle->WriteInt(flags()) &&
+ pickle->WriteInt(declared_min()) &&
+ pickle->WriteInt(declared_max()) &&
+ pickle->WriteUInt64(bucket_count()) &&
+ pickle->WriteUInt32(bucket_ranges()->checksum());
+}
+
Histogram::Histogram(const string& name,
Sample minimum,
Sample maximum,
@@ -397,10 +352,6 @@ Histogram::~Histogram() {
}
}
-bool Histogram::SerializeRanges(Pickle* pickle) const {
- return true;
-}
-
bool Histogram::PrintEmptyBucket(size_t index) const {
return true;
}
@@ -431,6 +382,31 @@ const string Histogram::GetAsciiBucketRange(size_t i) const {
//------------------------------------------------------------------------------
// Private methods
+// static
+HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
+ string histogram_name;
+ int flags;
+ int declared_min;
+ int declared_max;
+ uint64 bucket_count;
+ uint32 range_checksum;
+
+ if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+ &declared_max, &bucket_count, &range_checksum)) {
+ return NULL;
+ }
+
+ // Find or create the local version of the histogram in this process.
+ HistogramBase* histogram = Histogram::FactoryGet(
+ histogram_name, declared_min, declared_max, bucket_count, flags);
+
+ if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+ // The serialized histogram might be corrupted.
+ return NULL;
+ }
+ return histogram;
+}
+
scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
samples->Add(*samples_);
@@ -710,6 +686,29 @@ void LinearHistogram::InitializeBucketRanges(Sample minimum,
ranges->ResetChecksum();
}
+// static
+HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+ string histogram_name;
+ int flags;
+ int declared_min;
+ int declared_max;
+ uint64 bucket_count;
+ uint32 range_checksum;
+
+ if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+ &declared_max, &bucket_count, &range_checksum)) {
+ return NULL;
+ }
+
+ HistogramBase* histogram = LinearHistogram::FactoryGet(
+ histogram_name, declared_min, declared_max, bucket_count, flags);
+ if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+ // The serialized histogram might be corrupted.
+ return NULL;
+ }
+ return histogram;
+}
+
//------------------------------------------------------------------------------
// This section provides implementation for BooleanHistogram.
//------------------------------------------------------------------------------
@@ -750,6 +749,28 @@ BooleanHistogram::BooleanHistogram(const string& name,
const BucketRanges* ranges)
: LinearHistogram(name, 1, 2, 3, ranges) {}
+HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+ string histogram_name;
+ int flags;
+ int declared_min;
+ int declared_max;
+ uint64 bucket_count;
+ uint32 range_checksum;
+
+ if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+ &declared_max, &bucket_count, &range_checksum)) {
+ return NULL;
+ }
+
+ HistogramBase* histogram = BooleanHistogram::FactoryGet(
+ histogram_name, flags);
+ if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+ // The serialized histogram might be corrupted.
+ return NULL;
+ }
+ return histogram;
+}
+
//------------------------------------------------------------------------------
// CustomHistogram:
//------------------------------------------------------------------------------
@@ -809,26 +830,52 @@ CustomHistogram::CustomHistogram(const string& name,
ranges->size() - 1,
ranges) {}
-bool CustomHistogram::SerializeRanges(Pickle* pickle) const {
- for (size_t i = 0; i < bucket_ranges()->size(); ++i) {
+bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
+ if (!Histogram::SerializeInfoImpl(pickle))
+ return false;
+
+ // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
+ // write them.
+ for (size_t i = 1; i < bucket_ranges()->size() - 1; ++i) {
if (!pickle->WriteInt(bucket_ranges()->range(i)))
return false;
}
return true;
}
+double CustomHistogram::GetBucketSize(Count current, size_t i) const {
+ return 1;
+}
+
// static
-bool CustomHistogram::DeserializeRanges(
- PickleIterator* iter, vector<Sample>* ranges) {
- for (size_t i = 0; i < ranges->size(); ++i) {
- if (!iter->ReadInt(&(*ranges)[i]))
- return false;
+HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+ string histogram_name;
+ int flags;
+ int declared_min;
+ int declared_max;
+ uint64 bucket_count;
+ uint32 range_checksum;
+
+ if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+ &declared_max, &bucket_count, &range_checksum)) {
+ return NULL;
}
- return true;
-}
-double CustomHistogram::GetBucketSize(Count current, size_t i) const {
- return 1;
+ // First and last ranges are not serialized.
+ vector<Sample> sample_ranges(bucket_count - 1);
+
+ for (size_t i = 0; i < sample_ranges.size(); ++i) {
+ if (!iter->ReadInt(&sample_ranges[i]))
+ return NULL;
+ }
+
+ HistogramBase* histogram = CustomHistogram::FactoryGet(
+ histogram_name, sample_ranges, flags);
+ if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+ // The serialized histogram might be corrupted.
+ return NULL;
+ }
+ return histogram;
}
// static
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 02a975c..ed8de6f 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -375,11 +375,6 @@ class BASE_EXPORT Histogram : public HistogramBase {
NEVER_EXCEEDED_VALUE = 0x10
};
- struct DescriptionPair {
- Sample sample;
- const char* description; // Null means end of a list of pairs.
- };
-
//----------------------------------------------------------------------------
// For a valid histogram, input should follow these restrictions:
// minimum > 0 (if a minimum below 1 is specified, it will implicitly be
@@ -418,25 +413,6 @@ class BASE_EXPORT Histogram : public HistogramBase {
Add(static_cast<int>(time.InMilliseconds()));
}
- void AddSamples(const HistogramSamples& samples);
- bool AddSamplesFromPickle(PickleIterator* iter);
-
- // Convenience methods for serializing/deserializing the histograms.
- // Histograms from Renderer process are serialized and sent to the browser.
- // Browser process reconstructs the histogram from the pickled version
- // accumulates the browser-side shadow copy of histograms (that mirror
- // histograms created in the renderer).
-
- // Serialize the given snapshot of a Histogram into a String. Uses
- // Pickle class to flatten the object.
- static std::string SerializeHistogramInfo(const Histogram& histogram,
- const HistogramSamples& snapshot);
-
- // The following method accepts a list of pickled histograms and
- // builds a histogram and updates shadow copy of histogram data in the
- // browser process.
- static bool DeserializeHistogramInfo(const std::string& histogram_info);
-
// This constant if for FindCorruption. Since snapshots of histograms are
// taken asynchronously relative to sampling, and our counting code currently
// does not prevent race conditions, it is pretty likely that we'll catch a
@@ -480,6 +456,8 @@ class BASE_EXPORT Histogram : public HistogramBase {
size_t bucket_count) const OVERRIDE;
virtual void Add(Sample value) OVERRIDE;
virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
+ virtual void AddSamples(const HistogramSamples& samples) OVERRIDE;
+ virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE;
virtual void WriteHTMLGraph(std::string* output) const OVERRIDE;
virtual void WriteAscii(std::string* output) const OVERRIDE;
@@ -494,11 +472,8 @@ class BASE_EXPORT Histogram : public HistogramBase {
virtual ~Histogram();
- // Serialize the histogram's ranges to |*pickle|, returning true on success.
- // Most subclasses can leave this no-op implementation, but some will want to
- // override it, especially if the ranges cannot be re-derived from other
- // serialized parameters.
- virtual bool SerializeRanges(Pickle* pickle) const;
+ // HistogramBase implementation:
+ virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;
// Method to override to skip the display of the i'th bucket if it's empty.
virtual bool PrintEmptyBucket(size_t index) const;
@@ -522,6 +497,10 @@ class BASE_EXPORT Histogram : public HistogramBase {
friend class StatisticsRecorder; // To allow it to delete duplicates.
friend class StatisticsRecorderTest;
+ friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ PickleIterator* iter);
+ static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
// Implementation of SnapshotSamples function.
scoped_ptr<SampleVector> SnapshotSampleVector() const;
@@ -596,6 +575,11 @@ class BASE_EXPORT LinearHistogram : public Histogram {
size_t bucket_count,
int32 flags);
+ struct DescriptionPair {
+ Sample sample;
+ const char* description; // Null means end of a list of pairs.
+ };
+
// Create a LinearHistogram and store a list of number/text values for use in
// writing the histogram graph.
// |descriptions| can be NULL, which means no special descriptions to set. If
@@ -635,6 +619,10 @@ class BASE_EXPORT LinearHistogram : public Histogram {
virtual bool PrintEmptyBucket(size_t index) const OVERRIDE;
private:
+ friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ PickleIterator* iter);
+ static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
// For some ranges, we store a printable description of a bucket range.
// If there is no desciption, then GetAsciiBucketRange() uses parent class
// to provide a description.
@@ -658,6 +646,10 @@ class BASE_EXPORT BooleanHistogram : public LinearHistogram {
private:
BooleanHistogram(const std::string& name, const BucketRanges* ranges);
+ friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ PickleIterator* iter);
+ static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
};
@@ -685,20 +677,20 @@ class BASE_EXPORT CustomHistogram : public Histogram {
// TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
size_t num_values);
-
- // Helper for deserializing CustomHistograms. |*ranges| should already be
- // correctly sized before this call. Return true on success.
- static bool DeserializeRanges(PickleIterator* iter,
- std::vector<Sample>* ranges);
protected:
CustomHistogram(const std::string& name,
const BucketRanges* ranges);
- virtual bool SerializeRanges(Pickle* pickle) const OVERRIDE;
+ // HistogramBase implementation:
+ virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;
virtual double GetBucketSize(Count current, size_t i) const OVERRIDE;
private:
+ friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ PickleIterator* iter);
+ static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
static BucketRanges* CreateBucketRangesFromCustomRanges(
const std::vector<Sample>& custom_ranges);
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
index bcfb57f..6396132 100644
--- a/base/metrics/histogram_base.cc
+++ b/base/metrics/histogram_base.cc
@@ -9,6 +9,10 @@
#include "base/logging.h"
#include "base/json/json_string_value_serializer.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/pickle.h"
#include "base/values.h"
namespace base {
@@ -31,6 +35,41 @@ std::string HistogramTypeToString(HistogramType type) {
return "UNKNOWN";
}
+HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) {
+ int type;
+ if (!iter->ReadInt(&type))
+ return NULL;
+
+ switch (type) {
+ case HISTOGRAM:
+ return Histogram::DeserializeInfoImpl(iter);
+ case LINEAR_HISTOGRAM:
+ return LinearHistogram::DeserializeInfoImpl(iter);
+ case BOOLEAN_HISTOGRAM:
+ return BooleanHistogram::DeserializeInfoImpl(iter);
+ case CUSTOM_HISTOGRAM:
+ return CustomHistogram::DeserializeInfoImpl(iter);
+ case SPARSE_HISTOGRAM:
+ return SparseHistogram::DeserializeInfoImpl(iter);
+ default:
+ return NULL;
+ }
+}
+
+void DeserializeHistogramAndAddSamples(PickleIterator* iter) {
+ HistogramBase* histogram = DeserializeHistogramInfo(iter);
+ if (!histogram)
+ return;
+
+ if (histogram->flags() & base::HistogramBase::kIPCSerializationSourceFlag) {
+ DVLOG(1) << "Single process mode, histogram observed and not copied: "
+ << histogram->histogram_name();
+ return;
+ }
+ histogram->AddSamplesFromPickle(iter);
+}
+
+
const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
HistogramBase::HistogramBase(const std::string& name)
@@ -47,6 +86,12 @@ void HistogramBase::ClearFlags(int32 flags) {
flags_ &= ~flags;
}
+bool HistogramBase::SerializeInfo(Pickle* pickle) const {
+ if (!pickle->WriteInt(GetHistogramType()))
+ return false;
+ return SerializeInfoImpl(pickle);
+}
+
void HistogramBase::WriteJSON(std::string* output) const {
Count count;
scoped_ptr<ListValue> buckets(new ListValue());
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
index 302795a..69e1437 100644
--- a/base/metrics/histogram_base.h
+++ b/base/metrics/histogram_base.h
@@ -11,9 +11,13 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
+class Pickle;
+class PickleIterator;
+
namespace base {
class DictionaryValue;
+class HistogramBase;
class HistogramSamples;
class ListValue;
@@ -32,6 +36,15 @@ enum BASE_EXPORT HistogramType {
std::string HistogramTypeToString(HistogramType type);
+// Create or find existing histogram that matches the pickled info.
+// Returns NULL if the pickled data has problems.
+BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ PickleIterator* iter);
+
+// Create or find existing histogram and add the samples from pickle.
+// Silently returns when seeing any data problem in the pickle.
+BASE_EXPORT void DeserializeHistogramAndAddSamples(PickleIterator* iter);
+
////////////////////////////////////////////////////////////////////////////////
class BASE_EXPORT HistogramBase {
@@ -69,14 +82,22 @@ class BASE_EXPORT HistogramBase {
virtual HistogramType GetHistogramType() const = 0;
// Whether the histogram has construction arguments as parameters specified.
- // For histograms that don't have the concept of minimum, maximum or
- // bucket_count, this function always returns false.
+ // For histograms that don't have the concept of |minimum|, |maximum| or
+ // |bucket_count|, this function always returns false.
virtual bool HasConstructionArguments(Sample minimum,
Sample maximum,
size_t bucket_count) const = 0;
virtual void Add(Sample value) = 0;
+ virtual void AddSamples(const HistogramSamples& samples) = 0;
+ virtual bool AddSamplesFromPickle(PickleIterator* iter) = 0;
+
+ // Serialize the histogram info into |pickle|.
+ // Note: This only serializes the construction arguments of the histogram, but
+ // does not serialize the samples.
+ bool SerializeInfo(Pickle* pickle) const;
+
// Snapshot the current complete set of sample data.
// Override with atomic/locked snapshot if needed.
virtual scoped_ptr<HistogramSamples> SnapshotSamples() const = 0;
@@ -91,6 +112,9 @@ class BASE_EXPORT HistogramBase {
void WriteJSON(std::string* output) const;
protected:
+ // Subclasses should implement this function to make SerializeInfo work.
+ virtual bool SerializeInfoImpl(Pickle* pickle) const = 0;
+
// Writes information about the construction parameters in |params|.
virtual void GetParameters(DictionaryValue* params) const = 0;
diff --git a/base/metrics/histogram_base_unittest.cc b/base/metrics/histogram_base_unittest.cc
new file mode 100644
index 0000000..4944f31
--- /dev/null
+++ b/base/metrics/histogram_base_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class HistogramBaseTest : public testing::Test {
+ protected:
+ HistogramBaseTest() {
+ // Each test will have a clean state (no Histogram / BucketRanges
+ // registered).
+ statistics_recorder_ = NULL;
+ ResetStatisticsRecorder();
+ }
+
+ virtual ~HistogramBaseTest() {
+ delete statistics_recorder_;
+ }
+
+ void ResetStatisticsRecorder() {
+ delete statistics_recorder_;
+ statistics_recorder_ = new StatisticsRecorder();
+ }
+
+ private:
+ StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(HistogramBaseTest, DeserializeHistogram) {
+ HistogramBase* histogram = Histogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10,
+ (HistogramBase::kUmaTargetedHistogramFlag |
+ HistogramBase::kIPCSerializationSourceFlag));
+
+ Pickle pickle;
+ ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+ PickleIterator iter(pickle);
+ HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+ EXPECT_EQ(histogram, deserialized);
+
+ ResetStatisticsRecorder();
+
+ PickleIterator iter2(pickle);
+ deserialized = DeserializeHistogramInfo(&iter2);
+ EXPECT_TRUE(deserialized);
+ EXPECT_NE(histogram, deserialized);
+ EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+ EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
+
+ // kIPCSerializationSourceFlag will be cleared.
+ EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeHistogramAndAddSamples) {
+ HistogramBase* histogram = Histogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag);
+ histogram->Add(1);
+ histogram->Add(10);
+ histogram->Add(100);
+ histogram->Add(1000);
+
+ Pickle pickle;
+ ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+ histogram->SnapshotSamples()->Serialize(&pickle);
+
+ PickleIterator iter(pickle);
+ DeserializeHistogramAndAddSamples(&iter);
+
+ // The histogram has kIPCSerializationSourceFlag. So samples will be ignored.
+ scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+ EXPECT_EQ(1, snapshot->GetCount(1));
+ EXPECT_EQ(1, snapshot->GetCount(10));
+ EXPECT_EQ(1, snapshot->GetCount(100));
+ EXPECT_EQ(1, snapshot->GetCount(1000));
+
+ // Clear kIPCSerializationSourceFlag to emulate multi-process usage.
+ histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag);
+ PickleIterator iter2(pickle);
+ DeserializeHistogramAndAddSamples(&iter2);
+
+ scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+ EXPECT_EQ(2, snapshot2->GetCount(1));
+ EXPECT_EQ(2, snapshot2->GetCount(10));
+ EXPECT_EQ(2, snapshot2->GetCount(100));
+ EXPECT_EQ(2, snapshot2->GetCount(1000));
+}
+
+TEST_F(HistogramBaseTest, DeserializeLinearHistogram) {
+ HistogramBase* histogram = LinearHistogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10,
+ HistogramBase::kIPCSerializationSourceFlag);
+
+ Pickle pickle;
+ ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+ PickleIterator iter(pickle);
+ HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+ EXPECT_EQ(histogram, deserialized);
+
+ ResetStatisticsRecorder();
+
+ PickleIterator iter2(pickle);
+ deserialized = DeserializeHistogramInfo(&iter2);
+ EXPECT_TRUE(deserialized);
+ EXPECT_NE(histogram, deserialized);
+ EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+ EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
+ EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) {
+ HistogramBase* histogram = BooleanHistogram::FactoryGet(
+ "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
+
+ Pickle pickle;
+ ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+ PickleIterator iter(pickle);
+ HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+ EXPECT_EQ(histogram, deserialized);
+
+ ResetStatisticsRecorder();
+
+ PickleIterator iter2(pickle);
+ deserialized = DeserializeHistogramInfo(&iter2);
+ EXPECT_TRUE(deserialized);
+ EXPECT_NE(histogram, deserialized);
+ EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+ EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3));
+ EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeCustomHistogram) {
+ std::vector<HistogramBase::Sample> ranges;
+ ranges.push_back(13);
+ ranges.push_back(5);
+ ranges.push_back(9);
+
+ HistogramBase* histogram = CustomHistogram::FactoryGet(
+ "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag);
+
+ Pickle pickle;
+ ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+ PickleIterator iter(pickle);
+ HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+ EXPECT_EQ(histogram, deserialized);
+
+ ResetStatisticsRecorder();
+
+ PickleIterator iter2(pickle);
+ deserialized = DeserializeHistogramInfo(&iter2);
+ EXPECT_TRUE(deserialized);
+ EXPECT_NE(histogram, deserialized);
+ EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+ EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4));
+ EXPECT_EQ(0, deserialized->flags());
+}
+
+// TODO(kaiwang): Add SparseHistogram test.
+
+} // namespace base
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index 9fb9422..ee4e024 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -14,6 +14,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -49,18 +50,18 @@ class HistogramTest : public testing::Test {
TEST_F(HistogramTest, BasicTest) {
// Try basic construction
Histogram* histogram(Histogram::FactoryGet(
- "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags));
EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
Histogram* linear_histogram(LinearHistogram::FactoryGet(
- "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags));
EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
vector<int> custom_ranges;
custom_ranges.push_back(1);
custom_ranges.push_back(5);
Histogram* custom_histogram(CustomHistogram::FactoryGet(
- "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+ "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags));
EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
// Use standard macros (but with fixed samples)
@@ -79,7 +80,7 @@ TEST_F(HistogramTest, NameMatchTest) {
HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
Histogram* histogram(LinearHistogram::FactoryGet(
- "DuplicatedHistogram", 1, 101, 102, Histogram::kNoFlags));
+ "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags));
scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
EXPECT_EQ(2, samples->TotalCount());
EXPECT_EQ(2, samples->GetCountAtIndex(10));
@@ -99,7 +100,7 @@ TEST_F(HistogramTest, ExponentialRangesTest) {
// Check the corresponding Histogram will use the correct ranges.
Histogram* histogram(Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags));
+ "Histogram", 1, 64, 8, HistogramBase::kNoFlags));
EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
// When bucket count is limited, exponential ranges will partially look like
@@ -126,7 +127,7 @@ TEST_F(HistogramTest, ExponentialRangesTest) {
// Check the corresponding Histogram will use the correct ranges.
Histogram* histogram2(Histogram::FactoryGet(
- "Histogram2", 1, 32, 15, Histogram::kNoFlags));
+ "Histogram2", 1, 32, 15, HistogramBase::kNoFlags));
EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
}
@@ -139,7 +140,7 @@ TEST_F(HistogramTest, LinearRangesTest) {
EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
// The correspoding LinearHistogram should use the correct ranges.
Histogram* histogram(
- LinearHistogram::FactoryGet("Linear", 1, 7, 8, Histogram::kNoFlags));
+ LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags));
EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
// Linear ranges are not divisible.
@@ -153,7 +154,7 @@ TEST_F(HistogramTest, LinearRangesTest) {
EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5));
// The correspoding LinearHistogram should use the correct ranges.
Histogram* histogram2(
- LinearHistogram::FactoryGet("Linear2", 1, 6, 5, Histogram::kNoFlags));
+ LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags));
EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
}
@@ -176,7 +177,7 @@ TEST_F(HistogramTest, CustomHistogramTest) {
custom_ranges.push_back(1);
custom_ranges.push_back(2);
Histogram* histogram = CustomHistogram::FactoryGet(
- "TestCustomHistogram1", custom_ranges, Histogram::kNoFlags);
+ "TestCustomHistogram1", custom_ranges, HistogramBase::kNoFlags);
const BucketRanges* ranges = histogram->bucket_ranges();
ASSERT_EQ(4u, ranges->size());
EXPECT_EQ(0, ranges->range(0)); // Auto added.
@@ -189,7 +190,7 @@ TEST_F(HistogramTest, CustomHistogramTest) {
custom_ranges.push_back(2);
custom_ranges.push_back(1);
histogram = CustomHistogram::FactoryGet(
- "TestCustomHistogram2", custom_ranges, Histogram::kNoFlags);
+ "TestCustomHistogram2", custom_ranges, HistogramBase::kNoFlags);
ranges = histogram->bucket_ranges();
ASSERT_EQ(4u, ranges->size());
EXPECT_EQ(0, ranges->range(0));
@@ -203,7 +204,7 @@ TEST_F(HistogramTest, CustomHistogramTest) {
custom_ranges.push_back(1);
custom_ranges.push_back(4);
histogram = CustomHistogram::FactoryGet(
- "TestCustomHistogram3", custom_ranges, Histogram::kNoFlags);
+ "TestCustomHistogram3", custom_ranges, HistogramBase::kNoFlags);
ranges = histogram->bucket_ranges();
ASSERT_EQ(4u, ranges->size());
EXPECT_EQ(0, ranges->range(0));
@@ -222,7 +223,7 @@ TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
custom_ranges.push_back(4);
Histogram* histogram = CustomHistogram::FactoryGet(
- "2BucketsCustomHistogram", custom_ranges, Histogram::kNoFlags);
+ "2BucketsCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
const BucketRanges* ranges = histogram->bucket_ranges();
ASSERT_EQ(3u, ranges->size());
EXPECT_EQ(0, ranges->range(0));
@@ -234,7 +235,7 @@ TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
TEST_F(HistogramTest, BoundsTest) {
const size_t kBucketCount = 50;
Histogram* histogram(Histogram::FactoryGet(
- "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags));
+ "Bounded", 10, 100, kBucketCount, HistogramBase::kNoFlags));
// Put two samples "out of bounds" above and below.
histogram->Add(5);
@@ -256,8 +257,9 @@ TEST_F(HistogramTest, BoundsTest) {
custom_ranges.push_back(10);
custom_ranges.push_back(50);
custom_ranges.push_back(100);
- Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
- "TestCustomRangeBoundedHistogram", custom_ranges, Histogram::kNoFlags));
+ Histogram* test_custom_histogram = CustomHistogram::FactoryGet(
+ "TestCustomRangeBoundedHistogram", custom_ranges,
+ HistogramBase::kNoFlags);
// Put two samples "out of bounds" above and below.
test_custom_histogram->Add(5);
@@ -279,7 +281,7 @@ TEST_F(HistogramTest, BoundsTest) {
// Check to be sure samples land as expected is "correct" buckets.
TEST_F(HistogramTest, BucketPlacementTest) {
Histogram* histogram(Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags));
+ "Histogram", 1, 64, 8, HistogramBase::kNoFlags));
// Add i+1 samples to the i'th bucket.
histogram->Add(0);
@@ -298,7 +300,7 @@ TEST_F(HistogramTest, BucketPlacementTest) {
TEST_F(HistogramTest, CorruptSampleCounts) {
Histogram* histogram(Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags)); // As per header file.
+ "Histogram", 1, 64, 8, HistogramBase::kNoFlags)); // As per header file.
// Add some samples.
histogram->Add(20);
@@ -325,7 +327,7 @@ TEST_F(HistogramTest, CorruptSampleCounts) {
TEST_F(HistogramTest, CorruptBucketBounds) {
Histogram* histogram(Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags)); // As per header file.
+ "Histogram", 1, 64, 8, HistogramBase::kNoFlags)); // As per header file.
scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
EXPECT_EQ(Histogram::NO_INCONSISTENCIES,
@@ -357,6 +359,81 @@ TEST_F(HistogramTest, CorruptBucketBounds) {
bucket_ranges->set_range(4, bucket_ranges->range(4) + 1);
}
+TEST_F(HistogramTest, HistogramSerializeInfo) {
+ Histogram* histogram = Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, HistogramBase::kIPCSerializationSourceFlag);
+
+ Pickle pickle;
+ histogram->SerializeInfo(&pickle);
+
+ PickleIterator iter(pickle);
+
+ int type;
+ EXPECT_TRUE(iter.ReadInt(&type));
+ EXPECT_EQ(HISTOGRAM, type);
+
+ std::string name;
+ EXPECT_TRUE(iter.ReadString(&name));
+ EXPECT_EQ("Histogram", name);
+
+ int flag;
+ EXPECT_TRUE(iter.ReadInt(&flag));
+ EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
+
+ int min;
+ EXPECT_TRUE(iter.ReadInt(&min));
+ EXPECT_EQ(1, min);
+
+ int max;
+ EXPECT_TRUE(iter.ReadInt(&max));
+ EXPECT_EQ(64, max);
+
+ int64 bucket_count;
+ EXPECT_TRUE(iter.ReadInt64(&bucket_count));
+ EXPECT_EQ(8, bucket_count);
+
+ uint32 checksum;
+ EXPECT_TRUE(iter.ReadUInt32(&checksum));
+ EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
+
+ // No more data in the pickle.
+ EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
+ vector<int> custom_ranges;
+ custom_ranges.push_back(10);
+ custom_ranges.push_back(100);
+
+ Histogram* custom_histogram = CustomHistogram::FactoryGet(
+ "TestCustomRangeBoundedHistogram",
+ custom_ranges,
+ HistogramBase::kNoFlags);
+ Pickle pickle;
+ custom_histogram->SerializeInfo(&pickle);
+
+ // Validate the pickle.
+ PickleIterator iter(pickle);
+
+ int i;
+ std::string s;
+ int64 bucket_count;
+ uint32 ui32;
+ EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
+ iter.ReadInt(&i) && iter.ReadInt(&i) &&
+ iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32));
+ EXPECT_EQ(3, bucket_count);
+
+ int range;
+ EXPECT_TRUE(iter.ReadInt(&range));
+ EXPECT_EQ(10, range);
+ EXPECT_TRUE(iter.ReadInt(&range));
+ EXPECT_EQ(100, range);
+
+ // No more data in the pickle.
+ EXPECT_FALSE(iter.SkipBytes(1));
+}
+
#if GTEST_HAS_DEATH_TEST
// For Histogram, LinearHistogram and CustomHistogram, the minimum for a
// declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
@@ -364,13 +441,14 @@ TEST_F(HistogramTest, CorruptBucketBounds) {
// those limits. This is for backwards compatibility.
TEST(HistogramDeathTest, BadRangesTest) {
Histogram* histogram = Histogram::FactoryGet(
- "BadRanges", 0, HistogramBase::kSampleType_MAX, 8, Histogram::kNoFlags);
+ "BadRanges", 0, HistogramBase::kSampleType_MAX, 8,
+ HistogramBase::kNoFlags);
EXPECT_EQ(1, histogram->declared_min());
EXPECT_EQ(HistogramBase::kSampleType_MAX - 1, histogram->declared_max());
Histogram* linear_histogram = LinearHistogram::FactoryGet(
"BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
- Histogram::kNoFlags);
+ HistogramBase::kNoFlags);
EXPECT_EQ(1, linear_histogram->declared_min());
EXPECT_EQ(HistogramBase::kSampleType_MAX - 1,
linear_histogram->declared_max());
@@ -379,7 +457,7 @@ TEST(HistogramDeathTest, BadRangesTest) {
custom_ranges.push_back(0);
custom_ranges.push_back(5);
Histogram* custom_histogram1 = CustomHistogram::FactoryGet(
- "BadRangesCustom", custom_ranges, Histogram::kNoFlags);
+ "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags);
const BucketRanges* ranges = custom_histogram1->bucket_ranges();
ASSERT_EQ(3u, ranges->size());
EXPECT_EQ(0, ranges->range(0));
@@ -389,14 +467,14 @@ TEST(HistogramDeathTest, BadRangesTest) {
// CustomHistogram does not accepts kSampleType_MAX as range.
custom_ranges.push_back(HistogramBase::kSampleType_MAX);
EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges,
- Histogram::kNoFlags),
+ HistogramBase::kNoFlags),
"");
// CustomHistogram needs at least 1 valid range.
custom_ranges.clear();
custom_ranges.push_back(0);
EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
- Histogram::kNoFlags),
+ HistogramBase::kNoFlags),
"");
}
#endif
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
index 9bd78e7..42468cb 100644
--- a/base/metrics/sample_map.cc
+++ b/base/metrics/sample_map.cc
@@ -44,11 +44,6 @@ scoped_ptr<SampleCountIterator> SampleMap::Iterator() const {
return scoped_ptr<SampleCountIterator>(new SampleMapIterator(sample_counts_));
}
-void SampleMap::ResetRedundantCount(Count count) {
- IncreaseRedundantCount(-redundant_count());
- IncreaseRedundantCount(count);
-}
-
bool SampleMap::AddSubtractImpl(SampleCountIterator* iter,
HistogramSamples::Operator op) {
Sample min;
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
index 65a31f1..22c391bb 100644
--- a/base/metrics/sample_map.h
+++ b/base/metrics/sample_map.h
@@ -30,8 +30,6 @@ class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
virtual HistogramBase::Count TotalCount() const OVERRIDE;
virtual scoped_ptr<SampleCountIterator> Iterator() const OVERRIDE;
- void ResetRedundantCount(HistogramBase::Count count);
-
protected:
virtual bool AddSubtractImpl(
SampleCountIterator* iter,
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
index 169037d..c64f7cb 100644
--- a/base/metrics/sparse_histogram.cc
+++ b/base/metrics/sparse_histogram.cc
@@ -6,6 +6,7 @@
#include "base/metrics/sample_map.h"
#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
#include "base/synchronization/lock.h"
using std::map;
@@ -39,23 +40,27 @@ bool SparseHistogram::HasConstructionArguments(Sample minimum,
void SparseHistogram::Add(Sample value) {
base::AutoLock auto_lock(lock_);
- sample_counts_[value]++;
- redundant_count_ += 1;
+ samples_.Accumulate(value, 1);
}
scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
scoped_ptr<SampleMap> snapshot(new SampleMap());
base::AutoLock auto_lock(lock_);
- for(map<Sample, Count>::const_iterator it = sample_counts_.begin();
- it != sample_counts_.end();
- ++it) {
- snapshot->Accumulate(it->first, it->second);
- }
- snapshot->ResetRedundantCount(redundant_count_);
+ snapshot->Add(samples_);
return snapshot.PassAs<HistogramSamples>();
}
+void SparseHistogram::AddSamples(const HistogramSamples& samples) {
+ base::AutoLock auto_lock(lock_);
+ samples_.Add(samples);
+}
+
+bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
+ base::AutoLock auto_lock(lock_);
+ return samples_.AddFromPickle(iter);
+}
+
void SparseHistogram::WriteHTMLGraph(string* output) const {
// TODO(kaiwang): Implement.
}
@@ -64,9 +69,26 @@ void SparseHistogram::WriteAscii(string* output) const {
// TODO(kaiwang): Implement.
}
+bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
+ return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
+}
+
SparseHistogram::SparseHistogram(const string& name)
- : HistogramBase(name),
- redundant_count_(0) {}
+ : HistogramBase(name) {}
+
+HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+ string histogram_name;
+ int flags;
+ if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
+ DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
+ return NULL;
+ }
+
+ DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag);
+ flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+ return SparseHistogram::FactoryGet(histogram_name, flags);
+}
void SparseHistogram::GetParameters(DictionaryValue* params) const {
// TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
index a7c5695..346ffeb 100644
--- a/base/metrics/sparse_histogram.h
+++ b/base/metrics/sparse_histogram.h
@@ -13,6 +13,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
+#include "base/metrics/sample_map.h"
#include "base/synchronization/lock.h"
namespace base {
@@ -33,24 +34,35 @@ class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
Sample maximum,
size_t bucket_count) const OVERRIDE;
virtual void Add(Sample value) OVERRIDE;
+ virtual void AddSamples(const HistogramSamples& samples) OVERRIDE;
+ virtual bool AddSamplesFromPickle(PickleIterator* iter) OVERRIDE;
+ virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
virtual void WriteHTMLGraph(std::string* output) const OVERRIDE;
virtual void WriteAscii(std::string* output) const OVERRIDE;
- virtual scoped_ptr<HistogramSamples> SnapshotSamples() const OVERRIDE;
+
+ protected:
+ // HistogramBase implementation:
+ virtual bool SerializeInfoImpl(Pickle* pickle) const OVERRIDE;
private:
// Clients should always use FactoryGet to create SparseHistogram.
SparseHistogram(const std::string& name);
+ friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ PickleIterator* iter);
+ static HistogramBase* DeserializeInfoImpl(PickleIterator* iter);
+
virtual void GetParameters(DictionaryValue* params) const OVERRIDE;
virtual void GetCountAndBucketData(Count* count,
ListValue* buckets) const OVERRIDE;
- friend class SparseHistogramTest; // For constuctor calling.
+ // For constuctor calling.
+ friend class SparseHistogramTest;
- // Protects access to |sample_counts_| and |redundant_count_|.
+ // Protects access to |samples_|.
mutable base::Lock lock_;
- std::map<HistogramBase::Sample, HistogramBase::Count> sample_counts_;
- HistogramBase::Count redundant_count_;
+
+ SampleMap samples_;
DISALLOW_COPY_AND_ASSIGN(SparseHistogram);
};
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc
index b4eb8fd..1b52b6c 100644
--- a/base/metrics/sparse_histogram_unittest.cc
+++ b/base/metrics/sparse_histogram_unittest.cc
@@ -5,8 +5,10 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
#include "base/metrics/sample_map.h"
#include "base/metrics/sparse_histogram.h"
+#include "base/pickle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -19,7 +21,7 @@ class SparseHistogramTest : public testing::Test {
};
TEST_F(SparseHistogramTest, BasicTest) {
- scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse1"));
+ scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
EXPECT_EQ(0, snapshot->TotalCount());
EXPECT_EQ(0, snapshot->sum());
@@ -37,4 +39,29 @@ TEST_F(SparseHistogramTest, BasicTest) {
EXPECT_EQ(1, snapshot2->GetCount(101));
}
+TEST_F(SparseHistogramTest, Serialize) {
+ scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+ histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag);
+
+ Pickle pickle;
+ histogram->SerializeInfo(&pickle);
+
+ PickleIterator iter(pickle);
+
+ int type;
+ EXPECT_TRUE(iter.ReadInt(&type));
+ EXPECT_EQ(SPARSE_HISTOGRAM, type);
+
+ std::string name;
+ EXPECT_TRUE(iter.ReadString(&name));
+ EXPECT_EQ("Sparse", name);
+
+ int flag;
+ EXPECT_TRUE(iter.ReadInt(&flag));
+ EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
+
+ // No more data in the pickle.
+ EXPECT_FALSE(iter.SkipBytes(1));
+}
+
} // namespace base
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 5345735..6d40aff 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -90,6 +90,7 @@ class BASE_EXPORT StatisticsRecorder {
typedef std::map<uint32, std::list<const BucketRanges*>*> RangesMap;
friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
+ friend class HistogramBaseTest;
friend class HistogramTest;
friend class StatisticsRecorderTest;