| Index: base/histogram.cc
|
| ===================================================================
|
| --- base/histogram.cc (revision 10329)
|
| +++ base/histogram.cc (working copy)
|
| @@ -53,17 +53,16 @@
|
|
|
| Histogram::~Histogram() {
|
| if (registered_)
|
| - StatisticsRecorder::UnRegister(*this);
|
| + StatisticsRecorder::UnRegister(this);
|
| // Just to make sure most derived class did this properly...
|
| DCHECK(ValidateBucketRanges());
|
| }
|
|
|
| -
|
| // Hooks to override stats counter methods. This ensures that we gather all
|
| // input the stats counter sees.
|
| void Histogram::Add(int value) {
|
| if (!registered_)
|
| - registered_ = StatisticsRecorder::Register(*this);
|
| + registered_ = StatisticsRecorder::Register(this);
|
| if (value >= kSampleType_MAX)
|
| value = kSampleType_MAX - 1;
|
| StatsRate::Add(value);
|
| @@ -75,6 +74,10 @@
|
| Accumulate(value, 1, index);
|
| }
|
|
|
| +void Histogram::AddSampleSet(const SampleSet& sample) {
|
| + sample_.Add(sample);
|
| +}
|
| +
|
| // The following methods provide a graphical histogram display.
|
| void Histogram::WriteHTMLGraph(std::string* output) const {
|
| // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
|
| @@ -105,7 +108,7 @@
|
| while (0 == snapshot.counts(largest_non_empty_bucket)) {
|
| if (0 == largest_non_empty_bucket)
|
| break; // All buckets are empty.
|
| - largest_non_empty_bucket--;
|
| + --largest_non_empty_bucket;
|
| }
|
|
|
| // Calculate largest print width needed for any of our bucket range displays.
|
| @@ -121,7 +124,7 @@
|
| int64 remaining = sample_count;
|
| int64 past = 0;
|
| // Output the actual histogram graph.
|
| - for (size_t i = 0; i < bucket_count(); i++) {
|
| + for (size_t i = 0; i < bucket_count(); ++i) {
|
| Count current = snapshot.counts(i);
|
| if (!current && !PrintEmptyBucket(i))
|
| continue;
|
| @@ -129,7 +132,7 @@
|
| StringAppendF(output, "%#*s ", print_width, GetAsciiBucketRange(i).c_str());
|
| if (0 == current && i < bucket_count() - 1 && 0 == snapshot.counts(i + 1)) {
|
| while (i < bucket_count() - 1 && 0 == snapshot.counts(i + 1))
|
| - i++;
|
| + ++i;
|
| output->append("... ");
|
| output->append(newline);
|
| continue; // No reason to plot emptiness.
|
| @@ -169,7 +172,7 @@
|
| ranges_[bucket_count_] = kSampleType_MAX;
|
| InitializeBucketRange();
|
| DCHECK(ValidateBucketRanges());
|
| - registered_ = StatisticsRecorder::Register(*this);
|
| + registered_ = StatisticsRecorder::Register(this);
|
| }
|
|
|
| // Calculate what range of values are held in each bucket.
|
| @@ -199,7 +202,7 @@
|
| if (next > current)
|
| current = next;
|
| else
|
| - current++; // Just do a narrow bucket, and keep trying.
|
| + ++current; // Just do a narrow bucket, and keep trying.
|
| SetBucketRange(bucket_index, current);
|
| }
|
|
|
| @@ -277,7 +280,7 @@
|
|
|
| double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
|
| double max = 0;
|
| - for (size_t i = 0; i < bucket_count() ; i++) {
|
| + for (size_t i = 0; i < bucket_count() ; ++i) {
|
| double current_size = GetBucketSize(snapshot.counts(i), i);
|
| if (current_size > max)
|
| max = current_size;
|
| @@ -349,6 +352,100 @@
|
| output->append(" ");
|
| }
|
|
|
| +// static
|
| +std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
|
| + const SampleSet& snapshot) {
|
| + 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.histogram_type());
|
| + pickle.WriteInt(histogram.flags());
|
| +
|
| + snapshot.Serialize(&pickle);
|
| + return std::string(static_cast<const char*>(pickle.data()), pickle.size());
|
| +}
|
| +
|
| +// static
|
| +void Histogram::DeserializeHistogramList(
|
| + const std::vector<std::string>& histograms) {
|
| + for (std::vector<std::string>::const_iterator it = histograms.begin();
|
| + it < histograms.end();
|
| + ++it) {
|
| + DeserializeHistogramInfo(*it);
|
| + }
|
| +}
|
| +
|
| +// 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()));
|
| + void* iter = NULL;
|
| + size_t bucket_count;
|
| + int declared_min;
|
| + int declared_max;
|
| + int histogram_type;
|
| + int flags;
|
| + std::string histogram_name;
|
| + SampleSet sample;
|
| +
|
| + if (!pickle.ReadString(&iter, &histogram_name) ||
|
| + !pickle.ReadInt(&iter, &declared_min) ||
|
| + !pickle.ReadInt(&iter, &declared_max) ||
|
| + !pickle.ReadSize(&iter, &bucket_count) ||
|
| + !pickle.ReadInt(&iter, &histogram_type) ||
|
| + !pickle.ReadInt(&iter, &flags) ||
|
| + !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
|
| + LOG(ERROR) << "Picke error decoding Histogram: " << histogram_name;
|
| + return false;
|
| + }
|
| +
|
| + Histogram* render_histogram =
|
| + StatisticsRecorder::GetHistogram(histogram_name);
|
| +
|
| + if (render_histogram == NULL) {
|
| + if (histogram_type == EXPONENTIAL) {
|
| + render_histogram = new Histogram(histogram_name.c_str(),
|
| + declared_min,
|
| + declared_max,
|
| + bucket_count);
|
| + } else if (histogram_type == LINEAR) {
|
| + render_histogram = reinterpret_cast<Histogram*>
|
| + (new LinearHistogram(histogram_name.c_str(),
|
| + declared_min,
|
| + declared_max,
|
| + bucket_count));
|
| + } else {
|
| + LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " <<
|
| + histogram_type;
|
| + return false;
|
| + }
|
| + DCHECK(!(flags & kRendererHistogramFlag));
|
| + render_histogram->SetFlags(flags | kRendererHistogramFlag);
|
| + }
|
| +
|
| + DCHECK(declared_min == render_histogram->declared_min());
|
| + DCHECK(declared_max == render_histogram->declared_max());
|
| + DCHECK(bucket_count == render_histogram->bucket_count());
|
| + DCHECK(histogram_type == render_histogram->histogram_type());
|
| +
|
| + if (render_histogram->flags() & kRendererHistogramFlag) {
|
| + render_histogram->AddSampleSet(sample);
|
| + } else {
|
| + DLOG(INFO) << "Single thread mode, histogram observed and not copied: " <<
|
| + histogram_name;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +
|
| //------------------------------------------------------------------------------
|
| // Methods for the Histogram::SampleSet class
|
| //------------------------------------------------------------------------------
|
| @@ -383,7 +480,7 @@
|
| Count total = 0;
|
| for (Counts::const_iterator it = counts_.begin();
|
| it != counts_.end();
|
| - it++) {
|
| + ++it) {
|
| total += *it;
|
| }
|
| return total;
|
| @@ -393,7 +490,7 @@
|
| DCHECK(counts_.size() == other.counts_.size());
|
| sum_ += other.sum_;
|
| square_sum_ += other.square_sum_;
|
| - for (size_t index = 0; index < counts_.size(); index++)
|
| + for (size_t index = 0; index < counts_.size(); ++index)
|
| counts_[index] += other.counts_[index];
|
| }
|
|
|
| @@ -404,19 +501,57 @@
|
| // calculated). As a result, we don't currently CHCEK() for positive values.
|
| sum_ -= other.sum_;
|
| square_sum_ -= other.square_sum_;
|
| - for (size_t index = 0; index < counts_.size(); index++) {
|
| + for (size_t index = 0; index < counts_.size(); ++index) {
|
| counts_[index] -= other.counts_[index];
|
| DCHECK(counts_[index] >= 0);
|
| }
|
| }
|
|
|
| +bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
|
| + pickle->WriteInt64(sum_);
|
| + pickle->WriteInt64(square_sum_);
|
| + pickle->WriteSize(counts_.size());
|
| +
|
| + for (size_t index = 0; index < counts_.size(); ++index) {
|
| + pickle->WriteInt(counts_[index]);
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
|
| + DCHECK(counts_.size() == 0);
|
| + DCHECK(sum_ == 0);
|
| + DCHECK(square_sum_ == 0);
|
| +
|
| + size_t counts_size;
|
| +
|
| + if (!pickle.ReadInt64(iter, &sum_) ||
|
| + !pickle.ReadInt64(iter, &square_sum_) ||
|
| + !pickle.ReadSize(iter, &counts_size)) {
|
| + return false;
|
| + }
|
| +
|
| + if (counts_size <= 0)
|
| + return false;
|
| +
|
| + counts_.resize(counts_size, 0);
|
| + for (size_t index = 0; index < counts_size; ++index) {
|
| + if (!pickle.ReadInt(iter, &counts_[index])) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| //------------------------------------------------------------------------------
|
| // LinearHistogram: This histogram uses a traditional set of evenly spaced
|
| // buckets.
|
| //------------------------------------------------------------------------------
|
|
|
| -LinearHistogram::LinearHistogram(const char* name,
|
| - Sample minimum, Sample maximum, size_t bucket_count)
|
| +LinearHistogram::LinearHistogram(const char* name, Sample minimum,
|
| + Sample maximum, size_t bucket_count)
|
| : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) {
|
| InitializeBucketRange();
|
| DCHECK(ValidateBucketRanges());
|
| @@ -457,7 +592,7 @@
|
| double min = declared_min();
|
| double max = declared_max();
|
| size_t i;
|
| - for (i = 1; i < bucket_count(); i++) {
|
| + for (i = 1; i < bucket_count(); ++i) {
|
| double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) /
|
| (bucket_count() - 2);
|
| SetBucketRange(i, static_cast<int> (linear_range + 0.5));
|
| @@ -548,30 +683,30 @@
|
| }
|
|
|
| // static
|
| -bool StatisticsRecorder::Register(const Histogram& histogram) {
|
| +bool StatisticsRecorder::Register(Histogram* histogram) {
|
| if (!histograms_)
|
| return false;
|
| - const std::string name = histogram.histogram_name();
|
| + const std::string name = histogram->histogram_name();
|
| AutoLock auto_lock(*lock_);
|
|
|
| DCHECK(histograms_->end() == histograms_->find(name)) << name << " is already"
|
| "registered as a histogram. Check for duplicate use of the name, or a "
|
| "race where a static initializer could be run by several threads.";
|
| - (*histograms_)[name] = &histogram;
|
| + (*histograms_)[name] = histogram;
|
| return true;
|
| }
|
|
|
| // static
|
| -void StatisticsRecorder::UnRegister(const Histogram& histogram) {
|
| +void StatisticsRecorder::UnRegister(Histogram* histogram) {
|
| if (!histograms_)
|
| return;
|
| - const std::string name = histogram.histogram_name();
|
| + const std::string name = histogram->histogram_name();
|
| AutoLock auto_lock(*lock_);
|
| DCHECK(histograms_->end() != histograms_->find(name));
|
| histograms_->erase(name);
|
| if (dump_on_exit_) {
|
| std::string output;
|
| - histogram.WriteAscii(true, "\n", &output);
|
| + histogram->WriteAscii(true, "\n", &output);
|
| LOG(INFO) << output;
|
| }
|
| }
|
| @@ -593,7 +728,7 @@
|
| GetSnapshot(query, &snapshot);
|
| for (Histograms::iterator it = snapshot.begin();
|
| it != snapshot.end();
|
| - it++) {
|
| + ++it) {
|
| (*it)->WriteHTMLGraph(output);
|
| output->append("<br><hr><br>");
|
| }
|
| @@ -602,7 +737,7 @@
|
|
|
| // static
|
| void StatisticsRecorder::WriteGraph(const std::string& query,
|
| - std::string* output) {
|
| + std::string* output) {
|
| if (!histograms_)
|
| return;
|
| if (query.length())
|
| @@ -614,7 +749,7 @@
|
| GetSnapshot(query, &snapshot);
|
| for (Histograms::iterator it = snapshot.begin();
|
| it != snapshot.end();
|
| - it++) {
|
| + ++it) {
|
| (*it)->WriteAscii(true, "\n", output);
|
| output->append("\n");
|
| }
|
| @@ -627,18 +762,31 @@
|
| AutoLock auto_lock(*lock_);
|
| for (HistogramMap::iterator it = histograms_->begin();
|
| histograms_->end() != it;
|
| - it++) {
|
| + ++it) {
|
| output->push_back(it->second);
|
| }
|
| }
|
|
|
| +Histogram* StatisticsRecorder::GetHistogram(const std::string& query) {
|
| + if (!histograms_)
|
| + return NULL;
|
| + AutoLock auto_lock(*lock_);
|
| + for (HistogramMap::iterator it = histograms_->begin();
|
| + histograms_->end() != it;
|
| + ++it) {
|
| + if (it->first.find(query) != std::string::npos)
|
| + return it->second;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| // private static
|
| void StatisticsRecorder::GetSnapshot(const std::string& query,
|
| Histograms* snapshot) {
|
| AutoLock auto_lock(*lock_);
|
| for (HistogramMap::iterator it = histograms_->begin();
|
| histograms_->end() != it;
|
| - it++) {
|
| + ++it) {
|
| if (it->first.find(query) != std::string::npos)
|
| snapshot->push_back(it->second);
|
| }
|
|
|