tcmalloc_heap_profiler.py revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1# Copyright (c) 2013 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 5import logging 6import os 7import sys 8 9from telemetry.core.backends.chrome import android_browser_finder 10from telemetry.core.platform import profiler 11 12# Enviroment variables to (android properties, default value) mapping. 13_ENV_VARIABLES = { 14 'HEAP_PROFILE_TIME_INTERVAL': ('heapprof.time_interval', 20), 15 'HEAP_PROFILE_MMAP': ('heapprof.mmap', 1), 16 'DEEP_HEAP_PROFILE': ('heapprof.deep_heap_profile', 1), 17} 18 19 20class _TCMallocHeapProfilerAndroid(object): 21 """An internal class to set android properties and fetch dumps from device.""" 22 23 _DEFAULT_DEVICE_DIR = '/data/local/tmp/heap' 24 25 def __init__(self, browser_backend, output_path): 26 self._browser_backend = browser_backend 27 self._output_path = output_path 28 29 _ENV_VARIABLES['HEAPPROFILE'] = ('heapprof', 30 os.path.join(self._DEFAULT_DEVICE_DIR, 'dmprof')) 31 32 self._SetDeviceProperties(_ENV_VARIABLES) 33 34 def _SetDeviceProperties(self, properties): 35 device_configured = False 36 # This profiler requires adb root to set properties. 37 self._browser_backend.adb.Adb().EnableAdbRoot() 38 for values in properties.itervalues(): 39 device_property = self._browser_backend.adb.RunShellCommand( 40 'getprop ' + values[0]) 41 if (not device_property or len(device_property) != 1 or 42 not device_property[0].strip()): 43 print 'Setting device property ', values[0], values[1] 44 self._browser_backend.adb.RunShellCommand( 45 'setprop ' + values[0] + ' ' + str(values[1])) 46 device_configured = True 47 if not self._browser_backend.adb.Adb().FileExistsOnDevice( 48 self._DEFAULT_DEVICE_DIR): 49 self._browser_backend.adb.RunShellCommand( 50 'mkdir -p ' + self._DEFAULT_DEVICE_DIR) 51 self._browser_backend.adb.RunShellCommand( 52 'chmod 777 ' + self._DEFAULT_DEVICE_DIR) 53 device_configured = True 54 if device_configured: 55 raise Exception('Device required special config, run again.') 56 57 def CollectProfile(self): 58 self._browser_backend.adb.Adb().Adb().Pull( 59 self._DEFAULT_DEVICE_DIR, self._output_path) 60 self._browser_backend.adb.RunShellCommand( 61 'rm ' + os.path.join(self._DEFAULT_DEVICE_DIR, '*')) 62 if os.path.exists(self._output_path): 63 logging.info('TCMalloc dumps pulled to %s', self._output_path) 64 with file(os.path.join(self._output_path, 65 'browser.pid'), 'w') as pid_file: 66 pid_file.write(str(self._browser_backend.pid).rjust(5, '0')) 67 return [self._output_path] 68 69 70class _TCMallocHeapProfilerLinux(object): 71 """An internal class to set environment variables and fetch dumps.""" 72 73 _DEFAULT_DIR = '/tmp/tcmalloc/' 74 75 def __init__(self, browser_backend): 76 self._browser_backend = browser_backend 77 _ENV_VARIABLES['HEAPPROFILE'] = ('heapprof', self._DEFAULT_DIR + 'dmprof') 78 self._CheckEnvironmentVariables(_ENV_VARIABLES) 79 80 def _CheckEnvironmentVariables(self, env_vars): 81 msg = '' 82 for key, values in env_vars.iteritems(): 83 if key not in os.environ: 84 msg += '%s=%s ' % (key, str(values[1])) 85 if msg: 86 raise Exception('Need enviroment variables, try again with:\n %s' % msg) 87 if not os.path.exists(os.environ['HEAPPROFILE']): 88 os.makedirs(os.environ['HEAPPROFILE']) 89 assert os.path.isdir(os.environ['HEAPPROFILE']), 'HEAPPROFILE is not a dir' 90 91 def CollectProfile(self): 92 with file(os.path.join(os.path.dirname(os.environ['HEAPPROFILE']), 93 'browser.pid'), 'w') as pid_file: 94 pid_file.write(str(self._browser_backend.pid)) 95 print 'TCMalloc dumps available ', os.environ['HEAPPROFILE'] 96 return [os.environ['HEAPPROFILE']] 97 98 99class TCMallocHeapProfiler(profiler.Profiler): 100 """A Factory to instantiate the platform-specific profiler.""" 101 def __init__(self, browser_backend, platform_backend, output_path, state): 102 super(TCMallocHeapProfiler, self).__init__( 103 browser_backend, platform_backend, output_path, state) 104 if platform_backend.GetOSName() == 'android': 105 self._platform_profiler = _TCMallocHeapProfilerAndroid( 106 browser_backend, output_path) 107 else: 108 self._platform_profiler = _TCMallocHeapProfilerLinux(browser_backend) 109 110 @classmethod 111 def name(cls): 112 return 'tcmalloc-heap' 113 114 @classmethod 115 def is_supported(cls, browser_type): 116 if browser_type.startswith('cros'): 117 return False 118 if sys.platform.startswith('linux'): 119 return True 120 if browser_type == 'any': 121 return android_browser_finder.CanFindAvailableBrowsers() 122 return browser_type.startswith('android') 123 124 @classmethod 125 def CustomizeBrowserOptions(cls, browser_type, options): 126 options.AppendExtraBrowserArgs('--no-sandbox') 127 128 def CollectProfile(self): 129 return self._platform_profiler.CollectProfile() 130