diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-25 06:10:17 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-25 06:10:17 +0000 |
commit | 55e57d4d2326bd98d6e14c92ba055754ef77b0e6 (patch) | |
tree | 29f456dcb43fd5754104fe4e302df13532262c83 | |
parent | f78d965fa1ef193595740604508d7d94fde0ef84 (diff) | |
download | chromium_src-55e57d4d2326bd98d6e14c92ba055754ef77b0e6.zip chromium_src-55e57d4d2326bd98d6e14c92ba055754ef77b0e6.tar.gz chromium_src-55e57d4d2326bd98d6e14c92ba055754ef77b0e6.tar.bz2 |
Initial support for Renderer Side Histograms
Patch contributed by Raman Tenneti
see also patch number 21038
Review URL: http://codereview.chromium.org/27034
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10330 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | base/histogram.cc | 200 | ||||
-rw-r--r-- | base/histogram.h | 71 | ||||
-rw-r--r-- | chrome/browser/browser_about_handler.cc | 16 | ||||
-rw-r--r-- | chrome/browser/metrics/metrics_service.cc | 12 | ||||
-rw-r--r-- | chrome/browser/metrics/metrics_service.h | 5 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.cc | 23 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_message_filter.h | 4 | ||||
-rw-r--r-- | chrome/chrome.xcodeproj/project.pbxproj | 8 | ||||
-rw-r--r-- | chrome/common/render_messages_internal.h | 6 | ||||
-rw-r--r-- | chrome/renderer/render_thread.cc | 14 | ||||
-rw-r--r-- | chrome/renderer/render_thread.h | 10 | ||||
-rw-r--r-- | chrome/renderer/renderer.scons | 2 | ||||
-rw-r--r-- | chrome/renderer/renderer.vcproj | 8 | ||||
-rw-r--r-- | chrome/renderer/renderer_histogram_snapshots.cc | 94 | ||||
-rw-r--r-- | chrome/renderer/renderer_histogram_snapshots.h | 54 | ||||
-rw-r--r-- | chrome/renderer/renderer_main.cc | 8 |
17 files changed, 484 insertions, 52 deletions
@@ -27,3 +27,4 @@ Mohamed Mansour <m0.interactive@gmail.com> Joshua Roesslein <jroesslein@gmail.com> Yong Shin <sy3620@gmail.com> Laszlo Radanyi <bekkra@gmail.com> +Raman Tenneti <raman.tenneti@gmail.com> diff --git a/base/histogram.cc b/base/histogram.cc index 79e9497..3234eb9 100644 --- a/base/histogram.cc +++ b/base/histogram.cc @@ -53,17 +53,16 @@ Histogram::Histogram(const char* name, TimeDelta minimum, 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 @@ void Histogram::Add(int value) { 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 @@ void Histogram::WriteAscii(bool graph_it, const std::string& newline, 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 @@ void Histogram::WriteAscii(bool graph_it, const std::string& newline, 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 @@ void Histogram::WriteAscii(bool graph_it, const std::string& newline, 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 @@ void Histogram::Initialize() { 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 @@ void Histogram::InitializeBucketRange() { 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 @@ void Histogram::SetBucketRange(size_t i, Sample value) { 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 @@ void Histogram::WriteAsciiBucketGraph(double current_size, double max_size, 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 Histogram::SampleSet::TotalCount() const { Count total = 0; for (Counts::const_iterator it = counts_.begin(); it != counts_.end(); - it++) { + ++it) { total += *it; } return total; @@ -393,7 +490,7 @@ void Histogram::SampleSet::Add(const SampleSet& other) { 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 @@ void Histogram::SampleSet::Subtract(const SampleSet& other) { // 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 @@ void LinearHistogram::InitializeBucketRange() { 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 @@ bool StatisticsRecorder::WasStarted() { } // 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 @@ void StatisticsRecorder::WriteHTMLGraph(const std::string& query, 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 @@ void StatisticsRecorder::WriteHTMLGraph(const std::string& query, // static void StatisticsRecorder::WriteGraph(const std::string& query, - std::string* output) { + std::string* output) { if (!histograms_) return; if (query.length()) @@ -614,7 +749,7 @@ void StatisticsRecorder::WriteGraph(const std::string& query, 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 @@ void StatisticsRecorder::GetHistograms(Histograms* output) { 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); } diff --git a/base/histogram.h b/base/histogram.h index cf80c09..5bf0fc1 100644 --- a/base/histogram.h +++ b/base/histogram.h @@ -36,6 +36,7 @@ #include <vector> #include "base/lock.h" +#include "base/pickle.h" #include "base/scoped_ptr.h" #include "base/stats_counters.h" @@ -118,6 +119,11 @@ static const int kUmaTargetedHistogramFlag = 0x1; +// This indicates the histogram is shadow copy of renderer histrogram +// constructed by unpick method and updated regularly from renderer upload +// of histograms. +static const int kRendererHistogramFlag = 1 << 4; + #define UMA_HISTOGRAM_TIMES(name, sample) do { \ static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ base::TimeDelta::FromSeconds(10), 50); \ @@ -183,6 +189,11 @@ class Histogram : public StatsRate { static const int kHexRangePrintingFlag; + enum BucketLayout { + EXPONENTIAL, + LINEAR + }; + //---------------------------------------------------------------------------- // Statistic values, developed over the life of the histogram. @@ -206,6 +217,9 @@ class Histogram : public StatsRate { void Add(const SampleSet& other); void Subtract(const SampleSet& other); + bool Serialize(Pickle* pickle) const; + bool Deserialize(void** iter, const Pickle& pickle); + protected: // Actual histogram data is stored in buckets, showing the count of values // that fit into each bucket. @@ -228,6 +242,8 @@ class Histogram : public StatsRate { // input the stats counter sees. virtual void Add(int value); + void AddSampleSet(const SampleSet& sample); + // The following methods provide graphical histogram displays. void WriteHTMLGraph(std::string* output) const; void WriteAscii(bool graph_it, const std::string& newline, @@ -240,6 +256,26 @@ class Histogram : public StatsRate { void ClearFlags(int flags) { flags_ &= ~flags; } int flags() const { return flags_; } + virtual BucketLayout histogram_type() const { return EXPONENTIAL; } + + // 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 SampleSet& 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 void DeserializeHistogramList( + const std::vector<std::string>& histograms); + static bool DeserializeHistogramInfo(const std::string& state); + + //---------------------------------------------------------------------------- // Accessors for serialization and testing. //---------------------------------------------------------------------------- @@ -344,7 +380,7 @@ class Histogram : public StatsRate { // Indicate if successfully registered. bool registered_; - DISALLOW_EVIL_CONSTRUCTORS(Histogram); + DISALLOW_COPY_AND_ASSIGN(Histogram); }; //------------------------------------------------------------------------------ @@ -358,15 +394,18 @@ class LinearHistogram : public Histogram { const char* description; // Null means end of a list of pairs. }; LinearHistogram(const char* name, Sample minimum, - Sample maximum, size_t bucket_count); + Sample maximum, size_t bucket_count); + LinearHistogram(const char* name, base::TimeDelta minimum, - base::TimeDelta maximum, size_t bucket_count); + base::TimeDelta maximum, size_t bucket_count); ~LinearHistogram() {} // Store a list of number/text values for use in rendering the histogram. // The last element in the array has a null in its "description" slot. void SetRangeDescriptions(const DescriptionPair descriptions[]); + virtual BucketLayout histogram_type() const { return LINEAR; } + protected: // Initialize ranges_ mapping. virtual void InitializeBucketRange(); @@ -389,7 +428,7 @@ class LinearHistogram : public Histogram { typedef std::map<Sample, std::string> BucketDescriptionMap; BucketDescriptionMap bucket_description_; - DISALLOW_EVIL_CONSTRUCTORS(LinearHistogram); + DISALLOW_COPY_AND_ASSIGN(LinearHistogram); }; //------------------------------------------------------------------------------ @@ -404,7 +443,7 @@ class BooleanHistogram : public LinearHistogram { virtual void AddBoolean(bool value) { Add(value ? 1 : 0); } private: - DISALLOW_EVIL_CONSTRUCTORS(BooleanHistogram); + DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); }; //------------------------------------------------------------------------------ @@ -428,7 +467,7 @@ class ThreadSafeHistogram : public Histogram { private: Lock lock_; - DISALLOW_EVIL_CONSTRUCTORS(ThreadSafeHistogram); + DISALLOW_COPY_AND_ASSIGN(ThreadSafeHistogram); }; //------------------------------------------------------------------------------ @@ -438,7 +477,7 @@ class ThreadSafeHistogram : public Histogram { class StatisticsRecorder { public: - typedef std::vector<const Histogram*> Histograms; + typedef std::vector<Histogram*> Histograms; StatisticsRecorder(); @@ -449,9 +488,9 @@ class StatisticsRecorder { // Register, or add a new histogram to the collection of statistics. // Return true if registered. - static bool Register(const Histogram& histogram); + static bool Register(Histogram* histogram); // Unregister, or remove, a histogram from the collection of statistics. - static void UnRegister(const Histogram& histogram); + static void UnRegister(Histogram* histogram); // Methods for printing histograms. Only histograms which have query as // a substring are written to output (an empty string will process all @@ -462,11 +501,9 @@ class StatisticsRecorder { // Method for extracting histograms which were marked for use by UMA. static void GetHistograms(Histograms* output); - static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } + static Histogram* GetHistogram(const std::string& query); - private: - typedef std::map<std::string, const Histogram*> HistogramMap; - // We keep all registered histograms in a map, from name to histogram. + static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } // GetSnapshot copies some of the pointers to registered histograms into the // caller supplied vector (Histograms). Only histograms with names matching @@ -474,14 +511,20 @@ class StatisticsRecorder { // pointer to be copied. static void GetSnapshot(const std::string& query, Histograms* snapshot); + + private: + // We keep all registered histograms in a map, from name to histogram. + typedef std::map<std::string, Histogram*> HistogramMap; + static HistogramMap* histograms_; + // lock protects access to the above map. static Lock* lock_; // Dump all known histograms to log. static bool dump_on_exit_; - DISALLOW_EVIL_CONSTRUCTORS(StatisticsRecorder); + DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); }; #endif // BASE_HISTOGRAM_H__ diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index 7f4c10d..34f2556 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc @@ -9,6 +9,7 @@ #include "base/file_version_info.h" #include "base/histogram.h" +#include "base/platform_thread.h" #include "base/stats_table.h" #include "base/string_piece.h" #include "base/string_util.h" @@ -21,11 +22,13 @@ #include "chrome/browser/net/dns_global.h" #include "chrome/browser/profile.h" #include "chrome/browser/profile_manager.h" +#include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/common/jstemplate_builder.h" #include "chrome/common/l10n_util.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_service.h" +#include "chrome/common/render_messages.h" #include "chrome/common/resource_bundle.h" #include "chrome/renderer/about_handler.h" #include "googleurl/src/gurl.h" @@ -292,7 +295,7 @@ std::string BrowserAboutHandler::AboutVersion() { // static std::string BrowserAboutHandler::AboutCredits() { - static const std::string credits_html = + static const std::string credits_html = ResourceBundle::GetSharedInstance().GetDataResource( IDR_CREDITS_HTML); @@ -301,7 +304,7 @@ std::string BrowserAboutHandler::AboutCredits() { // static std::string BrowserAboutHandler::AboutTerms() { - static const std::string terms_html = + static const std::string terms_html = ResourceBundle::GetSharedInstance().GetDataResource( IDR_TERMS_HTML); @@ -344,6 +347,15 @@ std::string BrowserAboutHandler::AboutPlugins() { // static std::string BrowserAboutHandler::AboutHistograms(const std::string& query) { std::string data; + for (RenderProcessHost::iterator it = RenderProcessHost::begin(); + it != RenderProcessHost::end(); ++it) { + it->second->Send(new ViewMsg_GetRendererHistograms()); + } + + // TODO(raman): Delay page layout until we get respnoses + // back from renderers, and not have to use a fixed size delay. + PlatformThread::Sleep(1000); + StatisticsRecorder::WriteHTMLGraph(query, &data); return data; } diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc index 5c9cfda..c50a4c5 100644 --- a/chrome/browser/metrics/metrics_service.cc +++ b/chrome/browser/metrics/metrics_service.cc @@ -1755,9 +1755,21 @@ void MetricsService::RecordCurrentState(PrefService* pref) { RecordPluginChanges(pref); } +void MetricsService::CollectRendererHistograms() { + for (RenderProcessHost::iterator it = RenderProcessHost::begin(); + it != RenderProcessHost::end(); ++it) { + it->second->Send(new ViewMsg_GetRendererHistograms()); + } +} + void MetricsService::RecordCurrentHistograms() { DCHECK(current_log_); + CollectRendererHistograms(); + + // TODO(raman): Delay the metrics collection activities until we get all the + // updates from the renderers, or we time out (1 second? 3 seconds?). + StatisticsRecorder::Histograms histograms; StatisticsRecorder::GetHistograms(&histograms); for (StatisticsRecorder::Histograms::iterator it = histograms.begin(); diff --git a/chrome/browser/metrics/metrics_service.h b/chrome/browser/metrics/metrics_service.h index 630d2de..58c491a 100644 --- a/chrome/browser/metrics/metrics_service.h +++ b/chrome/browser/metrics/metrics_service.h @@ -342,9 +342,14 @@ class MetricsService : public NotificationObserver, // buffered plugin stability statistics. void RecordCurrentState(PrefService* pref); + // Requests all renderers to send their histograms back for + // collecting stats from renderers. + void CollectRendererHistograms(); + // Record complete list of histograms into the current log. // Called when we close a log. void RecordCurrentHistograms(); + // Record a specific histogram . void RecordHistogram(const Histogram& histogram); diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index e4ca158..ffded3e 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -139,7 +139,7 @@ ResourceMessageFilter::~ResourceMessageFilter() { void ResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) { channel_ = channel; - // Add the observers to intercept + // Add the observers to intercept. NotificationService::current()->AddObserver( this, NotificationType::SPELLCHECKER_REINITIALIZED, @@ -197,6 +197,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& message) { OnOpenChannelToPlugin) IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SpellCheck, OnSpellCheck) IPC_MESSAGE_HANDLER(ViewHostMsg_DnsPrefetch, OnDnsPrefetch) + IPC_MESSAGE_HANDLER(ViewHostMsg_RendererHistograms, + OnRendererHistograms) IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_PaintRect, render_widget_helper_->DidReceivePaintMsg(message)) IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardWriteObjectsAsync, @@ -412,7 +414,7 @@ void ResourceMessageFilter::OnPluginSyncMessage(const FilePath& plugin_path, } } -#if defined(OS_WIN) // This hack is Windows-specific. +#if defined(OS_WIN) // This hack is Windows-specific. void ResourceMessageFilter::OnLoadFont(LOGFONT font) { // If renderer is running in a sandbox, GetTextMetrics // can sometimes fail. If a font has not been loaded @@ -500,7 +502,7 @@ void ResourceMessageFilter::OnClipboardWriteObjects( // on the UI thread. We'll copy the relevant data and get a handle to any // shared memory so it doesn't go away when we resume the renderer, and post // a task to perform the write on the UI thread. - Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects); + Clipboard::ObjectMap* long_living_objects = new Clipboard::ObjectMap(objects); // We pass the render_handle_ to assist the clipboard with using shared // memory objects. render_handle_ is a handle to the process that would @@ -639,7 +641,7 @@ void ResourceMessageFilter::OnResourceTypeStats( } void ResourceMessageFilter::OnResolveProxy(const GURL& url, - IPC::Message* reply_msg) { + IPC::Message* reply_msg) { resolve_proxy_msg_helper_.Start(url, reply_msg); } @@ -764,7 +766,7 @@ ClipboardService* ResourceMessageFilter::GetClipboardService() { // the spellcheck dictionaries into the browser process, and all renderers ask // the browsers to do SpellChecking. // -// This filter should not try to initialize the spellchecker. It is up to the +// This filter should not try to initialize the spellchecker. It is up to the // profile to initialize it when required, and send it here. If |spellchecker_| // is made NULL, it corresponds to spellchecker turned off - i.e., all // spellings are correct. @@ -787,7 +789,7 @@ void ResourceMessageFilter::OnSpellCheck(const std::wstring& word, return; } -void ResourceMessageFilter::Observe(NotificationType type, +void ResourceMessageFilter::Observe(NotificationType type, const NotificationSource &source, const NotificationDetails &details) { if (type == NotificationType::SPELLCHECKER_REINITIALIZED) { @@ -801,9 +803,14 @@ void ResourceMessageFilter::OnDnsPrefetch( chrome_browser_net::DnsPrefetchList(hostnames); } +void ResourceMessageFilter::OnRendererHistograms( + const std::vector<std::string>& histograms) { + Histogram::DeserializeHistogramList(histograms); +} + void ResourceMessageFilter::OnCreateAudioStream( - const IPC::Message& msg, int stream_id, - const ViewHostMsg_Audio_CreateStream& params) { + const IPC::Message& msg, int stream_id, + const ViewHostMsg_Audio_CreateStream& params) { // TODO(hclam): call to AudioRendererHost::CreateStream and send a message to // renderer to notify the result. } diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 4121a50..ab60be0 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -5,6 +5,9 @@ #ifndef CHROME_BROWSER_RENDERER_HOST_RESOURCE_MSG_FILTER_H_ #define CHROME_BROWSER_RENDERER_HOST_RESOURCE_MSG_FILTER_H_ +#include <string> +#include <vector> + #include "base/clipboard.h" #include "base/file_path.h" #include "base/gfx/rect.h" @@ -146,6 +149,7 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnSpellCheck(const std::wstring& word, IPC::Message* reply_msg); void OnDnsPrefetch(const std::vector<std::string>& hostnames); + void OnRendererHistograms(const std::vector<std::string>& histogram_info); void OnReceiveContextMenuMsg(const IPC::Message& msg); // Clipboard messages void OnClipboardWriteObjects(const Clipboard::ObjectMap& objects); diff --git a/chrome/chrome.xcodeproj/project.pbxproj b/chrome/chrome.xcodeproj/project.pbxproj index d6ac699..7dc429d 100644 --- a/chrome/chrome.xcodeproj/project.pbxproj +++ b/chrome/chrome.xcodeproj/project.pbxproj @@ -330,6 +330,7 @@ A7C613C10F30D7E4008CEE5D /* mock_render_process_host.cc in Sources */ = {isa = PBXBuildFile; fileRef = A7C613BF0F30D7E4008CEE5D /* mock_render_process_host.cc */; }; A7C6146F0F30DA1D008CEE5D /* ipc_test_sink.cc in Sources */ = {isa = PBXBuildFile; fileRef = A7C6146D0F30DA1D008CEE5D /* ipc_test_sink.cc */; }; A7CBAD390F322A7E00360BF5 /* shell_dialogs_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = A7CBAD370F322A7E00360BF5 /* shell_dialogs_mac.mm */; }; + AB3B4B2B0F549D9E0009E2BF /* renderer_histogram_snapshots.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB3B4B290F549D9E0009E2BF /* renderer_histogram_snapshots.cc */; }; AB8963000F4E0901009CFFAC /* audio_renderer_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB8962FA0F4E087E009CFFAC /* audio_renderer_impl.cc */; }; AB8963010F4E0907009CFFAC /* data_source_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB8962FC0F4E087E009CFFAC /* data_source_impl.cc */; }; AB8963020F4E090D009CFFAC /* video_renderer_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = AB8962FE0F4E087E009CFFAC /* video_renderer_impl.cc */; }; @@ -2523,6 +2524,8 @@ A7C6146E0F30DA1D008CEE5D /* ipc_test_sink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipc_test_sink.h; sourceTree = "<group>"; }; A7CBAD370F322A7E00360BF5 /* shell_dialogs_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = shell_dialogs_mac.mm; sourceTree = "<group>"; }; A9C335E39D39A7DE087850FC /* url_pattern_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = url_pattern_unittest.cc; path = extensions/url_pattern_unittest.cc; sourceTree = "<group>"; }; + AB3B4B290F549D9E0009E2BF /* renderer_histogram_snapshots.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = renderer_histogram_snapshots.cc; sourceTree = "<group>"; }; + AB3B4B2A0F549D9E0009E2BF /* renderer_histogram_snapshots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderer_histogram_snapshots.h; sourceTree = "<group>"; }; AB8962FA0F4E087E009CFFAC /* audio_renderer_impl.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = audio_renderer_impl.cc; path = media/audio_renderer_impl.cc; sourceTree = "<group>"; }; AB8962FB0F4E087E009CFFAC /* audio_renderer_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = audio_renderer_impl.h; path = media/audio_renderer_impl.h; sourceTree = "<group>"; }; AB8962FC0F4E087E009CFFAC /* data_source_impl.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = data_source_impl.cc; path = media/data_source_impl.cc; sourceTree = "<group>"; }; @@ -3107,6 +3110,8 @@ 4D640CD60EAE868600EBCFC0 /* render_widget.h */, 4D640CD70EAE868600EBCFC0 /* render_widget_unittest.cc */, 4D640CD80EAE868600EBCFC0 /* renderer_glue.cc */, + AB3B4B290F549D9E0009E2BF /* renderer_histogram_snapshots.cc */, + AB3B4B2A0F549D9E0009E2BF /* renderer_histogram_snapshots.h */, 4D640CD90EAE868600EBCFC0 /* renderer_main.cc */, B51F6D110F37C4DC00152D66 /* renderer_main_platform_delegate.h */, B51F6D130F37C4DC00152D66 /* renderer_main_platform_delegate_mac.mm */, @@ -5433,9 +5438,10 @@ 3380A6A10F2E91F9004EF74F /* render_process.cc in Sources */, 3380A69D0F2E91D4004EF74F /* render_thread.cc in Sources */, A7A20E650F3A1E1C00F62B4D /* render_view.cc in Sources */, - B503E0F00F0175FD00547DC6 /* user_script_slave.cc in Sources */, + AB3B4B2B0F549D9E0009E2BF /* renderer_histogram_snapshots.cc in Sources */, B51F6D2E0F37D04200152D66 /* renderer_main.cc in Sources */, B51F6D150F37C4DC00152D66 /* renderer_main_platform_delegate_mac.mm in Sources */, + B503E0F00F0175FD00547DC6 /* user_script_slave.cc in Sources */, AB8963020F4E090D009CFFAC /* video_renderer_impl.cc in Sources */, 4D640CF50EAE86EF00EBCFC0 /* visitedlink_slave.cc in Sources */, ); diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 8475890..46be905 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -460,6 +460,9 @@ IPC_BEGIN_MESSAGES(View) // resource types. IPC_MESSAGE_CONTROL0(ViewMsg_GetCacheResourceStats) + // Asks the renderer to send back Histograms. + IPC_MESSAGE_CONTROL0(ViewMsg_GetRendererHistograms) + // Notifies the renderer about ui theme changes IPC_MESSAGE_ROUTED0(ViewMsg_ThemeChanged) @@ -1027,6 +1030,9 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_ROUTED1(ViewHostMsg_UserMetricsRecordAction, std::wstring /* action */) + // Send back histograms as vector of pickled-histogram strings. + IPC_MESSAGE_CONTROL1(ViewHostMsg_RendererHistograms, std::vector<std::string>) + // Request for a DNS prefetch of the names in the array. // NameList is typedef'ed std::vector<std::string> IPC_MESSAGE_CONTROL1(ViewHostMsg_DnsPrefetch, diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 58de4ef..6e8e7b0 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -59,7 +59,8 @@ RenderThread::RenderThread(const std::wstring& channel_name) MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT, kStackSize)), visited_link_slave_(NULL), user_script_slave_(NULL), - render_dns_master_(NULL) { + render_dns_master_(NULL), + renderer_histogram_snapshots_(NULL) { SetChannelName(channel_name); } @@ -83,6 +84,10 @@ void RenderThread::Resolve(const char* name, size_t length) { return render_dns_master_->Resolve(name, length); } +void RenderThread::SendHistograms() { + return renderer_histogram_snapshots_->SendHistograms(); +} + void RenderThread::Init() { ChildThread::Init(); notification_service_.reset(new NotificationService); @@ -97,6 +102,7 @@ void RenderThread::Init() { visited_link_slave_ = new VisitedLinkSlave(); user_script_slave_ = new UserScriptSlave(); render_dns_master_.reset(new RenderDnsMaster()); + renderer_histogram_snapshots_.reset(new RendererHistogramSnapshots()); } void RenderThread::CleanUp() { @@ -140,6 +146,8 @@ void RenderThread::OnControlMessageReceived(const IPC::Message& msg) { // is there a new non-windows message I should add here? IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView) IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities) + IPC_MESSAGE_HANDLER(ViewMsg_GetRendererHistograms, + OnGetRendererHistograms) IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats, OnGetCacheResourceStats) IPC_MESSAGE_HANDLER(ViewMsg_PluginMessage, OnPluginMessage) @@ -212,6 +220,10 @@ void RenderThread::OnGetCacheResourceStats() { #endif } +void RenderThread::OnGetRendererHistograms() { + SendHistograms(); +} + void RenderThread::InformHostOfCacheStats() { #if defined(OS_WIN) || defined(OS_LINUX) CacheManager::UsageStats stats; diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 54043ca..a23776e 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -12,10 +12,12 @@ #include "base/task.h" #include "build/build_config.h" #include "chrome/common/child_thread.h" +#include "chrome/renderer/renderer_histogram_snapshots.h" class FilePath; class NotificationService; class RenderDnsMaster; +class RendererHistogram; class SkBitmap; class UserScriptSlave; class VisitedLinkSlave; @@ -86,6 +88,9 @@ class RenderThread : public RenderThreadBase, // Do DNS prefetch resolution of a hostname. void Resolve(const char* name, size_t length); + // Send all the Histogram data to browser. + void SendHistograms(); + // Invokes InformHostOfCacheStats after a short delay. Used to move this // bookkeeping operation off the critical latency path. void InformHostOfCacheStatsLater(); @@ -113,6 +118,9 @@ class RenderThread : public RenderThreadBase, size_t capacity); void OnGetCacheResourceStats(); + // Send all histograms to browser. + void OnGetRendererHistograms(); + // Gather usage statistics from the in-memory cache and inform our host. // These functions should be call periodically so that the host can make // decisions about how to allocation resources using current information. @@ -124,6 +132,8 @@ class RenderThread : public RenderThreadBase, scoped_ptr<RenderDnsMaster> render_dns_master_; + scoped_ptr<RendererHistogramSnapshots> renderer_histogram_snapshots_; + scoped_ptr<ScopedRunnableMethodFactory<RenderThread> > cache_stats_factory_; scoped_ptr<NotificationService> notification_service_; diff --git a/chrome/renderer/renderer.scons b/chrome/renderer/renderer.scons index c03848b..3bb0d17 100644 --- a/chrome/renderer/renderer.scons +++ b/chrome/renderer/renderer.scons @@ -83,6 +83,8 @@ input_files = ChromeFileList([ 'render_widget.cc', 'render_widget.h', 'renderer_glue.cc', + 'renderer_histogram_snapshots.cc', + 'renderer_histogram_snapshots.h', 'renderer_main.cc', 'renderer_resources.h', 'user_script_slave.cc', diff --git a/chrome/renderer/renderer.vcproj b/chrome/renderer/renderer.vcproj index 7e50f8f..684ec52 100644 --- a/chrome/renderer/renderer.vcproj +++ b/chrome/renderer/renderer.vcproj @@ -298,6 +298,14 @@ > </File> <File + RelativePath=".\renderer_histogram_snapshots.cc" + > + </File> + <File + RelativePath=".\renderer_histogram_snapshots.h" + > + </File> + <File RelativePath=".\renderer_main.cc" > </File> diff --git a/chrome/renderer/renderer_histogram_snapshots.cc b/chrome/renderer/renderer_histogram_snapshots.cc new file mode 100644 index 0000000..a4488ca --- /dev/null +++ b/chrome/renderer/renderer_histogram_snapshots.cc @@ -0,0 +1,94 @@ +// Copyright (c) 2006-2008 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 "chrome/renderer/renderer_histogram_snapshots.h" + +#include <ctype.h> + +#include "base/histogram.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/pickle.h" +#include "chrome/common/render_messages.h" +#include "chrome/renderer/render_process.h" +#include "chrome/renderer/render_thread.h" + +// TODO(raman): Before renderer shuts down send final snapshot lists. + +RendererHistogramSnapshots::RendererHistogramSnapshots() + : ALLOW_THIS_IN_INITIALIZER_LIST( + renderer_histogram_snapshots_factory_(this)) { +} + +// Send data quickly! +void RendererHistogramSnapshots::SendHistograms() { + RenderThread::current()->message_loop()->PostTask(FROM_HERE, + renderer_histogram_snapshots_factory_.NewRunnableMethod( + &RendererHistogramSnapshots::UploadAllHistrograms)); +} + +void RendererHistogramSnapshots::UploadAllHistrograms() { + StatisticsRecorder::Histograms histograms; + StatisticsRecorder::GetHistograms(&histograms); + + HistogramPickledList pickled_histograms; + + for (StatisticsRecorder::Histograms::iterator it = histograms.begin(); + histograms.end() != it; + it++) { + UploadHistrogram(**it, &pickled_histograms); + } + // Send the handle over synchronous IPC. + if (pickled_histograms.size() > 0) { + RenderThread::current()->Send( + new ViewHostMsg_RendererHistograms(pickled_histograms)); + } +} + +// Extract snapshot data and then send it off the the Browser process +// to save it. +void RendererHistogramSnapshots::UploadHistrogram( + const Histogram& histogram, + HistogramPickledList* pickled_histograms) { + + // Get up-to-date snapshot of sample stats. + Histogram::SampleSet snapshot; + histogram.SnapshotSample(&snapshot); + const std::string& histogram_name = histogram.histogram_name(); + + // Find the already sent stats, or create an empty set. + LoggedSampleMap::iterator it = logged_samples_.find(histogram_name); + Histogram::SampleSet* already_logged; + if (logged_samples_.end() == it) { + // Add new entry. + already_logged = &logged_samples_[histogram.histogram_name()]; + already_logged->Resize(histogram); // Complete initialization. + } else { + already_logged = &(it->second); + // Deduct any stats we've already logged from our snapshot. + snapshot.Subtract(*already_logged); + } + + // Snapshot now contains only a delta to what we've already_logged. + + if (snapshot.TotalCount() > 0) { + UploadHistogramDelta(histogram, snapshot, pickled_histograms); + // Add new data into our running total. + already_logged->Add(snapshot); + } +} + +void RendererHistogramSnapshots::UploadHistogramDelta( + const Histogram& histogram, + const Histogram::SampleSet& snapshot, + HistogramPickledList* pickled_histograms) { + + DCHECK(0 != snapshot.TotalCount()); + snapshot.CheckSize(histogram); + + std::string histogram_info = + Histogram::SerializeHistogramInfo(histogram, snapshot); + pickled_histograms->push_back(histogram_info); +} + diff --git a/chrome/renderer/renderer_histogram_snapshots.h b/chrome/renderer/renderer_histogram_snapshots.h new file mode 100644 index 0000000..b3d7fb1 --- /dev/null +++ b/chrome/renderer/renderer_histogram_snapshots.h @@ -0,0 +1,54 @@ +// Copyright (c) 2006-2008 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. + +#ifndef CHROME_RENDERER_HISTOGRAM_SNAPSHOTS_H_ +#define CHROME_RENDERER_HISTOGRAM_SNAPSHOTS_H_ + +#include <list> +#include <map> +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/histogram.h" +#include "base/process.h" +#include "base/scoped_ptr.h" +#include "base/task.h" + +class RendererHistogramSnapshots { + public: + RendererHistogramSnapshots(); + + ~RendererHistogramSnapshots() {} + + // Send the histogram data. + void SendHistograms(); + + // Maintain a map of histogram names to the sample stats we've sent. + typedef std::map<std::string, Histogram::SampleSet> LoggedSampleMap; + typedef std::vector<std::string> HistogramPickledList; + + private: + // Extract snapshot data and then send it off the the Browser process. + // Send only a delta to what we have already sent. + void UploadAllHistrograms(); + void UploadHistrogram(const Histogram& histogram, + HistogramPickledList* histograms); + void UploadHistogramDelta(const Histogram& histogram, + const Histogram::SampleSet& snapshot, + HistogramPickledList* histograms); + + ScopedRunnableMethodFactory<RendererHistogramSnapshots> + renderer_histogram_snapshots_factory_; + + // For histograms, record what we've already logged (as a sample for each + // histogram) so that we can send only the delta with the next log. + LoggedSampleMap logged_samples_; + + DISALLOW_COPY_AND_ASSIGN(RendererHistogramSnapshots); +}; + +#endif // CHROME_RENDERER_HISTOGRAM_SNAPSHOTS_H_ + diff --git a/chrome/renderer/renderer_main.cc b/chrome/renderer/renderer_main.cc index b79e9e5..8e70dee 100644 --- a/chrome/renderer/renderer_main.cc +++ b/chrome/renderer/renderer_main.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/command_line.h" +#include "base/histogram.h" #include "base/message_loop.h" #include "base/path_service.h" #include "base/platform_thread.h" @@ -89,6 +90,13 @@ int RendererMain(const MainFunctionParams& parameters) { HandleRendererErrorTestParameters(parsed_command_line); + // Initialize histogram statistics gathering system. + // Don't create StatisticsRecorde in the single process mode. + scoped_ptr<StatisticsRecorder> statistics; + if (!StatisticsRecorder::WasStarted()) { + statistics.reset(new StatisticsRecorder()); + } + { RenderProcess render_process; bool run_loop = true; |