Commit 1b678864 authored by Michael Spang's avatar Michael Spang Committed by Commit Bot

chromecast: trace.py: Add support for requesting compressed traces

This adds the ability for trace.py to request compression of traces,
giving us much more headroom in /tmp. Compressed traces are about 1/10th
the size of uncompressed traces.

Compressed traces have to be base64 decoded when read from the websocket,
since those have a bizarre requirement that the payload be valid utf-8.

BUG=791708

Change-Id: I22f0c4aa70e22d9a33e3f2d3dd9a2180df33a815
Reviewed-on: https://chromium-review.googlesource.com/812012Reviewed-by: default avatarLuke Halliwell <halliwell@chromium.org>
Commit-Queue: Michael Spang <spang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522304}
parent faf0c664
...@@ -100,11 +100,11 @@ def main(): ...@@ -100,11 +100,11 @@ def main():
tracing_backend.StartTracing(options.category_filter, tracing_backend.StartTracing(options.category_filter,
options.record_continuously, options.systrace) options.record_continuously, options.systrace)
raw_input('Capturing trace. Press Enter to stop...') raw_input('Capturing trace. Press Enter to stop...')
filepath = GetOutputFilePath(options) output_path_base = GetOutputFilePath(options)
tracing_backend.StopTracing(filepath) output_path = tracing_backend.StopTracing(output_path_base)
print('Done') print('Done')
print('Trace written to file://%s' % filepath) print('Trace written to file://%s' % output_path)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
"""Utilities for capturing traces for chromecast devices.""" """Utilities for capturing traces for chromecast devices."""
import base64
import json import json
import logging import logging
import math import math
...@@ -45,6 +46,7 @@ class TracingBackend(object): ...@@ -45,6 +46,7 @@ class TracingBackend(object):
self._excluded_categories = [] self._excluded_categories = []
self._pending_read_ids = [] self._pending_read_ids = []
self._stream_handle = None self._stream_handle = None
self._output_file = None
def Connect(self): def Connect(self):
"""Connect to cast_shell.""" """Connect to cast_shell."""
...@@ -82,6 +84,8 @@ class TracingBackend(object): ...@@ -82,6 +84,8 @@ class TracingBackend(object):
'params': { 'params': {
'transferMode': 'transferMode':
'ReturnAsStream' if systrace else 'ReportEvents', 'ReturnAsStream' if systrace else 'ReportEvents',
'streamCompression':
'gzip' if systrace else 'none',
'traceConfig': { 'traceConfig': {
'enableSystrace': 'enableSystrace':
systrace, systrace,
...@@ -99,28 +103,39 @@ class TracingBackend(object): ...@@ -99,28 +103,39 @@ class TracingBackend(object):
} }
self._SendRequest(req) self._SendRequest(req)
def StopTracing(self, output_file): def StopTracing(self, output_path_base):
"""End a tracing session on device. """End a tracing session on device.
Args: Args:
output_file: Path to the file to store the trace. output_path_base: Path to the file to store the trace. A .gz extension
will be appended to this path if the trace is compressed.
Returns:
Final output filename.
""" """
self._socket.settimeout(self._timeout) self._socket.settimeout(self._timeout)
req = {'method': 'Tracing.end'} req = {'method': 'Tracing.end'}
self._SendRequest(req) self._SendRequest(req)
self._output_path_base = output_path_base
with open(output_file, 'w') as f: try:
while self._socket: while self._socket:
res = self._ReceiveResponse() res = self._ReceiveResponse()
has_error = 'error' in res has_error = 'error' in res
if has_error: if has_error:
logging.error('Tracing error: ' + str(res.get('error'))) logging.error('Tracing error: ' + str(res.get('error')))
if has_error or self._HandleResponse(res, f): if has_error or self._HandleResponse(res):
self._tracing_client = None self._tracing_client = None
if not self._stream_handle: if not self._stream_handle:
json.dump(self._tracing_data, f) # Compression not supported for ReportEvents transport.
self._output_path = self._output_path_base
with open(self._output_path, 'w') as output_file:
json.dump(self._tracing_data, output_file)
self._tracing_data = [] self._tracing_data = []
return return self._output_path
finally:
if self._output_file:
self._output_file.close()
def _SendRequest(self, req): def _SendRequest(self, req):
"""Sends request to remote devtools. """Sends request to remote devtools.
...@@ -159,7 +174,7 @@ class TracingBackend(object): ...@@ -159,7 +174,7 @@ class TracingBackend(object):
while len(self._pending_read_ids) < 2: while len(self._pending_read_ids) < 2:
self._pending_read_ids.append(self._SendRequest(req)) self._pending_read_ids.append(self._SendRequest(req))
def _HandleResponse(self, res, output_file): def _HandleResponse(self, res):
"""Handle response from remote devtools. """Handle response from remote devtools.
Args: Args:
...@@ -179,7 +194,13 @@ class TracingBackend(object): ...@@ -179,7 +194,13 @@ class TracingBackend(object):
self._tracing_client.BufferUsage(value) self._tracing_client.BufferUsage(value)
elif 'Tracing.tracingComplete' == method: elif 'Tracing.tracingComplete' == method:
self._stream_handle = res.get('params', {}).get('stream') self._stream_handle = res.get('params', {}).get('stream')
compression = res.get('params', {}).get('streamCompression')
if self._stream_handle: if self._stream_handle:
compression_suffix = '.gz' if compression == 'gzip' else ''
self._output_path = self._output_path_base
if not self._output_path.endswith(compression_suffix):
self._output_path += compression_suffix
self._output_file = open(self._output_path, 'w')
self._SendReadRequest() self._SendReadRequest()
else: else:
return True return True
...@@ -187,7 +208,12 @@ class TracingBackend(object): ...@@ -187,7 +208,12 @@ class TracingBackend(object):
self._pending_read_ids.remove(response_id) self._pending_read_ids.remove(response_id)
data = res.get('result', {}).get('data') data = res.get('result', {}).get('data')
eof = res.get('result', {}).get('eof') eof = res.get('result', {}).get('eof')
output_file.write(data.encode('utf-8')) base64_encoded = res.get('result', {}).get('base64Encoded')
if base64_encoded:
data = base64.b64decode(data)
else:
data = data.encode('utf-8')
self._output_file.write(data)
if eof: if eof:
return True return True
else: else:
...@@ -262,6 +288,7 @@ class TracingBackendAndroid(object): ...@@ -262,6 +288,7 @@ class TracingBackendAndroid(object):
break break
self._AdbCommand(['pull', self._file, output_file]) self._AdbCommand(['pull', self._file, output_file])
return output_file
def _AdbCommand(self, command): def _AdbCommand(self, command):
args = ['adb', '-s', self.device] args = ['adb', '-s', self.device]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment