11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# found in the LICENSE file.
4116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport collections
51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import json
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import logging
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)from metrics import Metric
9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import util
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccifrom telemetry.value import histogram_util
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry.value import scalar
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class StartupMetric(Metric):
16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  "A metric for browser startup time."
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  HISTOGRAMS_TO_RECORD = {
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'messageloop_start_time' :
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        'Startup.BrowserMessageLoopStartTimeFromMainEntry',
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'window_display_time' : 'Startup.BrowserWindowDisplay',
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    'open_tabs_time' : 'Startup.BrowserOpenTabs'}
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def Start(self, page, tab):
251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    raise NotImplementedError()
261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def Stop(self, page, tab):
281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    raise NotImplementedError()
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  def _GetBrowserMainEntryTime(self, tab):
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    """Returns the main entry time (in ms) of the browser."""
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    histogram_type = histogram_util.BROWSER_HISTOGRAM
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    high_bytes = histogram_util.GetHistogramSum(
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        histogram_type,
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        'Startup.BrowserMainEntryTimeAbsoluteHighWord',
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        tab)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    low_bytes = histogram_util.GetHistogramSum(
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        histogram_type,
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        'Startup.BrowserMainEntryTimeAbsoluteLowWord',
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        tab)
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if high_bytes == 0 and low_bytes == 0:
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return None
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return (int(high_bytes) << 32) | (int(low_bytes) << 1)
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  def _RecordTabLoadTimes(self, tab, browser_main_entry_time_ms, results):
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    """Records the tab load times for the browser. """
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    tab_load_times = []
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    TabLoadTime = collections.namedtuple(
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        'TabLoadTime',
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        ['load_start_ms', 'load_duration_ms'])
51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    def RecordTabLoadTime(t):
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      try:
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        t.WaitForDocumentReadyStateToBeComplete()
55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        result = t.EvaluateJavaScript(
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            'statsCollectionController.tabLoadTiming()')
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        result = json.loads(result)
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if 'load_start_ms' not in result or 'load_duration_ms' not in result:
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          raise Exception("Outdated Chrome version, "
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch              "statsCollectionController.tabLoadTiming() not present")
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        if result['load_duration_ms'] is None:
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          tab_title = t.EvaluateJavaScript('document.title')
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          print "Page: ", tab_title, " didn't finish loading."
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          return
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        tab_load_times.append(TabLoadTime(
69116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            int(result['load_start_ms']),
70116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            int(result['load_duration_ms'])))
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      except util.TimeoutException:
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Low memory Android devices may not be able to load more than
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # one tab at a time, so may timeout when the test attempts to
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # access a background tab. Ignore these tabs.
75116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        logging.error("Tab timed out on JavaScript access")
76116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # Only measure the foreground tab. We can't measure all tabs on Android
78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # because on Android the data of the background tabs is loaded on demand,
79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # when the user switches to them, rather than during startup. In view of
80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # this, to get the same measures on all platform, we only measure the
81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # foreground tab on all platforms.
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
83116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    RecordTabLoadTime(tab.browser.foreground_tab)
84116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    foreground_tab_stats = tab_load_times[0]
86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    foreground_tab_load_complete = ((foreground_tab_stats.load_start_ms +
87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        foreground_tab_stats.load_duration_ms) - browser_main_entry_time_ms)
88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    results.AddValue(scalar.ScalarValue(
89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        results.current_page, 'foreground_tab_load_complete', 'ms',
90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        foreground_tab_load_complete))
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def AddResults(self, tab, results):
93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    get_histogram_js = 'statsCollectionController.getBrowserHistogram("%s")'
94116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    for display_name, histogram_name in self.HISTOGRAMS_TO_RECORD.iteritems():
96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      result = tab.EvaluateJavaScript(get_histogram_js % histogram_name)
97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      result = json.loads(result)
98116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      measured_time = 0
99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if 'sum' in result:
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        # For all the histograms logged here, there's a single entry so sum
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        # is the exact value for that entry.
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        measured_time = result['sum']
104116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      elif 'buckets' in result:
105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        measured_time = \
106116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            (result['buckets'][0]['high'] + result['buckets'][0]['low']) / 2
107116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
108116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      results.AddValue(scalar.ScalarValue(
109116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          results.current_page, display_name, 'ms', measured_time))
110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # Get tab load times.
112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    browser_main_entry_time_ms = self._GetBrowserMainEntryTime(tab)
113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (browser_main_entry_time_ms is None):
114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      print "Outdated Chrome version, browser main entry time not supported."
115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return
116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._RecordTabLoadTimes(tab, browser_main_entry_time_ms, results)
117