Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / backends / chrome / tracing_backend.py
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import logging
6
7 from telemetry.core.backends.chrome import inspector_websocket
8 from telemetry.core.platform import tracing_options
9
10
11 class TracingUnsupportedException(Exception):
12   pass
13
14
15 class TracingTimeoutException(Exception):
16   pass
17
18 class TracingHasNotRunException(Exception):
19   pass
20
21
22 class TracingBackend(object):
23   def __init__(self, devtools_port, chrome_browser_backend):
24     self._inspector_websocket = inspector_websocket.InspectorWebsocket(
25         self._NotificationHandler,
26         self._ErrorHandler)
27
28     self._inspector_websocket.Connect(
29         'ws://127.0.0.1:%i/devtools/browser' % devtools_port)
30     self._tracing_data = []
31     self._is_tracing_running = False
32     self._chrome_browser_backend = chrome_browser_backend
33
34   @property
35   def is_tracing_running(self):
36     return self._is_tracing_running
37
38   def StartTracing(self, trace_options, custom_categories=None, timeout=10):
39     """ Starts tracing on the first call and returns True. Returns False
40         and does nothing on subsequent nested calls.
41     """
42     if self.is_tracing_running:
43       return False
44     # Reset collected tracing data from previous tracing calls.
45     self._tracing_data = []
46     self._CheckNotificationSupported()
47     #TODO(nednguyen): remove this when the stable branch pass 2118.
48     if (trace_options.record_mode == tracing_options.RECORD_AS_MUCH_AS_POSSIBLE
49         and self._chrome_browser_backend.chrome_branch_number
50         and self._chrome_browser_backend.chrome_branch_number < 2118):
51       logging.warning(
52           'Cannot use %s tracing mode on chrome browser with branch version %i,'
53           ' (<2118) fallback to use %s tracing mode' % (
54               trace_options.record_mode,
55               self._chrome_browser_backend.chrome_branch_number,
56               tracing_options.RECORD_UNTIL_FULL))
57       trace_options.record_mode = tracing_options.RECORD_UNTIL_FULL
58     req = {'method': 'Tracing.start'}
59     req['params'] = {}
60     m = {tracing_options.RECORD_UNTIL_FULL: 'record-until-full',
61          tracing_options.RECORD_AS_MUCH_AS_POSSIBLE:
62          'record-as-much-as-possible'}
63     req['params']['options'] = m[trace_options.record_mode]
64     if custom_categories:
65       req['params']['categories'] = custom_categories
66     self._inspector_websocket.SyncRequest(req, timeout)
67     self._is_tracing_running = True
68     return True
69
70   def StopTracing(self, timeout=30):
71     """ Stops tracing and returns the raw json trace result. It this is called
72     after tracing has been stopped, trace data from the last tracing run is
73     returned.
74     """
75     if not self.is_tracing_running:
76       if not self._tracing_data:
77         raise TracingHasNotRunException()
78       else:
79         return self._tracing_data
80     req = {'method': 'Tracing.end'}
81     self._inspector_websocket.SendAndIgnoreResponse(req)
82     # After Tracing.end, chrome browser will send asynchronous notifications
83     # containing trace data. This is until Tracing.tracingComplete is sent,
84     # which means there is no trace buffers pending flush.
85     try:
86       self._inspector_websocket.DispatchNotificationsUntilDone(timeout)
87     except \
88         inspector_websocket.DispatchNotificationsUntilDoneTimeoutException \
89         as err:
90       raise TracingTimeoutException(
91           'Trace data was not fully received due to timeout after %s '
92           'seconds. If the trace data is big, you may want to increase the '
93           'time out amount.' % err.elapsed_time)
94     self._is_tracing_running = False
95     return self._tracing_data
96
97   def _ErrorHandler(self, elapsed):
98     logging.error('Unrecoverable error after %ds reading tracing response.',
99                   elapsed)
100     raise
101
102   def _NotificationHandler(self, res):
103     if 'Tracing.dataCollected' == res.get('method'):
104       value = res.get('params', {}).get('value')
105       if type(value) in [str, unicode]:
106         self._tracing_data.append(value)
107       elif type(value) is list:
108         self._tracing_data.extend(value)
109       else:
110         logging.warning('Unexpected type in tracing data')
111     elif 'Tracing.tracingComplete' == res.get('method'):
112       return True
113
114   def Close(self):
115     self._inspector_websocket.Disconnect()
116
117   def _CheckNotificationSupported(self):
118     """Ensures we're running against a compatible version of chrome."""
119     req = {'method': 'Tracing.hasCompleted'}
120     res = self._inspector_websocket.SyncRequest(req)
121     if res.get('response'):
122       raise TracingUnsupportedException(
123           'Tracing not supported for this browser')
124     elif 'error' in res:
125       return