- add sources.
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / platform / profiler / sample_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 signal
6 import subprocess
7 import sys
8 import tempfile
9
10 from telemetry.core import exceptions
11 from telemetry.core import util
12 from telemetry.core.platform import profiler
13
14
15 class _SingleProcessSampleProfiler(object):
16   """An internal class for using iprofiler for a given process."""
17   def __init__(self, pid, output_path):
18     self._output_path = output_path
19     self._tmp_output_file = tempfile.NamedTemporaryFile('w', 0)
20     self._proc = subprocess.Popen(
21         ['sample', str(pid), '-mayDie', '-file', self._output_path],
22         stdout=self._tmp_output_file, stderr=subprocess.STDOUT)
23     def IsStarted():
24       stdout = self._GetStdOut()
25       if 'sample cannot examine process' in stdout:
26         raise exceptions.ProfilingException(
27             'Failed to start sample for process %s\n' %
28             self._output_path.split('.')[1])
29       return 'Sampling process' in stdout
30     util.WaitFor(IsStarted, 120)
31
32   def CollectProfile(self):
33     self._proc.send_signal(signal.SIGINT)
34     exit_code = self._proc.wait()
35     try:
36       if exit_code:
37         raise Exception(
38             'sample failed with exit code %d. Output:\n%s' % (
39             exit_code, self._GetStdOut()))
40     finally:
41       self._proc = None
42       self._tmp_output_file.close()
43
44     print 'To view the profile, run:'
45     print '  open -a TextEdit %s' % self._output_path
46
47     return self._output_path
48
49   def _GetStdOut(self):
50     self._tmp_output_file.flush()
51     try:
52       with open(self._tmp_output_file.name) as f:
53         return f.read()
54     except IOError:
55       return ''
56
57
58 class SampleProfiler(profiler.Profiler):
59
60   def __init__(self, browser_backend, platform_backend, output_path, state):
61     super(SampleProfiler, self).__init__(
62         browser_backend, platform_backend, output_path, state)
63     process_output_file_map = self._GetProcessOutputFileMap()
64     self._process_profilers = []
65     for pid, output_file in process_output_file_map.iteritems():
66       if '.utility' in output_file:
67         # The utility process may not have been started by Telemetry.
68         # So we won't have permissing to profile it
69         continue
70       self._process_profilers.append(
71           _SingleProcessSampleProfiler(pid, output_file))
72
73   @classmethod
74   def name(cls):
75     return 'sample'
76
77   @classmethod
78   def is_supported(cls, browser_type):
79     if sys.platform != 'darwin':
80       return False
81     if browser_type == 'any':
82       return True
83     return (not browser_type.startswith('android') and
84             not browser_type.startswith('cros'))
85
86   def CollectProfile(self):
87     output_paths = []
88     for single_process in self._process_profilers:
89       output_paths.append(single_process.CollectProfile())
90     return output_paths