- add sources.
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / platform / profiler / iprofiler_profiler.py
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
5 import os
6 import signal
7 import sys
8
9 from telemetry.core import exceptions
10 from telemetry.core import util
11 from telemetry.core.platform import profiler
12
13 # pexpect is not available on all platforms so use the third_party version.
14 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'third_party', 'pexpect')
15 try:
16   import pexpect  # pylint: disable=F0401
17 except ImportError:
18   pass
19
20
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],
30         timeout=300)
31     while True:
32       if self._proc.getecho():
33         output = self._proc.readline().strip()
34         if not output:
35           continue
36         if 'iprofiler: Profiling process' in output:
37           break
38         print 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')
48       print
49       def Echo():
50         return self._proc.getecho()
51       util.WaitFor(Echo, timeout=5)
52
53   def CollectProfile(self):
54     self._proc.kill(signal.SIGINT)
55     try:
56       self._proc.wait()
57     except pexpect.ExceptionPexpect:
58       pass
59     finally:
60       self._proc = None
61
62     print 'To view the profile, run:'
63     print '  open -a Instruments %s.dtps' % self._output_path
64     return self._output_path
65
66
67 class IprofilerProfiler(profiler.Profiler):
68
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
78         continue
79       self._process_profilers.append(
80           _SingleProcessIprofilerProfiler(pid, output_file))
81
82   @classmethod
83   def name(cls):
84     return 'iprofiler'
85
86   @classmethod
87   def is_supported(cls, browser_type):
88     if sys.platform != 'darwin':
89       return False
90     if browser_type == 'any':
91       return True
92     return (not browser_type.startswith('android') and
93             not browser_type.startswith('cros'))
94
95   def CollectProfile(self):
96     output_files = []
97     for single_process in self._process_profilers:
98       output_files.append(single_process.CollectProfile())
99     return output_files