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); |
} |