Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / backends / chrome / tracing_backend.py
index 9fa00e5..218b95c 100644 (file)
 # found in the LICENSE file.
 
 import logging
-import re
 
 from telemetry.core.backends.chrome import inspector_websocket
-
-
-# All tracing categories not disabled-by-default
-DEFAULT_TRACE_CATEGORIES = None
-
-
-# Categories for absolute minimum overhead tracing. This contains no
-# sub-traces of thread tasks, so it's only useful for capturing the
-# cpu-time spent on threads (as well as needed benchmark traces)
-# FIXME: Remove webkit.console when blink.console lands in chromium and
-# the ref builds are updated. crbug.com/386847
-MINIMAL_TRACE_CATEGORIES = ("toplevel,"
-                            "benchmark,"
-                            "webkit.console,"
-                            "blink.console,"
-                            "trace_event_overhead")
+from telemetry.core.platform import tracing_category_filter
+from telemetry.core.platform import tracing_options
 
 
 class TracingUnsupportedException(Exception):
   pass
 
 
-class CategoryFilter(object):
-  def __init__(self, filter_string):
-    self.excluded = set()
-    self.included = set()
-    self.disabled = set()
-    self.synthetic_delays = set()
-    self.contains_wildcards = False
-
-    if not filter_string:
-      return
-
-    if '*' in filter_string or '?' in filter_string:
-      self.contains_wildcards = True
-
-    filter_set = set(filter_string.split(','))
-    delay_re = re.compile(r'DELAY[(][A-Za-z0-9._;]+[)]')
-    for category in filter_set:
-      if category == '':
-        continue
-      if delay_re.match(category):
-        self.synthetic_delays.add(category)
-      elif category[0] == '-':
-        category = category[1:]
-        self.excluded.add(category)
-      elif category.startswith('disabled-by-default-'):
-        self.disabled.add(category)
-      else:
-        self.included.add(category)
-
-  def IsSubset(self, other):
-    """ Determine if filter A (self) is a subset of filter B (other).
-        Returns True if A is a subset of B, False if A is not a subset of B,
-        and None if we can't tell for sure.
-    """
-    # We don't handle filters with wildcards in this test.
-    if self.contains_wildcards or other.contains_wildcards:
-      return None
-
-    # Disabled categories get into a trace if and only if they are contained in
-    # the 'disabled' set. Return False if A's disabled set is not a subset of
-    # B's disabled set.
-    if not self.disabled <= other.disabled:
-      return False
-
-    # If A defines more or different synthetic delays than B, then A is not a
-    # subset.
-    if not self.synthetic_delays <= other.synthetic_delays:
-      return False
-
-    if self.included and other.included:
-      # A and B have explicit include lists. If A includes something that B
-      # doesn't, return False.
-      if not self.included <= other.included:
-        return False
-    elif self.included:
-      # Only A has an explicit include list. If A includes something that B
-      # excludes, return False.
-      if self.included.intersection(other.excluded):
-        return False
-    elif other.included:
-      # Only B has an explicit include list. We don't know which categories are
-      # contained in the default list, so return None.
-      return None
-    else:
-      # None of the filter have explicit include list. If B excludes categories
-      # that A doesn't exclude, return False.
-      if not other.excluded <= self.excluded:
-        return False
+class TracingTimeoutException(Exception):
+  pass
 
-    return True
 
 class TracingBackend(object):
-  def __init__(self, devtools_port):
+  def __init__(self, devtools_port, chrome_browser_backend):
     self._inspector_websocket = inspector_websocket.InspectorWebsocket(
         self._NotificationHandler,
         self._ErrorHandler)
@@ -110,21 +28,21 @@ class TracingBackend(object):
     self._category_filter = None
     self._nesting = 0
     self._tracing_data = []
+    self._is_tracing_running = False
+    self._chrome_browser_backend = chrome_browser_backend
 
   @property
   def is_tracing_running(self):
