146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 2a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 3a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# found in the LICENSE file. 4a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 5a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import os 6a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import signal 7a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)import sys 8a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochfrom telemetry.core import exceptions 10a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)from telemetry.core import util 11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)from telemetry.core.platform import profiler 12a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 13a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# pexpect is not available on all platforms so use the third_party version. 143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'third_party', 'pexpect') 15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)try: 16a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) import pexpect # pylint: disable=F0401 17a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)except ImportError: 18a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) pass 19a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class _SingleProcessIprofilerProfiler(object): 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) """An internal class for using iprofiler for a given process.""" 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) def __init__(self, pid, output_path): 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._output_path = output_path 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) output_dir = os.path.dirname(self._output_path) 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) output_file = os.path.basename(self._output_path) 27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) self._proc = pexpect.spawn( 28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 'iprofiler', ['-timeprofiler', '-T', '300', '-a', str(pid), 29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) '-d', output_dir, '-o', output_file], 30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) timeout=300) 31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) while True: 32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if self._proc.getecho(): 33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output = self._proc.readline().strip() 34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if not output: 35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) continue 36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if 'iprofiler: Profiling process' in output: 37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break 38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) print output 39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) self._proc.interact(escape_character='\x0d') 40558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if 'Failed to authorize rights' in output: 41558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch raise exceptions.ProfilingException( 42558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch 'Failed to authorize rights for iprofiler\n') 43558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if 'iprofiler error' in output: 44558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch raise exceptions.ProfilingException( 45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch 'Failed to start iprofiler for process %s\n' % 46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch self._output_path.split('.')[1]) 47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) self._proc.write('\x0d') 48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) print 49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) def Echo(): 50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return self._proc.getecho() 51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) util.WaitFor(Echo, timeout=5) 52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) def CollectProfile(self): 5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._proc.kill(signal.SIGINT) 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) try: 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._proc.wait() 5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) except pexpect.ExceptionPexpect: 5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pass 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) finally: 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._proc = None 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) print 'To view the profile, run:' 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) print ' open -a Instruments %s.dtps' % self._output_path 64558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return self._output_path 6590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class IprofilerProfiler(profiler.Profiler): 6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def __init__(self, browser_backend, platform_backend, output_path, state): 7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) super(IprofilerProfiler, self).__init__( 714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) browser_backend, platform_backend, output_path, state) 7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) process_output_file_map = self._GetProcessOutputFileMap() 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._process_profilers = [] 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for pid, output_file in process_output_file_map.iteritems(): 75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if '.utility' in output_file: 76558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch # The utility process may not have been started by Telemetry. 77558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch # So we won't have permissing to profile it 78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch continue 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._process_profilers.append( 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) _SingleProcessIprofilerProfiler(pid, output_file)) 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) @classmethod 83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) def name(cls): 84a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return 'iprofiler' 85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) @classmethod 8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) def is_supported(cls, browser_type): 88558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch if sys.platform != 'darwin': 89558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return False 9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if browser_type == 'any': 91558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return True 9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return (not browser_type.startswith('android') and 9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) not browser_type.startswith('cros')) 94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 95a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) def CollectProfile(self): 96558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch output_files = [] 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for single_process in self._process_profilers: 98558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch output_files.append(single_process.CollectProfile()) 99558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch return output_files 100