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