| 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 |