diff options
author | bulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 00:32:10 +0000 |
---|---|---|
committer | bulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-18 00:32:10 +0000 |
commit | a0a5a3a03e51c8d8cf6fa2e4bd1d55ba72a836cc (patch) | |
tree | 15a2aecb6b8191703e2ae50f58361367bf237c3e /tools/telemetry | |
parent | 36ed2103b130db30ad7fe5a50675ecb48d5c78de (diff) | |
download | chromium_src-a0a5a3a03e51c8d8cf6fa2e4bd1d55ba72a836cc.zip chromium_src-a0a5a3a03e51c8d8cf6fa2e4bd1d55ba72a836cc.tar.gz chromium_src-a0a5a3a03e51c8d8cf6fa2e4bd1d55ba72a836cc.tar.bz2 |
Telemetry / Devtools TraceHandler: exposes tracing via dev tools.
- exposes start / stop / get request methods via devtools.
This allows Telemetry to integrate trace collection across all platforms in a consistent
way.
BUG=
TEST=./tools/telemetry/run_tests --browser=android-content-shell testGotTrace
Review URL: https://chromiumcodereview.appspot.com/11548032
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173595 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/telemetry')
-rw-r--r-- | tools/telemetry/telemetry/browser.py | 13 | ||||
-rw-r--r-- | tools/telemetry/telemetry/browser_backend.py | 20 | ||||
-rw-r--r-- | tools/telemetry/telemetry/page_runner.py | 79 | ||||
-rw-r--r-- | tools/telemetry/telemetry/tracing_backend.py | 63 | ||||
-rw-r--r-- | tools/telemetry/telemetry/tracing_backend_unittest.py | 33 |
5 files changed, 155 insertions, 53 deletions
diff --git a/tools/telemetry/telemetry/browser.py b/tools/telemetry/telemetry/browser.py index a01cbfc..cfa2569 100644 --- a/tools/telemetry/telemetry/browser.py +++ b/tools/telemetry/telemetry/browser.py @@ -54,6 +54,19 @@ class Browser(object): def tabs(self): return self._backend.tabs + @property + def supports_tracing(self): + return self._backend.supports_tracing + + def StartTracing(self): + return self._backend.StartTracing() + + def StopTracing(self): + return self._backend.StopTracing() + + def GetTrace(self): + return self._backend.GetTrace() + def Close(self): """Closes this browser.""" if self._wpr_server: diff --git a/tools/telemetry/telemetry/browser_backend.py b/tools/telemetry/telemetry/browser_backend.py index 5afa946..11eecf9 100644 --- a/tools/telemetry/telemetry/browser_backend.py +++ b/tools/telemetry/telemetry/browser_backend.py @@ -1,6 +1,7 @@ # Copyright (c) 2012 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 urllib2 import httplib import socket @@ -10,6 +11,7 @@ import weakref from telemetry import browser_gone_exception from telemetry import tab +from telemetry import tracing_backend from telemetry import user_agent from telemetry import util from telemetry import wpr_modes @@ -123,6 +125,7 @@ class BrowserBackend(object): self._inspector_protocol_version = 0 self._chrome_branch_number = 0 self._webkit_base_revision = 0 + self._tracing_backend = None def SetBrowser(self, browser): self.tabs = TabController(browser, self) @@ -186,6 +189,23 @@ class BrowserBackend(object): def supports_tab_control(self): return self._chrome_branch_number >= 1303 + @property + def supports_tracing(self): + return True + + def StartTracing(self): + self._tracing_backend = tracing_backend.TracingBackend(self._port) + self._tracing_backend.BeginTracing() + + def StopTracing(self): + self._tracing_backend.EndTracingAsync() + + def GetTrace(self): + def IsTracingRunning(self): + return not self._tracing_backend.HasCompleted() + util.WaitFor(lambda: not IsTracingRunning(self), 10) + return self._tracing_backend.GetTraceAndReset() + def CreateForwarder(self, host_port): raise NotImplementedError() diff --git a/tools/telemetry/telemetry/page_runner.py b/tools/telemetry/telemetry/page_runner.py index ffe2251..c19d74a 100644 --- a/tools/telemetry/telemetry/page_runner.py +++ b/tools/telemetry/telemetry/page_runner.py @@ -23,13 +23,9 @@ class _RunState(object): self.first_browser = True self.browser = None self.tab = None - self.trace_tab = None + self.is_tracing = False def Close(self): - if self.trace_tab: - self.trace_tab.Disconnect() - self.trace_tab = None - if self.tab: self.tab.Disconnect() self.tab = None @@ -136,7 +132,7 @@ http://goto/read-src-internal, or create a new archive using record_wpr. logging.warning('Tab crashed: %s%s', page.url, stdout) state.Close() - if options.trace_dir and state.trace_tab: + if options.trace_dir: self._EndTracing(state, options, page) break except browser_gone_exception.BrowserGoneException: @@ -228,56 +224,33 @@ http://goto/read-src-internal, or create a new archive using record_wpr. state.browser.SetReplayArchivePath(archive_path) def _SetupTracingTab(self, state): - if not state.trace_tab: - # Swap the two tabs because new tabs open to about:blank, and we - # can't navigate across protocols to chrome://tracing. The initial - # tab starts at chrome://newtab, so it works for that tab. - # TODO(dtu): If the trace_tab crashes, we're hosed. - state.trace_tab = state.tab - state.tab = state.browser.tabs.New() + if state.browser.supports_tracing: + state.is_tracing = True + state.browser.StartTracing() - state.trace_tab.page.Navigate('chrome://tracing') - state.trace_tab.WaitForDocumentReadyStateToBeInteractiveOrBetter() + def _EndTracing(self, state, options, page): + if state.is_tracing: + state.is_tracing = False + state.browser.StopTracing() + trace = state.browser.GetTrace() + logging.info('Processing trace...') - # Start tracing. - state.trace_tab.runtime.Execute('tracingController.beginTracing(' - 'tracingController.supportsSystemTracing);') + trace_file_base = os.path.join( + options.trace_dir, page.url_as_file_safe_name) - def _EndTracing(self, state, options, page): - def IsTracingRunning(): - return state.trace_tab.runtime.Evaluate( - 'tracingController.isTracingEnabled') - # Tracing might have ended already if the buffer filled up. - if IsTracingRunning(): - state.trace_tab.runtime.Execute('tracingController.endTracing()') - util.WaitFor(lambda: not IsTracingRunning(), 10) - - logging.info('Processing trace...') - - trace_file_base = os.path.join( - options.trace_dir, page.url_as_file_safe_name) - - if options.page_repeat != 1 or options.pageset_repeat != 1: - trace_file_index = 0 - - while True: - trace_file = '%s_%03d.json' % (trace_file_base, trace_file_index) - if not os.path.exists(trace_file): - break - trace_file_index = trace_file_index + 1 - else: - trace_file = '%s.json' % trace_file_base - - with open(trace_file, 'w') as trace_file: - trace_file.write(state.trace_tab.runtime.Evaluate(""" - JSON.stringify({ - traceEvents: tracingController.traceEvents, - systemTraceEvents: tracingController.systemTraceEvents, - clientInfo: tracingController.clientInfo_, - gpuInfo: tracingController.gpuInfo_ - }); - """)) - logging.info('Trace saved.') + if options.page_repeat != 1 or options.pageset_repeat != 1: + trace_file_index = 0 + + while True: + trace_file = '%s_%03d.json' % (trace_file_base, trace_file_index) + if not os.path.exists(trace_file): + break + trace_file_index = trace_file_index + 1 + else: + trace_file = '%s.json' % trace_file_base + with open(trace_file, 'w') as trace_file: + trace_file.write(trace) + logging.info('Trace saved.') def _PreparePage(self, page, tab, page_state, results): parsed_url = urlparse.urlparse(page.url) diff --git a/tools/telemetry/telemetry/tracing_backend.py b/tools/telemetry/telemetry/tracing_backend.py new file mode 100644 index 0000000..54f9057 --- /dev/null +++ b/tools/telemetry/telemetry/tracing_backend.py @@ -0,0 +1,63 @@ +# Copyright (c) 2012 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 json +import logging +import socket + +from telemetry import util +from telemetry import websocket + + +class TracingBackend(object): + def __init__(self, devtools_port): + debugger_url = 'ws://localhost:%i/devtools/browser' % devtools_port + self._socket = websocket.create_connection(debugger_url) + self._next_request_id = 0 + self._cur_socket_timeout = 0 + + def BeginTracing(self): + req = {'method': 'Tracing.start'} + self._SyncRequest(req) + + def EndTracingAsync(self): + req = {'method': 'Tracing.end'} + self._SyncRequest(req) + + def HasCompleted(self): + req = {'method': 'Tracing.hasCompleted'} + r = self._SyncRequest(req) + return r['response']['result'] + + def GetTraceAndReset(self): + req = {'method': 'Tracing.getTraceAndReset'} + r = self._SyncRequest(req) + return '{"traceEvents":[' + r['response']['result'] + ']}' + + def _SyncRequest(self, req, timeout=10): + self._SetTimeout(timeout) + req['id'] = self._next_request_id + self._next_request_id += 1 + data = json.dumps(req) + logging.debug('will send [%s]', data) + self._socket.send(data) + + while True: + try: + data = self._socket.recv() + except (socket.error, websocket.WebSocketException): + raise util.TimeoutException( + 'Timed out waiting for reply. This is unusual.') + + logging.debug('got [%s]', data) + res = json.loads(data) + if res['id'] != req['id']: + logging.debug('Dropped reply: %s', json.dumps(res)) + continue + return res + + def _SetTimeout(self, timeout): + if self._cur_socket_timeout != timeout: + self._socket.settimeout(timeout) + self._cur_socket_timeout = timeout diff --git a/tools/telemetry/telemetry/tracing_backend_unittest.py b/tools/telemetry/telemetry/tracing_backend_unittest.py new file mode 100644 index 0000000..7a8370d --- /dev/null +++ b/tools/telemetry/telemetry/tracing_backend_unittest.py @@ -0,0 +1,33 @@ +# Copyright (c) 2012 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 json +import os + +from telemetry import tab_test_case +from telemetry import util + + +class TracingBackendTest(tab_test_case.TabTestCase): + def _StartServer(self): + base_dir = os.path.dirname(__file__) + self._browser.SetHTTPServerDirectory(os.path.join(base_dir, '..', + 'unittest_data')) + + def _WaitForAnimationFrame(self): + def _IsDone(): + js_is_done = """done""" + return bool(self._tab.runtime.Evaluate(js_is_done)) + util.WaitFor(_IsDone, 5) + + def testGotTrace(self): + self._StartServer() + self._browser.StartTracing() + self._browser.http_server.UrlOf('image.png') + self.assertTrue(self._browser.supports_tracing) + self._browser.StopTracing() + trace = self._browser.GetTrace() + json_trace = json.loads(trace) + self.assertTrue('traceEvents' in json_trace) + self.assertTrue(json_trace['traceEvents']) |