| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import datetime | 5 import datetime |
| 6 import json | |
| 7 import logging | 6 import logging |
| 8 import os | 7 import os |
| 9 import random | 8 import random |
| 10 import shutil | 9 import shutil |
| 11 import subprocess | |
| 12 import sys | 10 import sys |
| 13 import tempfile | 11 import tempfile |
| 14 | 12 |
| 15 from py_utils import cloud_storage # pylint: disable=import-error | 13 from py_utils import cloud_storage # pylint: disable=import-error |
| 16 | 14 |
| 17 from telemetry.internal.util import file_handle | 15 from telemetry.internal.util import file_handle |
| 18 from telemetry.timeline import trace_data as trace_data_module | 16 from telemetry.timeline import trace_data as trace_data_module |
| 19 from telemetry import value as value_module | 17 from telemetry import value as value_module |
| 20 | 18 |
| 21 _TRACE2HTML_PATH = os.path.join(os.path.dirname(__file__), '..', '..', '..', | |
| 22 'tracing', 'bin', 'trace2html') | |
| 23 | |
| 24 | 19 |
| 25 class TraceValue(value_module.Value): | 20 class TraceValue(value_module.Value): |
| 26 def __init__(self, page, trace_data, important=False, description=None): | 21 def __init__(self, page, trace_data, important=False, description=None): |
| 27 """A value that contains a TraceData object and knows how to | 22 """A value that contains a TraceData object and knows how to |
| 28 output it. | 23 output it. |
| 29 | 24 |
| 30 Adding TraceValues and outputting as JSON will produce a directory full of | 25 Adding TraceValues and outputting as JSON will produce a directory full of |
| 31 HTML files called trace_files. Outputting as chart JSON will also produce | 26 HTML files called trace_files. Outputting as chart JSON will also produce |
| 32 an index, files.html, linking to each of these files. | 27 an index, files.html, linking to each of these files. |
| 33 """ | 28 """ |
| 34 super(TraceValue, self).__init__( | 29 super(TraceValue, self).__init__( |
| 35 page, name='trace', units='', important=important, | 30 page, name='trace', units='', important=important, |
| 36 description=description, tir_label=None, grouping_keys=None) | 31 description=description, tir_label=None, grouping_keys=None) |
| 37 self._temp_file = self._GetTempFileHandle(trace_data) | 32 self._temp_file = self._GetTempFileHandle(trace_data) |
| 38 self._cloud_url = None | 33 self._cloud_url = None |
| 39 self._serialized_file_handle = None | 34 self._serialized_file_handle = None |
| 40 | 35 |
| 41 @property | 36 @property |
| 42 def value(self): | 37 def value(self): |
| 43 if self._cloud_url: | 38 if self._cloud_url: |
| 44 return self._cloud_url | 39 return self._cloud_url |
| 45 elif self._serialized_file_handle: | 40 elif self._serialized_file_handle: |
| 46 return self._serialized_file_handle.GetAbsPath() | 41 return self._serialized_file_handle.GetAbsPath() |
| 47 | 42 |
| 48 def _GetTraceParts(self, trace_data): | 43 def _GetTraceParts(self, trace_data): |
| 49 return [(trace_data.GetTracesFor(p), p) | 44 return [(trace_data.GetTracesFor(p), p) |
| 50 for p in trace_data_module.ALL_TRACE_PARTS | 45 for p in trace_data_module.ALL_TRACE_PARTS |
| 51 if trace_data.HasTracesFor(p)] | 46 if trace_data.HasTracesFor(p)] |
| 52 | 47 |
| 53 @staticmethod | |
| 54 def _DumpTraceToFile(trace, path): | |
| 55 with open(path, 'w') as fp: | |
| 56 if isinstance(trace, basestring): | |
| 57 fp.write(trace) | |
| 58 elif isinstance(trace, dict) or isinstance(trace, list): | |
| 59 json.dump(trace, fp) | |
| 60 else: | |
| 61 raise TypeError('Trace is of unknown type.') | |
| 62 | |
| 63 def _GetTempFileHandle(self, trace_data): | 48 def _GetTempFileHandle(self, trace_data): |
| 64 temp_dir = tempfile.mkdtemp() | 49 tf = tempfile.NamedTemporaryFile(delete=False, suffix='.html') |
| 65 trace_files = [] | 50 tf.close() |
| 66 counter = 0 | 51 title = '' |
| 67 try: | 52 if self.page: |
| 68 trace_size_data = {} | 53 title = self.page.display_name |
| 69 for traces_list, part in self._GetTraceParts(trace_data): | 54 trace_data.Serialize(tf.name, trace_title=title) |
| 70 for trace in traces_list: | 55 return file_handle.FromFilePath(tf.name) |
| 71 if isinstance(trace, trace_data_module.TraceFileHandle): | |
| 72 file_path = trace.file_path | |
| 73 else: | |
| 74 file_path = os.path.join(temp_dir, '%s.trace' % counter) | |
| 75 self._DumpTraceToFile(trace, file_path) | |
| 76 trace_size_data.setdefault(part, 0) | |
| 77 trace_size_data[part] += os.path.getsize(file_path) | |
| 78 trace_files.append(file_path) | |
| 79 counter += 1 | |
| 80 logging.info('Trace sizes in bytes: %s', trace_size_data) | |
| 81 tf = tempfile.NamedTemporaryFile(delete=False, suffix='.html') | |
| 82 tf.close() | |
| 83 if trace_files: | |
| 84 title = '' | |
| 85 if self.page: | |
| 86 title = self.page.display_name | |
| 87 cmd = (['python', _TRACE2HTML_PATH] + trace_files + | |
| 88 ['--output', tf.name] + ['--title', title]) | |
| 89 subprocess.check_output(cmd) | |
| 90 else: | |
| 91 logging.warning('No traces to convert to html.') | |
| 92 return file_handle.FromTempFile(tf) | |
| 93 finally: | |
| 94 shutil.rmtree(temp_dir) | |
| 95 | 56 |
| 96 def __repr__(self): | 57 def __repr__(self): |
| 97 if self.page: | 58 if self.page: |
| 98 page_name = self.page.display_name | 59 page_name = self.page.display_name |
| 99 else: | 60 else: |
| 100 page_name = 'None' | 61 page_name = 'None' |
| 101 return 'TraceValue(%s, %s)' % (page_name, self.name) | 62 return 'TraceValue(%s, %s)' % (page_name, self.name) |
| 102 | 63 |
| 103 def CleanUp(self): | 64 def CleanUp(self): |
| 104 """Cleans up tempfile after it is no longer needed. | 65 """Cleans up tempfile after it is no longer needed. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 fh.extension)) | 151 fh.extension)) |
| 191 self._cloud_url = cloud_storage.Insert( | 152 self._cloud_url = cloud_storage.Insert( |
| 192 bucket, remote_path, fh.GetAbsPath()) | 153 bucket, remote_path, fh.GetAbsPath()) |
| 193 sys.stderr.write( | 154 sys.stderr.write( |
| 194 'View generated trace files online at %s for page %s\n' % | 155 'View generated trace files online at %s for page %s\n' % |
| 195 (self._cloud_url, self.page.url if self.page else 'unknown')) | 156 (self._cloud_url, self.page.url if self.page else 'unknown')) |
| 196 return self._cloud_url | 157 return self._cloud_url |
| 197 except cloud_storage.PermissionError as e: | 158 except cloud_storage.PermissionError as e: |
| 198 logging.error('Cannot upload trace files to cloud storage due to ' | 159 logging.error('Cannot upload trace files to cloud storage due to ' |
| 199 ' permission error: %s' % e.message) | 160 ' permission error: %s' % e.message) |
| OLD | NEW |