Home | History | Annotate | Download | only in adb_profile_chrome
      1 # Copyright 2014 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 json
      6 import os
      7 import re
      8 import time
      9 
     10 from adb_profile_chrome import controllers
     11 
     12 from pylib import pexpect
     13 
     14 _HEAP_PROFILE_MMAP_PROPERTY = 'heapprof.mmap'
     15 
     16 class ChromeTracingController(controllers.BaseController):
     17   def __init__(self, device, package_info,
     18                categories, ring_buffer, trace_memory=False):
     19     controllers.BaseController.__init__(self)
     20     self._device = device
     21     self._package_info = package_info
     22     self._categories = categories
     23     self._ring_buffer = ring_buffer
     24     self._trace_file = None
     25     self._trace_interval = None
     26     self._trace_memory = trace_memory
     27     self._trace_start_re = \
     28        re.compile(r'Logging performance trace to file')
     29     self._trace_finish_re = \
     30        re.compile(r'Profiler finished[.] Results are in (.*)[.]')
     31     self._device.old_interface.StartMonitoringLogcat(clear=False)
     32 
     33   def __repr__(self):
     34     return 'chrome trace'
     35 
     36   @staticmethod
     37   def GetCategories(device, package_info):
     38     device.old_interface.BroadcastIntent(
     39         package_info.package, 'GPU_PROFILER_LIST_CATEGORIES')
     40     try:
     41       json_category_list = device.old_interface.WaitForLogMatch(
     42           re.compile(r'{"traceCategoriesList(.*)'), None, timeout=5).group(0)
     43     except pexpect.TIMEOUT:
     44       raise RuntimeError('Performance trace category list marker not found. '
     45                          'Is the correct version of the browser running?')
     46 
     47     record_categories = []
     48     disabled_by_default_categories = []
     49     json_data = json.loads(json_category_list)['traceCategoriesList']
     50     for item in json_data:
     51       if item.startswith('disabled-by-default'):
     52         disabled_by_default_categories.append(item)
     53       else:
     54         record_categories.append(item)
     55 
     56     return record_categories, disabled_by_default_categories
     57 
     58   def StartTracing(self, interval):
     59     self._trace_interval = interval
     60     self._device.old_interface.SyncLogCat()
     61     self._device.old_interface.BroadcastIntent(
     62         self._package_info.package, 'GPU_PROFILER_START',
     63         '-e categories "%s"' % ','.join(self._categories),
     64         '-e continuous' if self._ring_buffer else '')
     65 
     66     if self._trace_memory:
     67       self._device.old_interface.EnableAdbRoot()
     68       self._device.old_interface.system_properties \
     69           [_HEAP_PROFILE_MMAP_PROPERTY] = 1
     70 
     71     # Chrome logs two different messages related to tracing:
     72     #
     73     # 1. "Logging performance trace to file"
     74     # 2. "Profiler finished. Results are in [...]"
     75     #
     76     # The first one is printed when tracing starts and the second one indicates
     77     # that the trace file is ready to be pulled.
     78     try:
     79       self._device.old_interface.WaitForLogMatch(
     80           self._trace_start_re, None, timeout=5)
     81     except pexpect.TIMEOUT:
     82       raise RuntimeError('Trace start marker not found. Is the correct version '
     83                          'of the browser running?')
     84 
     85   def StopTracing(self):
     86     self._device.old_interface.BroadcastIntent(
     87         self._package_info.package,
     88         'GPU_PROFILER_STOP')
     89     self._trace_file = self._device.old_interface.WaitForLogMatch(
     90         self._trace_finish_re, None, timeout=120).group(1)
     91     if self._trace_memory:
     92       self._device.old_interface.system_properties \
     93           [_HEAP_PROFILE_MMAP_PROPERTY] = 0
     94 
     95   def PullTrace(self):
     96     # Wait a bit for the browser to finish writing the trace file.
     97     time.sleep(self._trace_interval / 4 + 1)
     98 
     99     trace_file = self._trace_file.replace('/storage/emulated/0/', '/sdcard/')
    100     host_file = os.path.join(os.path.curdir, os.path.basename(trace_file))
    101     self._device.old_interface.PullFileFromDevice(trace_file, host_file)
    102     return host_file
    103