Skip to content

Commit

Permalink
Chromecast: tracing script to use for Linux-based cast_shell.
Browse files Browse the repository at this point in the history
R=lcwu@chromium.org
BUG=336640

Review URL: https://codereview.chromium.org/962063002

Cr-Commit-Position: refs/heads/master@{#318396}
  • Loading branch information
gunsch authored and Commit bot committed Feb 27, 2015
1 parent 31c08a6 commit 7455cde
Showing 1 changed file with 185 additions and 0 deletions.
185 changes: 185 additions & 0 deletions chromecast/tools/trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#!/usr/bin/env python
#
# Copyright 2015 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.
#
# This script was originally written by Alok Priyadarshi (alokp@)
# with some minor local modifications.

import contextlib
import json
import logging
import math
import optparse
import os
import sys
import websocket


class TracingClient(object):
def BufferUsage(self, buffer_usage):
percent = int(math.floor(buffer_usage * 100))
logging.debug('Buffer Usage: %i', percent)


class TracingBackend(object):
def __init__(self, devtools_port):
self._socket = None
self._next_request_id = 0
self._tracing_client = None
self._tracing_data = []

def Connect(self, device_ip, devtools_port, timeout=10):
assert not self._socket
url = 'ws://%s:%i/devtools/browser' % (device_ip, devtools_port)
print('Connect to %s ...' % url)
self._socket = websocket.create_connection(url, timeout=timeout)
self._next_request_id = 0

def Disconnect(self):
if self._socket:
self._socket.close()
self._socket = None

def StartTracing(self,
tracing_client=None,
custom_categories=None,
record_continuously=False,
buffer_usage_reporting_interval=0,
timeout=10):
self._tracing_client = tracing_client
self._socket.settimeout(timeout)
req = {
'method': 'Tracing.start',
'params': {
'categories': custom_categories,
'bufferUsageReportingInterval': buffer_usage_reporting_interval,
'options': 'record-continuously' if record_continuously else
'record-until-full'
}
}
self._SendRequest(req)

def StopTracing(self, timeout=30):
self._socket.settimeout(timeout)
req = {'method': 'Tracing.end'}
self._SendRequest(req)
while self._socket:
res = self._ReceiveResponse()
if 'method' in res and self._HandleResponse(res):
self._tracing_client = None
result = self._tracing_data
self._tracing_data = []
return result

def _SendRequest(self, req):
req['id'] = self._next_request_id
self._next_request_id += 1
data = json.dumps(req)
self._socket.send(data)

def _ReceiveResponse(self):
while self._socket:
data = self._socket.recv()
res = json.loads(data)
return res

def _HandleResponse(self, res):
method = res.get('method')
value = res.get('params', {}).get('value')
if 'Tracing.dataCollected' == method:
if type(value) in [str, unicode]:
self._tracing_data.append(value)
elif type(value) is list:
self._tracing_data.extend(value)
else:
logging.warning('Unexpected type in tracing data')
elif 'Tracing.bufferUsage' == method and self._tracing_client:
self._tracing_client.BufferUsage(value)
elif 'Tracing.tracingComplete' == method:
return True


@contextlib.contextmanager
def Connect(device_ip, devtools_port):
backend = TracingBackend(devtools_port)
try:
backend.Connect(device_ip, devtools_port)
yield backend
finally:
backend.Disconnect()


def DumpTrace(trace, options):
filepath = os.path.expanduser(options.output) if options.output \
else os.path.join(os.getcwd(), 'trace.json')

dirname = os.path.dirname(filepath)
if dirname:
if not os.path.exists(dirname):
os.makedirs(dirname)
else:
filepath = os.path.join(os.getcwd(), filepath)

with open(filepath, "w") as f:
json.dump(trace, f)
return filepath


def _CreateOptionParser():
parser = optparse.OptionParser(description='Record about://tracing profiles '
'from any running instance of Chrome.')
parser.add_option(
'-v', '--verbose', help='Verbose logging.', action='store_true')
parser.add_option(
'-p', '--port', help='Remote debugging port.', type="int", default=9222)
parser.add_option(
'-d', '--device', help='Device ip address.', type='string',
default='127.0.0.1')

tracing_opts = optparse.OptionGroup(parser, 'Tracing options')
tracing_opts.add_option(
'-c', '--category-filter',
help='Apply filter to control what category groups should be traced.',
type='string')
tracing_opts.add_option(
'--record-continuously',
help='Keep recording until stopped. The trace buffer is of fixed size '
'and used as a ring buffer. If this option is omitted then '
'recording stops when the trace buffer is full.',
action='store_true')
parser.add_option_group(tracing_opts)

output_options = optparse.OptionGroup(parser, 'Output options')
output_options.add_option(
'-o', '--output',
help='Save trace output to file.')
parser.add_option_group(output_options)

return parser


def _ProcessOptions(options):
websocket.enableTrace(options.verbose)


def main():
parser = _CreateOptionParser()
options, _args = parser.parse_args()
_ProcessOptions(options)

with Connect(options.device, options.port) as tracing_backend:
tracing_backend.StartTracing(TracingClient(),
options.category_filter,
options.record_continuously)
raw_input('Capturing trace. Press Enter to stop...')
trace = tracing_backend.StopTracing()

filepath = DumpTrace(trace, options)
print('Done')
print('Trace written to file://%s' % filepath)


if __name__ == '__main__':
sys.exit(main())

0 comments on commit 7455cde

Please sign in to comment.