13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
23551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
33551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# found in the LICENSE file.
43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import json
63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import logging
73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import re
83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import signal
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import subprocess
103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import sys
113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import tempfile
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)from telemetry.core.platform import profiler
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)from telemetry.timeline import model
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# Parses one line of strace output, for example:
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)# 6052  1311456063.159722 read(8, "\1\0\0\0\0\0\0\0", 8) = 8 <0.000022>
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)_STRACE_LINE_RE = re.compile(
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '^(?P<tid>\d+)\s+'
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<ts>\d+)'
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<micro>.\d+)\s+'
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<func>.*?)'
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '[(](?P<args>.*?)[)]\s+=\s+'
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<ret>.*?)\s+'
253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '<(?P<dur>[\d.]+)>$')
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)_UNFINISHED_LINE_RE = re.compile(
283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '^(?P<tid>\d+)\s+'
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<line>.*?)'
303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '<unfinished ...>$')
313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)_RESUMED_LINE_RE = re.compile(
333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '^(?P<tid>\d+)\s+'
343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<ts>\d+)'
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<micro>.\d+)\s+'
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '<[.][.][.]\s(?P<func>.*?)\sresumed>'
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<line>.*?)$')
383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)_KILLED_LINE_RE = re.compile(
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '^(?P<tid>\d+)\s+'
413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<ts>\d+)'
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '(?P<micro>.\d+)\s+'
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    '[+][+][+] killed by SIGKILL [+][+][+]$')
443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def _StraceToChromeTrace(pid, infile):
473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """Returns chrometrace json format for |infile| strace output."""
483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  # Map of fd:file_name for open file descriptors. Useful for displaying
493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  # file name instead of the descriptor number.
503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  fd_map = {}
513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  # Map of tid:interrupted_call for the interrupted call on each thread. It is
533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  # possible to context switch during a system call. In this case we must
543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  # match up the lines.
553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  interrupted_call_map = {}
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  out = []
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  with open(infile, 'r') as f:
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for line in f.readlines():
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      # Ignore kill lines for now.
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      m = _KILLED_LINE_RE.match(line)
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if m:
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        continue
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      # If this line is interrupted, then remember it and continue.
663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      m = _UNFINISHED_LINE_RE.match(line)
673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if m:
683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert m.group('tid') not in interrupted_call_map
693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        interrupted_call_map[m.group('tid')] = line
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        continue
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      # If this is a resume of a previous line, stitch it together.
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      interrupted = False
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      m = _RESUMED_LINE_RE.match(line)
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if m:
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        interrupted = True
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        assert m.group('tid') in interrupted_call_map
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        line = interrupted_call_map[m.group('tid')].replace(
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            '<unfinished ...>', m.group('line'))
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        del interrupted_call_map[m.group('tid')]
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      # At this point we can do a normal match.
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      m = _STRACE_LINE_RE.match(line)
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if not m:
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        if ('exit' not in line and
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            'Profiling timer expired' not in line and
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            '<unavailable>' not in line):
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          logging.warn('Failed to parse line: %s' % line)
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        continue
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ts_begin = int(1000000 * (int(m.group('ts')) + float(m.group('micro'))))
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ts_end = ts_begin + int(1000000 * float(m.group('dur')))
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      tid = int(m.group('tid'))
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      function_name = unicode(m.group('func'), errors='ignore')
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      function_args = unicode(m.group('args'), errors='ignore')
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      ret = unicode(m.group('ret'), errors='ignore')
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      cat = 'strace'
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      possible_fd_arg = None
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      first_arg = function_args.split(',')[0]
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if first_arg and first_arg.strip().isdigit():
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        possible_fd_arg = first_arg.strip()
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if function_name == 'open' and ret.isdigit():
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        # 1918  1311606151.649379 open("/foo/bar.so", O_RDONLY) = 7 <0.000088>
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        fd_map[ret] = first_arg
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      args = {
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'args': function_args,
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'ret': ret,
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          }
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if interrupted:
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        args['interrupted'] = True
1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if possible_fd_arg and possible_fd_arg in fd_map:
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        args['fd%s' % first_arg] = fd_map[possible_fd_arg]
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      out.append({
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'cat': cat,
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'pid': pid,
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'tid': tid,
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'ts': ts_begin,
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'ph': 'B',  # Begin
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'name': function_name,
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          })
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      out.append({
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'cat': cat,
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'pid': pid,
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'tid': tid,
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'ts': ts_end,
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'ph': 'E',  # End
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'name': function_name,
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'args': args,
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          })
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return out
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def _GenerateTraceMetadata(timeline_model):
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  out = []
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for process in timeline_model.processes:
1413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    out.append({
1423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        'name': 'process_name',
1433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        'ph': 'M',  # Metadata
1443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        'pid': process,
1453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        'args': {
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          'name': timeline_model.processes[process].name
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          }
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        })
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for thread in timeline_model.processes[process].threads:
1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      out.append({
1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'name': 'thread_name',
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'ph': 'M',  # Metadata
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'pid': process,
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'tid': thread,
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'args': {
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            'name': timeline_model.processes[process].threads[thread].name
1573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
1583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          })
1593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return out
1603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)class _SingleProcessStraceProfiler(object):
1633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  """An internal class for using perf for a given process."""
1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def __init__(self, pid, output_file, platform_backend):
1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._pid = pid
1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._platform_backend = platform_backend
1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._output_file = output_file
1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._tmp_output_file = tempfile.NamedTemporaryFile('w', 0)
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._proc = subprocess.Popen(
1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        ['strace', '-ttt', '-f', '-T', '-p', str(pid), '-o', output_file],
1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        stdout=self._tmp_output_file, stderr=subprocess.STDOUT)
1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def CollectProfile(self):
1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if ('renderer' in self._output_file and
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        not self._platform_backend.GetCommandLine(self._pid)):
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      logging.warning('Renderer was swapped out during profiling. '
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      'To collect a full profile rerun with '
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                      '"--extra-browser-args=--single-process"')
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._proc.send_signal(signal.SIGINT)
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    exit_code = self._proc.wait()
1813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    try:
1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if exit_code:
1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        raise Exception('strace failed with exit code %d. Output:\n%s' % (
1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                        exit_code, self._GetStdOut()))
1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    finally:
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      self._tmp_output_file.close()
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return _StraceToChromeTrace(self._pid, self._output_file)
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def _GetStdOut(self):
1913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._tmp_output_file.flush()
1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    try:
1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      with open(self._tmp_output_file.name) as f:
1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return f.read()
1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    except IOError:
1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return ''
1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)class StraceProfiler(profiler.Profiler):
2003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def __init__(self, browser_backend, platform_backend, output_path, state):
2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    super(StraceProfiler, self).__init__(
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        browser_backend, platform_backend, output_path, state)
2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    assert self._browser_backend.supports_tracing
2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._browser_backend.StartTracing(None, 10)
2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    process_output_file_map = self._GetProcessOutputFileMap()
2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._process_profilers = []
2083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    self._output_file = output_path + '.json'
2093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for pid, output_file in process_output_file_map.iteritems():
2103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if 'zygote' in output_file:
2113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        continue
2123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      self._process_profilers.append(
2133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          _SingleProcessStraceProfiler(pid, output_file, platform_backend))
2143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  @classmethod
2163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def name(cls):
2173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return 'strace'
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  @classmethod
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def is_supported(cls, browser_type):
2213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if sys.platform != 'linux2':
2223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return False
2233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    # TODO(tonyg): This should be supported on android and cros.
22458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (browser_type.startswith('android') or
22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       browser_type.startswith('cros')):
2263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return False
2273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return True
2283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  @classmethod
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CustomizeBrowserOptions(cls, browser_type, options):
23158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    options.AppendExtraBrowserArgs([
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        '--no-sandbox',
23358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        '--allow-sandbox-debugging'
23458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    ])
2353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def CollectProfile(self):
2373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    print 'Processing trace...'
2383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    out_json = []
2403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    for single_process in self._process_profilers:
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      out_json.extend(single_process.CollectProfile())
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeline_data = self._browser_backend.StopTracing()
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timeline_model = model.TimelineModel(timeline_data)
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    out_json.extend(_GenerateTraceMetadata(timeline_model))
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    with open(self._output_file, 'w') as f:
2493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      f.write(json.dumps(out_json, separators=(',', ':')))
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    print 'Trace saved as %s' % self._output_file
2523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    print 'To view, open in chrome://tracing'
2533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return [self._output_file]
254