Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Unified Diff: content/browser/stats_collection_message_filter.cc

Issue 12389073: Collect tab timing information for use in telementry-based startup tests (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: formatting/compile fix Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/stats_collection_message_filter.cc
diff --git a/content/browser/stats_collection_message_filter.cc b/content/browser/stats_collection_message_filter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ef40bacc223f8ca40c4b1750e8ead89dd2fe3d22
--- /dev/null
+++ b/content/browser/stats_collection_message_filter.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2013 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 "content/browser/stats_collection_message_filter.h"
+
+#include <map>
+#include <set>
+
+#include "base/memory/singleton.h"
+#include "base/process_util.h"
+#include "content/common/child_process_messages.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
jam 2013/04/04 17:28:39 ditto re putting this inside content namespace
jeremy 2013/04/07 14:51:54 Done.
+
+bool RoutingIDFromNotificationSource(
+ const content::NotificationSource& source,
+ int *routing_id) {
+ content::NavigationController* tab =
+ content::Source<content::NavigationController>(source).ptr();
+ if (!tab)
+ return false;
+ content::WebContents* contents = tab->GetWebContents(); // Can never be NULL.
jam 2013/04/04 17:28:39 nit: comment is redundant with code
jeremy 2013/04/07 14:51:54 Done.
+ *routing_id = contents->GetRoutingID();
+ return true;
+}
+
+} // namespace
+
+namespace content {
+
+// Singleton that listens for tab lifetime events (load/unload/crash) and
+// records timing information.
+//
+// Lifetime: Needs to be instantiated before first page load in order to be able
+// to listen to the relevant events.
+// Once instantiated, the class will collect tab timing information for all
+// loded tabs, GetTimingInformation() is used to read out the data.
+class InitialLoadObserver : public content::NotificationObserver {
+ public:
+ static InitialLoadObserver* GetInstance() {
+ return Singleton<InitialLoadObserver>::get();
+ }
+
+ // content::NotificationObserver implementation:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // Gets stats on tab load start/stop time given a specific |routing_id|.
+ void GetTimingInformationForTab(int routing_id,
+ TabLoadTime* result,
+ base::TimeTicks* timer_start) const;
+
+ private:
+ friend struct DefaultSingletonTraits<InitialLoadObserver>;
+
+ typedef std::map<int, TabLoadTime> TabTimeMap;
+ typedef std::set<int> TabSet;
+
+ InitialLoadObserver();
+ virtual ~InitialLoadObserver();
+
+ content::NotificationRegistrar registrar_;
+ size_t crashed_tab_count_;
jam 2013/04/04 17:28:39 i don't see this used other than to collect?
jeremy 2013/04/07 14:51:54 Removed.
+ base::TimeTicks init_time_;
+ TabTimeMap loading_tabs_;
+ TabSet finished_tabs_;
+
+ DISALLOW_COPY_AND_ASSIGN(InitialLoadObserver);
+};
+
+InitialLoadObserver::InitialLoadObserver()
+ : crashed_tab_count_(0),
+ init_time_(base::TimeTicks::Now()) {
+ registrar_.Add(this, content::NOTIFICATION_LOAD_START,
+ content::NotificationService::AllSources());
+ registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
jam 2013/04/04 17:28:39 so, it seems that this class is listening for LOAD
jeremy 2013/04/07 14:51:54 This makes sense but I fear I'm going to need to a
jam 2013/04/07 21:14:04 Can you elaborate on what you think you'll need?
+ content::NotificationService::AllSources());
+ registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+ content::NotificationService::AllSources());
+}
+
+InitialLoadObserver::~InitialLoadObserver() {
+}
+
+void InitialLoadObserver::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ if (type == content::NOTIFICATION_LOAD_START) {
+ int routing_id = 0;
+ if (!RoutingIDFromNotificationSource(source, &routing_id))
+ return;
+ loading_tabs_[routing_id] = TabLoadTime(base::TimeTicks::Now());
+ } else if (type == content::NOTIFICATION_LOAD_STOP) {
+ int routing_id = 0;
+ if (!RoutingIDFromNotificationSource(source, &routing_id))
+ return;
+ TabTimeMap::iterator iter = loading_tabs_.find(routing_id);
+ if (iter != loading_tabs_.end()) {
+ finished_tabs_.insert(routing_id);
+ iter->second.set_stop_time(base::TimeTicks::Now());
+ }
+ } else if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
+ base::TerminationStatus status =
+ content::Details<content::RenderProcessHost::RendererClosedDetails>(
+ details)->status;
+ switch (status) {
+ case base::TERMINATION_STATUS_NORMAL_TERMINATION:
+ break;
+
+ case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
+ case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+ case base::TERMINATION_STATUS_PROCESS_CRASHED:
+ crashed_tab_count_++;
+ break;
+
+ case base::TERMINATION_STATUS_STILL_RUNNING:
+ LOG(ERROR) << "Got RENDERER_PROCESS_CLOSED notification, "
+ << "but the process is still running. We may miss further "
+ << "crash notification, resulting in hangs.";
+ break;
+
+ default:
+ LOG(ERROR) << "Unhandled termination status " << status;
+ NOTREACHED();
+ break;
+ }
+ } else {
+ NOTREACHED();
+ }
+}
+
+void InitialLoadObserver::GetTimingInformationForTab(
+ int routing_id,
+ TabLoadTime* result,
+ base::TimeTicks* timer_start) const {
+ TabTimeMap::const_iterator it = loading_tabs_.find(routing_id);
+ if (it == loading_tabs_.end()) {
+ *timer_start = base::TimeTicks();
+ *result = TabLoadTime();
+ return;
+ }
+
+ *timer_start = init_time_;
+ *result = it->second;
+}
+
+StatsCollectionMessageFilter::StatsCollectionMessageFilter() {
+ // StatsCollectionMessageFilter's lifetime is tied to a renderer, we want
+ // InitialLoadObserver to stick around and listen for tab loads indefinitely.
+ InitialLoadObserver::GetInstance();
+}
+
+void StatsCollectionMessageFilter::OnChannelConnected(int32 peer_pid) {
+ BrowserMessageFilter::OnChannelConnected(peer_pid);
+}
+
+bool StatsCollectionMessageFilter::OnMessageReceived(
+ const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(StatsCollectionMessageFilter, message,
+ *message_was_ok)
+ IPC_MESSAGE_HANDLER(ChildProcessHostMsg_GetTabLoadTimingInformation,
+ OnGetTabLoadTimingInformation)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+ return handled;
+}
+
+StatsCollectionMessageFilter::~StatsCollectionMessageFilter() {
+}
+
+void StatsCollectionMessageFilter::OnGetTabLoadTimingInformation(
+ int routing_id,
+ TabLoadTime* tab_timing_data,
+ base::TimeTicks* timer_start) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ InitialLoadObserver::GetInstance()->GetTimingInformationForTab(
+ routing_id, tab_timing_data, timer_start);
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698