win_pgo_profiler.py revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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 5import glob 6import os 7import subprocess 8import sys 9 10from telemetry.core.platform import profiler 11 12 13_PGOSWEEP_EXECUTABLE = 'pgosweep.exe' 14 15 16class WinPGOProfiler(profiler.Profiler): 17 """A profiler that run the Visual Studio PGO utility 'pgosweep.exe' before 18 terminating a browser or a renderer process. 19 """ 20 21 def __init__(self, browser_backend, platform_backend, output_path, state): 22 super(WinPGOProfiler, self).__init__( 23 browser_backend, platform_backend, output_path, state) 24 25 pgosweep_is_in_path = False 26 for entry in os.environ['PATH'].split(os.pathsep): 27 if os.path.exists(os.path.join(entry, _PGOSWEEP_EXECUTABLE)): 28 pgosweep_is_in_path = True 29 break 30 if not pgosweep_is_in_path: 31 raise IOError(2, '%s isn\'t in the current path, run vcvarsall.bat to fix' 32 ' this.' % _PGOSWEEP_EXECUTABLE) 33 34 self._browser_dir = browser_backend.browser_directory 35 self._chrome_pgc_counter = self._GetNextProfileIndex('chrome') 36 self._chrome_child_pgc_counter = self._GetNextProfileIndex('chrome_child') 37 38 def _GetNextProfileIndex(self, dll_name): 39 """Scan the directory containing the DLL |dll_name| to find the next index 40 to use for the profile data files. 41 42 Args: 43 dll_name: The name of the DLL for which we want to get the next index to 44 to use. 45 """ 46 max_index = 0 47 pgc_files = glob.glob(os.path.join(self._browser_dir, 48 '%s!*.pgc' % dll_name)) 49 for pgc_file in pgc_files: 50 max_index = max(max_index, 51 int(os.path.splitext(os.path.split(pgc_file)[1])[0].split('!')[1])) 52 return max_index + 1 53 54 def _RunPGOSweep(self, pid, dll_name, index): 55 """Run the pgosweep utility to gather the profile data of a given process. 56 57 Args: 58 pid: The PID of the process we're interested in. 59 dll_name: The name of the DLL for which we want the profile data. 60 index: The index to use for the profile data file. 61 62 Returns the name of the profile data file. 63 """ 64 pgc_filename = '%s\\%s!%d.pgc' % (self._browser_dir, dll_name, index) 65 subprocess.Popen([_PGOSWEEP_EXECUTABLE, 66 '/pid:%d' % pid, 67 '%s.dll' % dll_name, 68 pgc_filename] 69 ).wait() 70 return pgc_filename 71 72 @classmethod 73 def name(cls): 74 return 'win_pgo_profiler' 75 76 @classmethod 77 def is_supported(cls, browser_type): 78 # This profiler only make sense when doing a Windows build with Visual 79 # Studio (minimal supported version is 2013 Update 2). 80 return sys.platform.startswith('win') 81 82 @classmethod 83 def CustomizeBrowserOptions(cls, browser_type, options): 84 # The sandbox need to be disabled if we want to be able to gather the 85 # profile data. 86 options.AppendExtraBrowserArgs('--no-sandbox') 87 88 def CollectProfile(self): 89 """Collect the profile data for the current processes.""" 90 output_files = [] 91 for pid, output_file in self._GetProcessOutputFileMap().iteritems(): 92 if 'renderer' in output_file: 93 output_files.append(self._RunPGOSweep(pid, 94 'chrome_child', 95 self._chrome_child_pgc_counter)) 96 self._chrome_child_pgc_counter += 1 97 elif 'browser0' in output_file: 98 output_files.append(self._RunPGOSweep(pid, 99 'chrome', 100 self._chrome_pgc_counter)) 101 self._chrome_pgc_counter += 1 102 return output_files 103