1 # Copyright 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.
9 from telemetry.core import exceptions
10 from telemetry.core import util
11 from telemetry.core.platform import profiler
13 # pexpect is not available on all platforms so use the third_party version.
14 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'third_party', 'pexpect')
16 import pexpect # pylint: disable=F0401
21 class _SingleProcessIprofilerProfiler(object):
22 """An internal class for using iprofiler for a given process."""
23 def __init__(self, pid, output_path):
24 self._output_path = output_path
25 output_dir = os.path.dirname(self._output_path)
26 output_file = os.path.basename(self._output_path)
27 self._proc = pexpect.spawn(
28 'iprofiler', ['-timeprofiler', '-T', '300', '-a', str(pid),
29 '-d', output_dir, '-o', output_file],
32 if self._proc.getecho():
33 output = self._proc.readline().strip()
36 if 'iprofiler: Profiling process' in output:
39 self._proc.interact(escape_character='\x0d')
40 if 'Failed to authorize rights' in output:
41 raise exceptions.ProfilingException(
42 'Failed to authorize rights for iprofiler\n')
43 if 'iprofiler error' in output:
44 raise exceptions.ProfilingException(
45 'Failed to start iprofiler for process %s\n' %
46 self._output_path.split('.')[1])
47 self._proc.write('\x0d')
50 return self._proc.getecho()
51 util.WaitFor(Echo, timeout=5)
53 def CollectProfile(self):
54 self._proc.kill(signal.SIGINT)
57 except pexpect.ExceptionPexpect:
62 print 'To view the profile, run:'
63 print ' open -a Instruments %s.dtps' % self._output_path
64 return self._output_path
67 class IprofilerProfiler(profiler.Profiler):
69 def __init__(self, browser_backend, platform_backend, output_path, state):
70 super(IprofilerProfiler, self).__init__(
71 browser_backend, platform_backend, output_path, state)
72 process_output_file_map = self._GetProcessOutputFileMap()
73 self._process_profilers = []
74 for pid, output_file in process_output_file_map.iteritems():
75 if '.utility' in output_file:
76 # The utility process may not have been started by Telemetry.
77 # So we won't have permissing to profile it
79 self._process_profilers.append(
80 _SingleProcessIprofilerProfiler(pid, output_file))
87 def is_supported(cls, browser_type):
88 if sys.platform != 'darwin':
90 if browser_type == 'any':
92 return (not browser_type.startswith('android') and
93 not browser_type.startswith('cros'))
95 def CollectProfile(self):
97 for single_process in self._process_profilers:
98 output_files.append(single_process.CollectProfile())