1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch# Copyright 2014 The Chromium Authors. All rights reserved.
2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch# Use of this source code is governed by a BSD-style license that can be
3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch# found in the LICENSE file.
40529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochfrom measurements import smooth_gesture_util
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from telemetry.core.platform import tracing_category_filter
703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)from telemetry.core.platform import tracing_options
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)from telemetry.timeline.model import TimelineModel
9a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfrom telemetry.page.actions import action_runner
10a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfrom telemetry.web_perf import timeline_interaction_record as tir_module
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
130529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochRUN_SMOOTH_ACTIONS = 'RunSmoothAllActions'
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
15010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochclass TimelineController(object):
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def __init__(self):
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    super(TimelineController, self).__init__()
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self.trace_categories = None
20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self._model = None
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self._renderer_process = None
220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    self._smooth_records = []
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    self._interaction = None
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def SetUp(self, page, tab):
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    """Starts gathering timeline data.
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    """
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    # Resets these member variables incase this object is reused.
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self._model = None
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self._renderer_process = None
3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if not tab.browser.platform.tracing_controller.IsChromeTracingSupported(
3303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      tab.browser):
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      raise Exception('Not supported')
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    category_filter = tracing_category_filter.TracingCategoryFilter(
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        filter_string=self.trace_categories)
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for delay in page.GetSyntheticDelayCategories():
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      category_filter.AddSyntheticDelay(delay)
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    options = tracing_options.TracingOptions()
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    options.enable_chrome_trace = True
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    tab.browser.platform.tracing_controller.Start(options, category_filter)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  def Start(self, tab):
44a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    # Start the smooth marker for all actions.
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    runner = action_runner.ActionRunner(tab)
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    self._interaction = runner.BeginInteraction(
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        RUN_SMOOTH_ACTIONS, is_smooth=True)
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def Stop(self, tab):
50a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    # End the smooth marker for all actions.
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    self._interaction.End()
52a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    # Stop tracing.
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    timeline_data = tab.browser.platform.tracing_controller.Stop()
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self._model = TimelineModel(timeline_data)
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    self._renderer_process = self._model.GetRendererProcessFromTabId(tab.id)
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    renderer_thread = self.model.GetRendererThreadFromTabId(tab.id)
570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    run_smooth_actions_record = None
590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    self._smooth_records = []
600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    for event in renderer_thread.async_slices:
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      if not tir_module.IsTimelineInteractionRecord(event.name):
620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        continue
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      r = tir_module.TimelineInteractionRecord.FromAsyncEvent(event)
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      if r.label == RUN_SMOOTH_ACTIONS:
650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        assert run_smooth_actions_record is None, (
660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          'TimelineController cannot issue more than 1 %s record' %
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          RUN_SMOOTH_ACTIONS)
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        run_smooth_actions_record = r
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      elif r.is_smooth:
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        self._smooth_records.append(
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          smooth_gesture_util.GetAdjustedInteractionIfContainGesture(
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            self.model, r))
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    # If there is no other smooth records, we make measurements on time range
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    # marked by timeline_controller itself.
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    # TODO(nednguyen): when crbug.com/239179 is marked fixed, makes sure that
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    # page sets are responsible for issueing the markers themselves.
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if len(self._smooth_records) == 0 and run_smooth_actions_record:
790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      self._smooth_records = [run_smooth_actions_record]
80a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def CleanUp(self, tab):
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if tab.browser.platform.tracing_controller.is_tracing_running:
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      tab.browser.platform.tracing_controller.Stop()
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  @property
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def model(self):
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return self._model
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  @property
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def renderer_process(self):
92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return self._renderer_process
93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  @property
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  def smooth_records(self):
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return self._smooth_records
97