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

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: Rebased. 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 os
6 import subprocess
7 import sys
8 import tempfile
9
10 from chrome_profiler import controllers
11
12 from pylib import android_commands
13 from pylib import constants
14
15 sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT,
16 'tools',
17 'telemetry'))
18 # pylint: disable=F0401
19 from telemetry.core.platform.profiler import android_profiling_helper
20 from telemetry.util import support_binaries
21
22
23 _PERF_OPTIONS = [
24 '--all-cpus',
25 '--call-graph',
26 '--realtime', '80',
27 '--raw-samples',
28 '--freq', '2000',
29 ]
30
31
32 class _PerfProfilerInstance(object):
33 def __init__(self, device, perf_binary, categories):
34 self._device = device
35 self._output_file = android_commands.DeviceTempFile(
36 self._device.old_interface, prefix='perf_output')
37 self._log_file = tempfile.TemporaryFile()
38
39 device_param = (['-s', self._device.old_interface.GetDevice()]
40 if self._device.old_interface.GetDevice() else [])
41 cmd = ['adb'] + device_param + \
42 ['shell', perf_binary, 'record',
43 '--output', self._output_file.name] + _PERF_OPTIONS
44 if categories:
45 cmd += ['--event', ','.join(categories)]
46 self._perf_process = subprocess.Popen(cmd,
47 stdout=self._log_file,
48 stderr=subprocess.STDOUT)
49
50 def Wait(self):
51 self._perf_process.wait()
52
53 def _FailWithLog(self, msg):
54 self._log_file.seek(0)
55 log = self._log_file.read()
56 raise RuntimeError('%s. Log output:\n%s' % (msg, log))
57
58 def PullResult(self, output_path):
59 if not self._device.old_interface.FileExistsOnDevice(
60 self._output_file.name):
61 self._FailWithLog('Perf recorded no data')
62
63 perf_profile = os.path.join(output_path,
64 os.path.basename(self._output_file.name))
65 self._device.old_interface.PullFileFromDevice(self._output_file.name,
66 perf_profile)
67 if not os.stat(perf_profile).st_size:
68 os.remove(perf_profile)
69 self._FailWithLog('Perf recorded a zero-sized file')
Dominik Grewe 2014/05/28 17:09:43 Can we also somehow check if there are any samples
Sami 2014/06/02 17:56:38 Great point, we should complain if the perf trace
70
71 self._log_file.close()
72 self._output_file.close()
73 return perf_profile
74
75
76 class PerfProfilerController(controllers.BaseController):
77 def __init__(self, device, categories):
78 controllers.BaseController.__init__(self)
79 self._device = device
80 self._categories = categories
81 self._perf_binary = self._PrepareDevice(device)
82 self._perf_instance = None
83
84 def __repr__(self):
85 return 'perf profile'
86
87 @staticmethod
88 def _PrepareDevice(device):
89 if not 'BUILDTYPE' in os.environ:
90 os.environ['BUILDTYPE'] = 'Release'
91 return android_profiling_helper.PrepareDeviceForPerf(device)
92
93 @classmethod
94 def GetCategories(cls, device):
95 perf_binary = cls._PrepareDevice(device)
96 return device.old_interface.RunShellCommand('%s list' % perf_binary)
97
98 def StartTracing(self, _):
99 self._perf_instance = _PerfProfilerInstance(self._device,
100 self._perf_binary,
101 self._categories)
102
103 def StopTracing(self):
104 if not self._perf_instance:
105 return
106 perf_pids = self._device.old_interface.ExtractPid('perf')
Dominik Grewe 2014/05/28 17:09:43 Why not ask the perf profiler instance directly fo
Sami 2014/06/02 17:56:38 Good idea, that's much cleaner.
107 self._device.old_interface.RunShellCommand(
108 'kill -SIGINT ' + ' '.join(perf_pids))
109 self._perf_instance.Wait()
110
111 def PullTrace(self):
112 symfs_dir = os.path.join(tempfile.gettempdir(),
113 os.path.expandvars('$USER-perf-symfs'))
114 if not os.path.exists(symfs_dir):
115 os.makedirs(symfs_dir)
116 required_libs = set()
117
118 # Download the recorded perf profile.
119 perf_profile = self._perf_instance.PullResult(symfs_dir)
120 required_libs = \
121 android_profiling_helper.GetRequiredLibrariesForPerfProfile(
122 perf_profile)
123
124 # Build a symfs with all the necessary libraries.
125 kallsyms = android_profiling_helper.CreateSymFs(self._device,
126 symfs_dir,
127 required_libs,
128 use_symlinks=False)
129 # Convert the perf profile into JSON.
130 perfhost_path = \
131 os.path.abspath(support_binaries.FindPath('perfhost', 'linux'))
132 perf_script_path = \
133 os.path.join(constants.DIR_SOURCE_ROOT,
134 'tools', 'telemetry', 'telemetry', 'core', 'platform',
135 'profiler', 'perf_vis', 'perf_to_tracing.py')
136 json_file_name = os.path.basename(perf_profile)
137 with open(json_file_name, 'w') as json_file:
138 cmd = [perfhost_path, 'script', '-s', perf_script_path,
139 '-i', perf_profile, '--symfs', symfs_dir, '--kallsyms',
140 kallsyms]
141 subprocess.call(cmd, stdout=json_file)
142 return json_file_name
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698