OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
| 7 import base64 |
7 import gzip | 8 import gzip |
8 import logging | 9 import logging |
9 import optparse | 10 import optparse |
10 import os | 11 import os |
11 import re | 12 import re |
12 import shutil | 13 import shutil |
13 import sys | 14 import sys |
14 import threading | 15 import threading |
15 import time | 16 import time |
| 17 import webbrowser |
16 import zipfile | 18 import zipfile |
17 import zlib | 19 import zlib |
18 | 20 |
19 from pylib import android_commands | 21 from pylib import android_commands |
20 from pylib import cmd_helper | 22 from pylib import cmd_helper |
21 from pylib import constants | 23 from pylib import constants |
22 from pylib import pexpect | 24 from pylib import pexpect |
23 | 25 |
24 | 26 |
| 27 _TRACE_VIEWER_TEMPLATE = """<!DOCTYPE html> |
| 28 <html> |
| 29 <head> |
| 30 <title>%(title)s</title> |
| 31 <style> |
| 32 %(timeline_css)s |
| 33 </style> |
| 34 <style> |
| 35 .view { |
| 36 overflow: hidden; |
| 37 position: absolute; |
| 38 top: 0; |
| 39 bottom: 0; |
| 40 left: 0; |
| 41 right: 0; |
| 42 } |
| 43 </style> |
| 44 <script> |
| 45 %(timeline_js)s |
| 46 </script> |
| 47 <script> |
| 48 document.addEventListener('DOMContentLoaded', function() { |
| 49 var trace_data = window.atob('%(trace_data_base64)s'); |
| 50 var m = new tracing.TraceModel(trace_data); |
| 51 var timelineViewEl = document.querySelector('.view'); |
| 52 ui.decorate(timelineViewEl, tracing.TimelineView); |
| 53 timelineViewEl.model = m; |
| 54 timelineViewEl.tabIndex = 1; |
| 55 timelineViewEl.timeline.focusElement = timelineViewEl; |
| 56 }); |
| 57 </script> |
| 58 </head> |
| 59 <body> |
| 60 <div class="view"></view> |
| 61 </body> |
| 62 </html>""" |
| 63 |
25 _DEFAULT_CHROME_CATEGORIES = '_DEFAULT_CHROME_CATEGORIES' | 64 _DEFAULT_CHROME_CATEGORIES = '_DEFAULT_CHROME_CATEGORIES' |
26 | 65 |
27 | 66 |
28 def _GetTraceTimestamp(): | 67 def _GetTraceTimestamp(): |
29 return time.strftime('%Y-%m-%d-%H%M%S', time.localtime()) | 68 return time.strftime('%Y-%m-%d-%H%M%S', time.localtime()) |
30 | 69 |
31 | 70 |
| 71 def _PackageTraceAsHtml(trace_file_name, html_file_name): |
| 72 trace_viewer_root = os.path.join(constants.DIR_SOURCE_ROOT, |
| 73 'third_party', 'trace-viewer') |
| 74 build_dir = os.path.join(trace_viewer_root, 'build') |
| 75 src_dir = os.path.join(trace_viewer_root, 'src') |
| 76 if not build_dir in sys.path: |
| 77 sys.path.append(build_dir) |
| 78 generate = __import__('generate', {}, {}) |
| 79 parse_deps = __import__('parse_deps', {}, {}) |
| 80 |
| 81 basename = os.path.splitext(trace_file_name)[0] |
| 82 load_sequence = parse_deps.calc_load_sequence( |
| 83 ['tracing/standalone_timeline_view.js'], [src_dir]) |
| 84 |
| 85 with open(trace_file_name) as trace_file: |
| 86 trace_data = base64.b64encode(trace_file.read()) |
| 87 with open(html_file_name, 'w') as html_file: |
| 88 html = _TRACE_VIEWER_TEMPLATE % { |
| 89 'title': os.path.basename(os.path.splitext(trace_file_name)[0]), |
| 90 'timeline_js': generate.generate_js(load_sequence), |
| 91 'timeline_css': generate.generate_css(load_sequence), |
| 92 'trace_data_base64': trace_data |
| 93 } |
| 94 html_file.write(html) |
| 95 |
| 96 |
32 class ChromeTracingController(object): | 97 class ChromeTracingController(object): |
33 def __init__(self, adb, package_info, categories, ring_buffer): | 98 def __init__(self, adb, package_info, categories, ring_buffer): |
34 self._adb = adb | 99 self._adb = adb |
35 self._package_info = package_info | 100 self._package_info = package_info |
36 self._categories = categories | 101 self._categories = categories |
37 self._ring_buffer = ring_buffer | 102 self._ring_buffer = ring_buffer |
38 self._trace_file = None | 103 self._trace_file = None |
39 self._trace_interval = None | 104 self._trace_interval = None |
40 self._trace_start_re = \ | 105 self._trace_start_re = \ |
41 re.compile(r'Logging performance trace to file: (.*)') | 106 re.compile(r'Logging performance trace to file: (.*)') |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 def _StartTracing(controllers, interval): | 266 def _StartTracing(controllers, interval): |
202 for controller in controllers: | 267 for controller in controllers: |
203 controller.StartTracing(interval) | 268 controller.StartTracing(interval) |
204 | 269 |
205 | 270 |
206 def _StopTracing(controllers): | 271 def _StopTracing(controllers): |
207 for controller in controllers: | 272 for controller in controllers: |
208 controller.StopTracing() | 273 controller.StopTracing() |
209 | 274 |
210 | 275 |
211 def _PullTraces(controllers, output, compress): | 276 def _PullTraces(controllers, output, compress, write_html): |
212 _PrintMessage('Downloading...', eol='') | 277 _PrintMessage('Downloading...', eol='') |
213 trace_files = [] | 278 trace_files = [] |
214 for controller in controllers: | 279 for controller in controllers: |
215 trace_files.append(controller.PullTrace()) | 280 trace_files.append(controller.PullTrace()) |
216 | 281 |
217 if compress and len(trace_files) == 1: | 282 if compress and len(trace_files) == 1: |
218 result = output or trace_files[0] + '.gz' | 283 result = output or trace_files[0] + '.gz' |
219 _CompressFile(trace_files[0], result) | 284 _CompressFile(trace_files[0], result) |
220 elif len(trace_files) > 1: | 285 elif len(trace_files) > 1: |
221 result = output or 'chrome-combined-trace-%s.zip' % _GetTraceTimestamp() | 286 result = output or 'chrome-combined-trace-%s.zip' % _GetTraceTimestamp() |
222 _ArchiveFiles(trace_files, result) | 287 _ArchiveFiles(trace_files, result) |
223 elif output: | 288 elif output: |
224 result = output | 289 result = output |
225 shutil.move(trace_files[0], result) | 290 shutil.move(trace_files[0], result) |
226 else: | 291 else: |
227 result = trace_files[0] | 292 result = trace_files[0] |
228 | 293 |
| 294 if write_html: |
| 295 result, trace_file = os.path.splitext(result)[0] + '.html', result |
| 296 _PackageTraceAsHtml(trace_file, result) |
| 297 if trace_file != result: |
| 298 os.unlink(trace_file) |
| 299 |
229 _PrintMessage('done') | 300 _PrintMessage('done') |
230 _PrintMessage('Trace written to %s' % os.path.abspath(result)) | 301 _PrintMessage('Trace written to %s' % os.path.abspath(result)) |
| 302 return result |
231 | 303 |
232 | 304 |
233 def _CaptureAndPullTrace(controllers, interval, output, compress): | 305 def _CaptureAndPullTrace(controllers, interval, output, compress, write_html): |
234 trace_type = ' + '.join(map(str, controllers)) | 306 trace_type = ' + '.join(map(str, controllers)) |
235 try: | 307 try: |
236 _StartTracing(controllers, interval) | 308 _StartTracing(controllers, interval) |
237 if interval: | 309 if interval: |
238 _PrintMessage('Capturing %d-second %s. Press Ctrl-C to stop early...' % \ | 310 _PrintMessage('Capturing %d-second %s. Press Ctrl-C to stop early...' % \ |
239 (interval, trace_type), eol='') | 311 (interval, trace_type), eol='') |
240 time.sleep(interval) | 312 time.sleep(interval) |
241 else: | 313 else: |
242 _PrintMessage('Capturing %s. Press Enter to stop...' % trace_type, eol='') | 314 _PrintMessage('Capturing %s. Press Enter to stop...' % trace_type, eol='') |
243 raw_input() | 315 raw_input() |
244 except KeyboardInterrupt: | 316 except KeyboardInterrupt: |
245 _PrintMessage('\nInterrupted...', eol='') | 317 _PrintMessage('\nInterrupted...', eol='') |
246 finally: | 318 finally: |
247 _StopTracing(controllers) | 319 _StopTracing(controllers) |
248 if interval: | 320 if interval: |
249 _PrintMessage('done') | 321 _PrintMessage('done') |
250 | 322 |
251 _PullTraces(controllers, output, compress) | 323 return _PullTraces(controllers, output, compress, write_html) |
252 | 324 |
253 | 325 |
254 def _ComputeChromeCategories(options): | 326 def _ComputeChromeCategories(options): |
255 categories = [] | 327 categories = [] |
256 if options.trace_cc: | 328 if options.trace_cc: |
257 categories.append('disabled-by-default-cc.debug*') | 329 categories.append('disabled-by-default-cc.debug*') |
258 if options.trace_gpu: | 330 if options.trace_gpu: |
259 categories.append('disabled-by-default-gpu.debug*') | 331 categories.append('disabled-by-default-gpu.debug*') |
260 if options.chrome_categories: | 332 if options.chrome_categories: |
261 categories += options.chrome_categories.split(',') | 333 categories += options.chrome_categories.split(',') |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 'both types of categories. Use "list" to see the ' | 376 'both types of categories. Use "list" to see the ' |
305 'available categories. Systrace is disabled by ' | 377 'available categories. Systrace is disabled by ' |
306 'default.', metavar='SYS_CATEGORIES', | 378 'default.', metavar='SYS_CATEGORIES', |
307 dest='systrace_categories', default='') | 379 dest='systrace_categories', default='') |
308 categories.add_option('--trace-cc', help='Enable extra trace categories for ' | 380 categories.add_option('--trace-cc', help='Enable extra trace categories for ' |
309 'compositor frame viewer data.', action='store_true') | 381 'compositor frame viewer data.', action='store_true') |
310 categories.add_option('--trace-gpu', help='Enable extra trace categories for ' | 382 categories.add_option('--trace-gpu', help='Enable extra trace categories for ' |
311 'GPU data.', action='store_true') | 383 'GPU data.', action='store_true') |
312 parser.add_option_group(categories) | 384 parser.add_option_group(categories) |
313 | 385 |
314 parser.add_option('-o', '--output', help='Save profile output to file.') | 386 output_options = optparse.OptionGroup(parser, 'Output options') |
| 387 output_options.add_option('-o', '--output', help='Save trace output to file.') |
| 388 output_options.add_option('--html', help='Package trace into a standalone ' |
| 389 'html file.', action='store_true') |
| 390 output_options.add_option('--view', help='Open resulting trace file in a ' |
| 391 'browser.', action='store_true') |
| 392 parser.add_option_group(output_options) |
| 393 |
315 browsers = sorted(_GetSupportedBrowsers().keys()) | 394 browsers = sorted(_GetSupportedBrowsers().keys()) |
316 parser.add_option('-b', '--browser', help='Select among installed browsers. ' | 395 parser.add_option('-b', '--browser', help='Select among installed browsers. ' |
317 'One of ' + ', '.join(browsers) + ', "stable" is used by ' | 396 'One of ' + ', '.join(browsers) + ', "stable" is used by ' |
318 'default.', type='choice', choices=browsers, | 397 'default.', type='choice', choices=browsers, |
319 default='stable') | 398 default='stable') |
320 parser.add_option('-v', '--verbose', help='Verbose logging.', | 399 parser.add_option('-v', '--verbose', help='Verbose logging.', |
321 action='store_true') | 400 action='store_true') |
322 parser.add_option('-z', '--compress', help='Compress the resulting trace ' | 401 parser.add_option('-z', '--compress', help='Compress the resulting trace ' |
323 'with gzip. ', action='store_true') | 402 'with gzip. ', action='store_true') |
324 options, args = parser.parse_args() | 403 options, args = parser.parse_args() |
(...skipping 26 matching lines...) Expand all Loading... |
351 options.ring_buffer)) | 430 options.ring_buffer)) |
352 if systrace_categories: | 431 if systrace_categories: |
353 controllers.append(SystraceController(adb, | 432 controllers.append(SystraceController(adb, |
354 systrace_categories, | 433 systrace_categories, |
355 options.ring_buffer)) | 434 options.ring_buffer)) |
356 | 435 |
357 if not controllers: | 436 if not controllers: |
358 _PrintMessage('No trace categories enabled.') | 437 _PrintMessage('No trace categories enabled.') |
359 return 1 | 438 return 1 |
360 | 439 |
361 _CaptureAndPullTrace(controllers, | 440 result = _CaptureAndPullTrace(controllers, |
362 options.time if not options.continuous else 0, | 441 options.time if not options.continuous else 0, |
363 options.output, | 442 options.output, |
364 options.compress) | 443 options.compress, |
| 444 options.html) |
| 445 if options.view: |
| 446 webbrowser.open(result) |
365 | 447 |
366 | 448 |
367 if __name__ == '__main__': | 449 if __name__ == '__main__': |
368 sys.exit(main()) | 450 sys.exit(main()) |
OLD | NEW |