<filename>tools/perf/metrics/startup_metric.py
# Copyright 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.
import collections
import json
import logging

from metrics import Metric
from metrics import histogram_util

from telemetry.core import util


class StartupMetric(Metric):
  "A metric for browser startup time."

  HISTOGRAMS_TO_RECORD = {
    'messageloop_start_time' :
        'Startup.BrowserMessageLoopStartTimeFromMainEntry',
    'window_display_time' : 'Startup.BrowserWindowDisplay',
    'open_tabs_time' : 'Startup.BrowserOpenTabs'}

  def Start(self, page, tab):
    raise NotImplementedError()

  def Stop(self, page, tab):
    raise NotImplementedError()

  def _GetBrowserMainEntryTime(self, tab):
    """Returns the main entry time (in ms) of the browser."""
    histogram_type = histogram_util.BROWSER_HISTOGRAM
    high_bytes = histogram_util.GetHistogramSum(
        histogram_type,
        'Startup.BrowserMainEntryTimeAbsoluteHighWord',
        tab)
    low_bytes = histogram_util.GetHistogramSum(
        histogram_type,
        'Startup.BrowserMainEntryTimeAbsoluteLowWord',
        tab)
    if high_bytes == 0 and low_bytes == 0:
      return None
    return (int(high_bytes) << 32) | (int(low_bytes) << 1)

  def _RecordTabLoadTimes(self, tab, browser_main_entry_time_ms, results):
    """Records the tab load times for the browser. """
    tab_load_times = []
    TabLoadTime = collections.namedtuple(
        'TabLoadTime',
        ['load_start_ms', 'load_duration_ms'])

    def RecordTabLoadTime(t):
      try:
        t.WaitForDocumentReadyStateToBeComplete()

        result = t.EvaluateJavaScript(
            'statsCollectionController.tabLoadTiming()')
        result = json.loads(result)

        if 'load_start_ms' not in result or 'load_duration_ms' not in result:
          raise Exception("Outdated Chrome version, "
              "statsCollectionController.tabLoadTiming() not present")
        if result['load_duration_ms'] is None:
          tab_title = t.EvaluateJavaScript('document.title')
          print "Page: ", tab_title, " didn't finish loading."
          return

        tab_load_times.append(TabLoadTime(
            int(result['load_start_ms']),
            int(result['load_duration_ms'])))
      except util.TimeoutException:
        # Low memory Android devices may not be able to load more than
        # one tab at a time, so may timeout when the test attempts to
        # access a background tab. Ignore these tabs.
        logging.error("Tab timed out on JavaScript access")

    # Only measure the foreground tab. We can't measure all tabs on Android
    # because on Android the data of the background tabs is loaded on demand,
    # when the user switches to them, rather than during startup. In view of
    # this, to get the same measures on all platform, we only measure the
    # foreground tab on all platforms.

    RecordTabLoadTime(tab.browser.foreground_tab)

    foreground_tab_stats = tab_load_times[0]
    foreground_tab_load_complete = ((foreground_tab_stats.load_start_ms +
        foreground_tab_stats.load_duration_ms) - browser_main_entry_time_ms)
    results.Add(
        'foreground_tab_load_complete', 'ms', foreground_tab_load_complete)

  def AddResults(self, tab, results):
    get_histogram_js = 'statsCollectionController.getBrowserHistogram("%s")'

    for display_name, histogram_name in self.HISTOGRAMS_TO_RECORD.iteritems():
      result = tab.EvaluateJavaScript(get_histogram_js % histogram_name)
      result = json.loads(result)
      measured_time = 0

      if 'sum' in result:
        # For all the histograms logged here, there's a single entry so sum
        # is the exact value for that entry.
        measured_time = result['sum']
      elif 'buckets' in result:
        measured_time = \
            (result['buckets'][0]['high'] + result['buckets'][0]['low']) / 2

      results.Add(display_name, 'ms', measured_time)

    # Get tab load times.
    browser_main_entry_time_ms = self._GetBrowserMainEntryTime(tab)
    if (browser_main_entry_time_ms is None):
      print "Outdated Chrome version, browser main entry time not supported."
      return
    self._RecordTabLoadTimes(tab, browser_main_entry_time_ms, results)

<filename>tools/perf/metrics/startup_metric.py
# Copyright 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.
import collections
import json
import logging

from metrics import Metric
from metrics import histogram_util

from telemetry.core import util


