Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: build/android/chrome_profiler/perf_controller.py

Issue 293193002: adb_profile_chrome: Add perf profiler (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Implemented trace merging. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
5 import logging
6 import os
7 import subprocess
8 import sys
9 import tempfile
10
11 from chrome_profiler import controllers
12
13 from pylib import android_commands
14 from pylib import constants
15
16 sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT,
17 'tools',
18 'telemetry'))
19 try:
20 # pylint: disable=F0401
21 from telemetry.core.platform.profiler import android_profiling_helper
22 from telemetry.util import support_binaries
23 except ImportError:
24 android_profiling_helper = None
25 support_binaries = None
26
27
28 _PERF_OPTIONS = [
29 '--all-cpus',
30 '--call-graph',
31 '--realtime', '80',
32 '--raw-samples',
33 '--freq', '2000',
34 ]
35
36
37 class _PerfProfilerInstance(object):
bulach 2014/06/04 10:34:12 nit: how about just _PerfProfiler? or _PerfProfile
Sami 2014/06/04 15:16:59 _PerfProfiler sgtm.
38 def __init__(self, device, perf_binary, categories):
39 self._device = device
40 self._output_file = android_commands.DeviceTempFile(
41 self._device.old_interface, prefix='perf_output')
42 self._log_file = tempfile.TemporaryFile()
43
44 device_param = (['-s', self._device.old_interface.GetDevice()]
45 if self._device.old_interface.GetDevice() else [])
46 cmd = ['adb'] + device_param + \
47 ['shell', perf_binary, 'record',
48 '--output', self._output_file.name] + _PERF_OPTIONS
49 if categories:
50 cmd += ['--event', ','.join(categories)]
51 self._perf_process = subprocess.Popen(cmd,
52 stdout=self._log_file,
53 stderr=subprocess.STDOUT)
54
55 def SignalAndWait(self):
56 perf_pids = self._device.old_interface.ExtractPid('perf')
57 self._device.old_interface.RunShellCommand(
58 'kill -SIGINT ' + ' '.join(perf_pids))
59 self._perf_process.wait()
60
61 def _FailWithLog(self, msg):
62 self._log_file.seek(0)
63 log = self._log_file.read()
64 raise RuntimeError('%s. Log output:\n%s' % (msg, log))
65
66 def PullResult(self, output_path):
67 if not self._device.old_interface.FileExistsOnDevice(
68 self._output_file.name):
69 self._FailWithLog('Perf recorded no data')
70
71 perf_profile = os.path.join(output_path,
72 os.path.basename(self._output_file.name))
73 self._device.old_interface.PullFileFromDevice(self._output_file.name,
74 perf_profile)
75 if not os.stat(perf_profile).st_size:
76 os.remove(perf_profile)
77 self._FailWithLog('Perf recorded a zero-sized file')
78
79 self._log_file.close()
80 self._output_file.close()
81 return perf_profile
82
83
84 class PerfProfilerController(controllers.BaseController):
85 def __init__(self, device, categories):
86 controllers.BaseController.__init__(self)
87 self._device = device
88 self._categories = categories
89 self._perf_binary = self._PrepareDevice(device)
90 self._perf_instance = None
91
92 def __repr__(self):
93 return 'perf profile'
94
95 @staticmethod
96 def IsSupported():
97 return bool(android_profiling_helper)
98
99 @staticmethod
100 def _PrepareDevice(device):
101 if not 'BUILDTYPE' in os.environ:
102 os.environ['BUILDTYPE'] = 'Release'
103 return android_profiling_helper.PrepareDeviceForPerf(device)
104
105 @classmethod
106 def GetCategories(cls, device):
107 perf_binary = cls._PrepareDevice(device)
108 return device.old_interface.RunShellCommand('%s list' % perf_binary)
109
110 def StartTracing(self, _):
111 self._perf_instance = _PerfProfilerInstance(self._device,
112 self._perf_binary,
113 self._categories)
114
115 def StopTracing(self):
116 if not self._perf_instance:
117 return
118 self._perf_instance.SignalAndWait()
119
120 def PullTrace(self):
121 symfs_dir = os.path.join(tempfile.gettempdir(),
122 os.path.expandvars('$USER-perf-symfs'))
123 if not os.path.exists(symfs_dir):
124 os.makedirs(symfs_dir)
125 required_libs = set()
126
127 # Download the recorded perf profile.
128 perf_profile = self._perf_instance.PullResult(symfs_dir)
129 required_libs = \
130 android_profiling_helper.GetRequiredLibrariesForPerfProfile(
131 perf_profile)
132 if not required_libs:
133 logging.warning('No libraries required by perf trace. Most likely there '
134 'are no samples in the trace.')
135
136 # Build a symfs with all the necessary libraries.
137 kallsyms = android_profiling_helper.CreateSymFs(self._device,
138 symfs_dir,
139 required_libs,
140 use_symlinks=False)
141 # Convert the perf profile into JSON.
142 perfhost_path = \
bulach 2014/06/04 10:34:12 nit: avoid \, something like: perfhost_path = os.
Sami 2014/06/04 15:16:59 Well spotted, done. I just got used to having long
143 os.path.abspath(support_binaries.FindPath('perfhost', 'linux'))
144 perf_script_path = \
bulach 2014/06/04 10:34:12 ditto..
Sami 2014/06/04 15:16:59 Done.
145 os.path.join(constants.DIR_SOURCE_ROOT,
146 'tools', 'telemetry', 'telemetry', 'core', 'platform',
147 'profiler', 'perf_vis', 'perf_to_tracing.py')
148 json_file_name = os.path.basename(perf_profile)
149 with open(os.devnull, 'w') as dev_null:
150 with open(json_file_name, 'w') as json_file:
bulach 2014/06/04 10:34:12 nit: I think we're on python2.7 everywhere, so mul
Sami 2014/06/04 15:16:59 Oh thanks, I forgot about that syntax!
151 cmd = [perfhost_path, 'script', '-s', perf_script_path,
152 '-i', perf_profile, '--symfs', symfs_dir, '--kallsyms',
153 kallsyms]
154 subprocess.call(cmd, stdout=json_file, stderr=dev_null)
155 return json_file_name
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698