15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/sparse_histogram.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/sample_map.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/statistics_recorder.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/pickle.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::map;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using std::string;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HistogramBase::Count Count;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef HistogramBase::Sample Sample;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistogramBase* SparseHistogram::FactoryGet(const string& name, int32 flags) {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!histogram) {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // To avoid racy destruction at shutdown, the following will be leaked.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    HistogramBase* tentative_histogram = new SparseHistogram(name);
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    tentative_histogram->SetFlags(flags);
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    histogram =
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return histogram;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SparseHistogram::~SparseHistogram() {}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HistogramType SparseHistogram::GetHistogramType() const {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SPARSE_HISTOGRAM;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool SparseHistogram::HasConstructionArguments(
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Sample expected_minimum,
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Sample expected_maximum,
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    size_t expected_bucket_count) const {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SparseHistogram never has min/max/bucket_count limit.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SparseHistogram::Add(Sample value) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  samples_.Accumulate(value, 1);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<SampleMap> snapshot(new SampleMap());
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::AutoLock auto_lock(lock_);
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  snapshot->Add(samples_);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return snapshot.PassAs<HistogramSamples>();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SparseHistogram::AddSamples(const HistogramSamples& samples) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  samples_.Add(samples);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock auto_lock(lock_);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return samples_.AddFromPickle(iter);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SparseHistogram::WriteHTMLGraph(string* output) const {
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->append("<PRE>");
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WriteAsciiImpl(true, "<br>", output);
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->append("</PRE>");
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SparseHistogram::WriteAscii(string* output) const {
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WriteAsciiImpl(true, "\n", output);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SparseHistogram::SparseHistogram(const string& name)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : HistogramBase(name) {}
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  string histogram_name;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int flags;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag);
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  flags &= ~HistogramBase::kIPCSerializationSourceFlag;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SparseHistogram::FactoryGet(histogram_name, flags);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SparseHistogram::GetParameters(DictionaryValue* params) const {
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SparseHistogram::GetCountAndBucketData(Count* count,
109b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                            int64* sum,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            ListValue* buckets) const {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SparseHistogram::WriteAsciiImpl(bool graph_it,
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     const std::string& newline,
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                     std::string* output) const {
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Get a local copy of the data so we are consistent.
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<HistogramSamples> snapshot = SnapshotSamples();
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Count total_count = snapshot->TotalCount();
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  double scaled_total_count = total_count / 100.0;
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  WriteAsciiHeader(total_count, output);
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  output->append(newline);
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Determine how wide the largest bucket range is (how many digits to print),
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // so that we'll be able to right-align starts for the graphical bars.
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Determine which bucket has the largest sample count so that we can
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // normalize the graphical bar-width relative to that sample count.
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Count largest_count = 0;
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  Sample largest_sample = 0;
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<SampleCountIterator> it = snapshot->Iterator();
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (!it->Done())
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Sample min;
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Sample max;
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Count count;
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    it->Get(&min, &max, &count);
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (min > largest_sample)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      largest_sample = min;
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (count > largest_count)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      largest_count = count;
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    it->Next();
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1;
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // iterate over each item and display them
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  it = snapshot->Iterator();
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (!it->Done())
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  {
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Sample min;
151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Sample max;
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    Count count;
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    it->Get(&min, &max, &count);
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // value is min, so display it
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    string range = GetSimpleAsciiBucketRange(min);
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output->append(range);
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t j = 0; range.size() + j < print_width + 1; ++j)
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      output->push_back(' ');
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (graph_it)
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      WriteAsciiBucketGraph(count, largest_count, output);
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    WriteAsciiBucketValue(count, scaled_total_count, output);
164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    output->append(newline);
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    it->Next();
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void SparseHistogram::WriteAsciiHeader(const Count total_count,
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                       std::string* output) const {
171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  StringAppendF(output,
172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                "Histogram: %s recorded %d samples",
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                histogram_name().c_str(),
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                total_count);
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (flags() & ~kHexRangePrintingFlag)
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
180