class StartupMetric(Metric):
  "A metric for browser startup time."

  HISTOGRAMS_TO_RECORD = {
    'messageloop_start_time' :
        'Startup.BrowserMessageLoopStartTimeFromMainEntry',
    'window_display_time' : 'Startup.BrowserWindowDisplay',
    'open_tabs_time' : 'Startup.BrowserOpenTabs'}

  def Start(self, page, tab):
    raise NotImplementedError()

  def Stop(self, page, tab):
    raise NotImplementedError()

  def _GetBrowserMainEntryTime(self, tab):
    """Returns the main entry time (in ms) of the browser."""
    histogram_type = histogram_util.BROWSER_HISTOGRAM
    high_bytes = histogram_util.GetHistogramSum(
        histogram_type,
        'Startup.BrowserMainEntryTimeAbsoluteHighWord',
        tab)
    low_bytes = histogram_util.GetHistogramSum(
        histogram_type,
        'Startup.BrowserMainEntryTimeAbsoluteLowWord',
        tab)
    if high_bytes == 0 and low_bytes == 0:
      return None
    return (int(high_bytes) << 32) | (int(low_bytes) << 1)

  def _RecordTabLoadTimes(self, tab, browser_main_entry_time_ms, results):
    """Records the tab load times for the browser. """
    tab_load_times = []
    TabLoadTime = collections.namedtuple(
        'TabLoadTime',
        ['load_start_ms', 'load_duration_ms'])

    def RecordTabLoadTime(t):
      try:
        t.WaitForDocumentReadyStateToBeComplete()

        result = t.EvaluateJavaScript(
            'statsCollectionController.tabLoadTiming()')
        result = json.loads(result)

        if 'load_start_ms' not in result or 'load_duration_ms' not in result:
          raise Exception("Outdated Chrome version, "
              "statsCollectionController.tabLoadTiming() not present")
        if result['load_duration_ms'] is None:
          tab_title = t.EvaluateJavaScript('document.title')
          print "Page: ", tab_title, " didn't finish loading."
          return

        tab_load_times.append(TabLoadTime(
            int(result['load_start_ms']),
            int(result['load_duration_ms'])))
      except util.TimeoutException:
        # Low memory Android devices may not be able to load more than
        # one tab at a time, so may timeout when the test attempts to
        # access a background tab. Ignore these tabs.
        logging.error("Tab timed out on JavaScript access")

    # Only measure the foreground tab. We can't measure all tabs on Android
    # because on Android the data of the background tabs is loaded on demand,
    # when the user switches to them, rather than during startup. In view of
    # this, to get the same measures on all platform, we only measure the
    # foreground tab on all platforms.

    RecordTabLoadTime(tab.browser.foreground_tab)

    foreground_tab_stats = tab_load_times[0]
    foreground_tab_load_complete = ((foreground_tab_stats.load_start_ms +
        foreground_tab_stats.load_duration_ms) - browser_main_entry_time_ms)
    results.Add(
        'foreground_tab_load_complete', 'ms', foreground_tab_load_complete)

  def AddResults(self, tab, results):
    get_histogram_js = 'statsCollectionController.getBrowserHistogram("%s")'

    for display_name, histogram_name in self.HISTOGRAMS_TO_RECORD.iteritems():
      result = tab.EvaluateJavaScript(get_histogram_js % histogram_name)
      result = json.loads(result)
      measured_time = 0

      if 'sum' in result:
        # For all the histograms logged here, there's a single entry so sum
        # is the exact value for that entry.
        measured_time = result['sum']
      elif 'buckets' in result:
        measured_time = \
            (result['buckets'][0]['high'] + result['buckets'][0]['low']) / 2

      results.Add(display_name, 'ms', measured_time)

    # Get tab load times.
    browser_main_entry_time_ms = self._GetBrowserMainEntryTime(tab)
    if (browser_main_entry_time_ms is None):
      print "Outdated Chrome version, browser main entry time not supported."
      return
    self._RecordTabLoadTimes(tab, browser_main_entry_time_ms, results)

# Copyright 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. Returns the main entry time (in ms) of the browser. Records the tab load times for the browser. # Low memory Android devices may not be able to load more than # one tab at a time, so may timeout when the test attempts to # access a background tab. Ignore these tabs. # Only measure the foreground tab. We can't measure all tabs on Android # because on Android the data of the background tabs is loaded on demand, # when the user switches to them, rather than during startup. In view of # this, to get the same measures on all platform, we only measure the # foreground tab on all platforms. # For all the histograms logged here, there's a single entry so sum # is the exact value for that entry. # Get tab load times.