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