-    return self._inspector_websocket.is_dispatching_async_notifications
-
-  def AddTabToMarkerMapping(self, tab, marker):
-    self._tab_to_marker_mapping[tab] = marker
+    return self._is_tracing_running
 
-  def StartTracing(self, custom_categories=None, timeout=10):
+  def StartTracing(self, trace_options, custom_categories=None, timeout=10):
     """ Starts tracing on the first nested call and returns True. Returns False
         and does nothing on subsequent nested calls.
     """
     self._nesting += 1
     if self.is_tracing_running:
-      new_category_filter = CategoryFilter(custom_categories)
+      new_category_filter = tracing_category_filter.TracingCategoryFilter(
+          filter_string=custom_categories)
       is_subset = new_category_filter.IsSubset(self._category_filter)
       assert(is_subset != False)
       if is_subset == None:
@@ -132,17 +50,32 @@ class TracingBackend(object):
                         'StartTracing call is subset of current filter.')
       return False
     self._CheckNotificationSupported()
+    #TODO(nednguyen): remove this when the stable branch pass 2118.
+    if (trace_options.record_mode == tracing_options.RECORD_AS_MUCH_AS_POSSIBLE
+        and self._chrome_browser_backend.chrome_branch_number
+        and self._chrome_browser_backend.chrome_branch_number < 2118):
+      logging.warning(
+          'Cannot use %s tracing mode on chrome browser with branch version %i,'
+          ' (<2118) fallback to use %s tracing mode' % (
+              trace_options.record_mode,
+              self._chrome_browser_backend.chrome_branch_number,
+              tracing_options.RECORD_UNTIL_FULL))
+      trace_options.record_mode = tracing_options.RECORD_UNTIL_FULL
     req = {'method': 'Tracing.start'}
-    self._category_filter = CategoryFilter(custom_categories)
+    req['params'] = {}
+    m = {tracing_options.RECORD_UNTIL_FULL: 'record-until-full',
+         tracing_options.RECORD_AS_MUCH_AS_POSSIBLE:
+         'record-as-much-as-possible'}
+    req['params']['options'] = m[trace_options.record_mode]
+    self._category_filter = tracing_category_filter.TracingCategoryFilter(
+        filter_string=custom_categories)
     if custom_categories:
-      req['params'] = {'categories': custom_categories}
+      req['params']['categories'] = custom_categories
     self._inspector_websocket.SyncRequest(req, timeout)
-    # Tracing.start will send asynchronous notifications containing trace
-    # data, until Tracing.end is called.
-    self._inspector_websocket.StartAsyncDispatchNotifications()
+    self._is_tracing_running = True
     return True
 
-  def StopTracing(self):
+  def StopTracing(self, timeout=30):
     """ Stops tracing on the innermost (!) nested call, because we cannot get
         results otherwise. Resets _tracing_data on the outermost nested call.
         Returns the result of the trace, as TracingTimelineData object.
@@ -152,7 +85,19 @@ class TracingBackend(object):
     if self.is_tracing_running:
       req = {'method': 'Tracing.end'}
       self._inspector_websocket.SendAndIgnoreResponse(req)
-      self._inspector_websocket.StopAsyncDispatchNotifications()
+      # After Tracing.end, chrome browser will send asynchronous notifications
+      # containing trace data. This is until Tracing.tracingComplete is sent,
+      # which means there is no trace buffers pending flush.
+      try:
+        self._inspector_websocket.DispatchNotificationsUntilDone(timeout)
+      except \
+          inspector_websocket.DispatchNotificationsUntilDoneTimeoutException \
+          as err:
+        raise TracingTimeoutException(
+            'Trace data was not fully received due to timeout after %s '
+            'seconds. If the trace data is big, you may want to increase the '
+            'time out amount.' % err.elapsed_time)
+      self._is_tracing_running = False
     if self._nesting == 0:
       self._category_filter = None
       return self._GetTraceResultAndReset()