def WriteTraceViewer(output_file, config_name=None, minify=False, report_sizes=False, report_deps=False, output_html_head_and_body=True, extra_search_paths=None, extra_module_names_to_load=None): project = tracing_project.TracingProject() if extra_search_paths: for p in extra_search_paths: project.source_paths.append(p) if config_name is None: config_name = project.GetDefaultConfigName() module_names = [project.GetModuleNameForConfigName(config_name)] if extra_module_names_to_load: module_names += extra_module_names_to_load vulcanizer = project.CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames(module_names) if report_deps: sys.stdout.write(vulcanizer.GetDepsGraphFromModuleNames(module_names)) generate.GenerateStandaloneHTMLToFile( output_file, load_sequence, minify=minify, report_sizes=report_sizes, output_html_head_and_body=output_html_head_and_body)
def Main(argv): parser = optparse.OptionParser( usage="%prog <options> trace_file1 [trace_file2 ...]", epilog="""Takes the provided trace file and produces a standalone html file that contains both the trace and the trace viewer.""") project = tracing_project.TracingProject() project.AddConfigNameOptionToParser(parser) parser.add_option( "--output", dest="output", help='Where to put the generated result. If not ' + 'given, the trace filename is used, with an html suffix.') parser.add_option( "--quiet", action='store_true', help='Dont print the output file name') options, args = parser.parse_args(argv[1:]) if len(args) == 0: parser.error('At least one trace file required') if options.output: output_filename = options.output elif len(args) > 1: parser.error('Must specify --output if >1 trace file') else: namepart = os.path.splitext(args[0])[0] output_filename = namepart + '.html' with codecs.open(output_filename, mode='w', encoding='utf-8') as f: WriteHTMLForTracesToFile(args, f, config_name=options.config_name) if not options.quiet: print output_filename return 0
def Main(argv): parser = argparse.ArgumentParser( usage='%(prog)s <options> trace_file1 [trace_file2 ...]', epilog='Takes the provided trace file and produces a standalone HTML\n' 'file that contains both the trace and the trace viewer.') project = tracing_project.TracingProject() project.AddConfigNameOptionToParser(parser) parser.add_argument( '--output', dest='output', help='Where to put the generated result. If not ' 'given, the trace filename is used, with an html suffix.') parser.add_argument( '--quiet', action='store_true', help='Dont print the output file name') parser.add_argument('trace_files', nargs='+') args = parser.parse_args(argv[1:]) if args.output: output_filename = args.output elif len(args.trace_files) > 1: parser.error('Must specify --output if there are multiple trace files.') else: name_part = os.path.splitext(args.trace_files[0])[0] output_filename = name_part + '.html' with codecs.open(output_filename, mode='w', encoding='utf-8') as f: WriteHTMLForTracesToFile(args.trace_files, f, config_name=args.config_name) if not args.quiet: print output_filename return 0
def Format(self, page_test_results): self._values.extend(page_test_results.value_set) vulcanizer = tracing_project.TracingProject().CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames( ['tracing.results2_template']) html = generate.GenerateStandaloneHTMLAsString(load_sequence) html = html.replace(self._JSON_TAG % '', self._JSON_TAG % json.dumps( self._values, separators=(',', ':'))) self._output_stream.seek(0) self._output_stream.write(html) self._output_stream.truncate() file_path = os.path.abspath(self._output_stream.name) if self._upload_results: remote_path = ('html-results/results-%s' % datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')) try: cloud_storage.Insert( cloud_storage.PUBLIC_BUCKET, remote_path, file_path) print 'View online at', print 'http://storage.googleapis.com/chromium-telemetry/' + remote_path except cloud_storage.PermissionError as e: logging.error('Cannot upload profiling files to cloud storage due ' + 'to permission error: ' + e.message) print 'View result at file://' + file_path
def WriteHTMLForTraceDataToFile(trace_data_list, title, output_file, config_name=None): project = tracing_project.TracingProject() if config_name is None: config_name = project.GetDefaultConfigName() modules = [ 'tracing.trace2html', project.GetModuleNameForConfigName(config_name), ] vulcanizer = project.CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames(modules) scripts = [] for trace_data in trace_data_list: # If the object was previously decoded from valid JSON data (e.g., in # WriteHTMLForTracesToFile), it will be a JSON object at this point and we # should re-serialize it into a string. Other types of data will be already # be strings. if not isinstance(trace_data, basestring): trace_data = json.dumps(trace_data) mime_type = 'application/json' else: mime_type = 'text/plain' scripts.append(ViewerDataScript(trace_data, mime_type)) generate.GenerateStandaloneHTMLToFile(output_file, load_sequence, title, extra_scripts=scripts)
def CompareSamples(sample_a, sample_b, metric, data_format='chartjson'): """Compare the values of a metric from two samples from benchmark output. Args: sample_a, sample_b (str): comma-separated lists of paths to the benchmark output. metric (str): Metric name in slash-separated format [2 or 3 part]. data_format (str): The format the samples are in. Supported values are: 'chartjson', 'valueset', 'buildbot'. Returns: JSON encoded dict with the values parsed form the samples and the result of the hypothesis testing comparison of the samples under the 'result' key. Possible values for the result key are: 'NEED_MORE_DATA', 'REJECT' and 'FAIL_TO_REJECT'. Where the null hypothesis is that the samples belong to the same population. i.e. a 'REJECT' result would make it reasonable to conclude that there is a significant difference between the samples. (e.g. a perf regression). """ method = FORMAT_TO_METHOD[data_format] project = tracing_project.TracingProject() all_source_paths = list(project.source_paths) def MakeAbsPaths(l): return ','.join(map(os.path.abspath, l.split(','))) return vinn.RunFile(_COMPARE_SAMPLES_CMD_LINE, source_paths=all_source_paths, js_args=[ method, MakeAbsPaths(sample_a), MakeAbsPaths(sample_b), metric ])
def MapSingleTrace(trace_handle, job, extra_import_options=None): assert (type(extra_import_options) is types.NoneType or type(extra_import_options) is types.DictType), ( 'extra_import_options should be a dict or None.') project = tracing_project.TracingProject() all_source_paths = list(project.source_paths) all_source_paths.append(project.trace_processor_root_path) result = mre_result.MreResult() with trace_handle.PrepareFileForProcessing() as prepared_trace_handle: js_args = [ json.dumps(prepared_trace_handle.AsDict()), json.dumps(job.AsDict()), ] if extra_import_options: js_args.append(json.dumps(extra_import_options)) res = vinn.RunFile( _MAP_SINGLE_TRACE_CMDLINE_PATH, source_paths=all_source_paths, js_args=js_args, # Use 8gb heap space to make sure we don't OOM'ed on big trace. v8_args=['--max-old-space-size=8192']) if res.returncode != 0: sys.stderr.write(res.stdout) result.AddFailure( failure.Failure(job, trace_handle.canonical_url, 'Error', 'vinn runtime error while mapping trace.', 'vinn runtime error while mapping trace.', 'Unknown stack')) return result for line in res.stdout.split('\n'): m = re.match('^MRE_RESULT: (.+)', line, re.DOTALL) if m: found_dict = json.loads(m.group(1)) failures = [ failure.Failure.FromDict(f, job, _FAILURE_NAME_TO_FAILURE_CONSTRUCTOR) for f in found_dict['failures'] ] for f in failures: result.AddFailure(f) for k, v in found_dict['pairs'].iteritems(): result.AddPair(k, v) else: if len(line) > 0: sys.stderr.write(line) sys.stderr.write('\n') if not (len(result.pairs) or len(result.failures)): raise InternalMapError('Internal error: No results were produced!') return result
def VulcanizeHistogramsViewer(): """Vulcanizes Histograms viewer with its dependencies. Args: path: destination to write the vulcanized viewer HTML. """ vulcanizer = tracing_project.TracingProject().CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames( ['tracing_build.histograms_viewer']) return generate.GenerateStandaloneHTMLAsString(load_sequence)
def GetKnownFiles(): project = tracing_project.TracingProject() vulcanizer = project.CreateVulcanizer() m = vulcanizer.loader.LoadModule( module_name='tracing.ui.extras.about_tracing.about_tracing') absolute_filenames = m.GetAllDependentFilenamesRecursive( include_raw_scripts=False) return list(set([os.path.relpath(f, project.tracing_root_path) for f in absolute_filenames]))
def get(self, *args, **kwargs): # pylint: disable=unused-argument project = tracing_project.TracingProject() test_relpaths = [ '/' + _RelPathToUnixPath(x) for x in project.FindAllTestModuleRelPaths() ] tests = {'test_relpaths': test_relpaths} tests_as_json = json.dumps(tests) self.response.content_type = 'application/json' return self.response.write(tests_as_json)
def RenderHTMLView(values, output_stream, reset_results=False): if not reset_results: values += ReadExistingResults(output_stream) vulcanizer = tracing_project.TracingProject().CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames( ['tracing.results2_template']) html = generate.GenerateStandaloneHTMLAsString(load_sequence) html = html.replace(_JSON_TAG % '', _JSON_TAG % json.dumps(values, separators=(',', ':'))) output_stream.seek(0) output_stream.write(html) output_stream.truncate()
def Main(args): parser = argparse.ArgumentParser(usage='%(prog)s --outdir=<directory>') parser.add_argument('--outdir', dest='out_dir', help='Where to place generated content') parser.add_argument('--no-min', default=False, action='store_true', help='Skip minification') args = parser.parse_args(args) if not args.out_dir: sys.stderr.write('ERROR: Must specify --outdir=<directory>') parser.print_help() return 1 names = ['tracing.ui.extras.about_tracing.about_tracing'] project = tracing_project.TracingProject() vulcanizer = project.CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames(names) olddir = os.getcwd() try: if not os.path.exists(args.out_dir): os.makedirs(args.out_dir) o = codecs.open(os.path.join(args.out_dir, 'about_tracing.html'), 'w', encoding='utf-8') try: py_vulcanize.GenerateStandaloneHTMLToFile( o, load_sequence, title='chrome://tracing', flattened_js_url='tracing.js', minify=not args.no_min) except py_vulcanize.module.DepsException as ex: sys.stderr.write('Error: %s\n\n' % str(ex)) return 255 o.close() o = codecs.open(os.path.join(args.out_dir, 'about_tracing.js'), 'w', encoding='utf-8') assert o.encoding == 'utf-8' py_vulcanize.GenerateJSToFile( o, load_sequence, use_include_tags_for_scripts=False, dir_for_include_tag_root=args.out_dir, minify=not args.no_min) o.close() finally: os.chdir(olddir) return 0
def Main(args): parser = optparse.OptionParser(usage="%prog --outdir=<directory>") parser.add_option("--outdir", dest="out_dir", help="Where to place generated content") parser.add_option('--no-min', dest='no_min', default=False, action='store_true', help='skip minification') options, args = parser.parse_args(args) if not options.out_dir: sys.stderr.write("ERROR: Must specify --outdir=<directory>") parser.print_help() return 1 names = ["tracing.ui.extras.about_tracing.about_tracing"] project = tracing_project.TracingProject() vulcanizer = project.CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames(names) olddir = os.getcwd() try: if not os.path.exists(options.out_dir): os.makedirs(options.out_dir) o = codecs.open(os.path.join(options.out_dir, "about_tracing.html"), 'w', encoding='utf-8') try: tvcm.GenerateStandaloneHTMLToFile(o, load_sequence, title='chrome://tracing', flattened_js_url='tracing.js', minify=not options.no_min) except tvcm.module.DepsException, ex: sys.stderr.write("Error: %s\n\n" % str(ex)) return 255 o.close() o = codecs.open(os.path.join(options.out_dir, "about_tracing.js"), 'w', encoding='utf-8') assert o.encoding == 'utf-8' tvcm.GenerateJSToFile(o, load_sequence, use_include_tags_for_scripts=False, dir_for_include_tag_root=options.out_dir, minify=not options.no_min) o.close()
def source_paths(self): # We lazily init source_paths to resolve this cyclic dependency # (See perf_insights_project.py). if self._source_paths is None: self._source_paths = [] self._source_paths.append(self.dashboard_root_path) self._source_paths.append(self.dashboard_polymer_path) self._source_paths.append(self.catapult_third_party_path) import tracing_project as tracing_project_module tracing_project = tracing_project_module.TracingProject() self._source_paths.extend(tracing_project.source_paths) return self._source_paths
def ConvertChartJson(chart_json): """Convert chart_json to Histograms. Args: chart_json: path to a file containing chart-json Returns: a Vinn result object whose 'returncode' indicates whether there was an exception, and whose 'stdout' contains HistogramSet json. """ return vinn.RunFile( os.path.join(os.path.dirname(__file__), 'convert_chart_json_cmdline.html'), source_paths=tracing_project.TracingProject().source_paths, js_args=[os.path.abspath(chart_json)])
def HistogramsToCsv(json_path): """Convert HistogramSet JSON to CSV. Args: json_path: path to a file containing HistogramSet JSON Returns: a Vinn result object whose 'returncode' indicates whether there was an exception, and whose 'stdout' contains CSV. """ return vinn.RunFile(os.path.join(os.path.dirname(__file__), 'histograms_to_csv_cmdline.html'), source_paths=list( tracing_project.TracingProject().source_paths), js_args=[os.path.abspath(json_path)])
def source_paths(self): # We lazily init of source_paths because for perf_insights_project's # UpdateSysPathIfNeeded to run, the PerfInsightsProject must be __init__'d, # because thats where we centralize the various directory names. # And, for source_paths to be set up, we need the UpdateSysPathIfNeeded to # have run! We use laziness to resolve this cyclic dependency. if self._source_paths is None: self._source_paths = [] self._source_paths.append(self.perf_insights_root_path) import tracing_project as tracing_project_module tracing_project = tracing_project_module.TracingProject() self._source_paths.extend(tracing_project.source_paths) return self._source_paths
def RunTests(): project = tracing_project.TracingProject() d8_test_module_filenames = [ '/' + _RelPathToUnixPath(x) for x in project.FindAllD8TestModuleRelPaths() ] d8_test_module_filenames.sort() cmd = """ loadHTML('/tracing/base/d8_tests.html'); """ res = vinn.RunJsString(cmd, source_paths=list(project.source_paths), js_args=d8_test_module_filenames, stdout=sys.stdout, stdin=sys.stdin) return res.returncode
def MergeHistograms(json_path): """Merge Histograms. Args: json_path: Path to a HistogramSet JSON file. Returns: HistogramSet dicts of the merged Histograms. """ result = vinn.RunFile( _MERGE_HISTOGRAMS_CMD_LINE, source_paths=list(tracing_project.TracingProject().source_paths), js_args=[os.path.abspath(json_path)]) if result.returncode != 0: sys.stderr.write(result.stdout) raise Exception('vinn merge_histograms_cmdline.html returned ' + str(result.returncode)) return json.loads(result.stdout)
def Main(argv): parser = optparse.OptionParser( usage="%prog <options>", epilog="""Produces a standalone html import that contains the trace viewer.""") project = tracing_project.TracingProject() project.AddConfigNameOptionToParser(parser) parser.add_option('--no-min', dest='no_min', default=False, action='store_true', help='skip minification') parser.add_option('--report-sizes', dest='report_sizes', default=False, action='store_true', help='Explain what makes tracing big.') parser.add_option('--report-deps', dest='report_deps', default=False, action='store_true', help='Print a dot-formatted deps graph.') parser.add_option( "--output", dest="output", help='Where to put the generated result. If not ' + 'given, $TRACING/tracing/bin/trace_viewer.html is used.') options, args = parser.parse_args(argv[1:]) if len(args) != 0: parser.error('No arguments needed.') tracing_dir = os.path.relpath( os.path.join(os.path.dirname(__file__), '..', '..')) if options.output: output_filename = options.output else: output_filename = os.path.join( tracing_dir, 'tracing/bin/trace_viewer_%s.html' % options.config_name) with codecs.open(output_filename, 'w', encoding='utf-8') as f: WriteTraceViewer( f, config_name=options.config_name, minify=not options.no_min, report_sizes=options.report_sizes, report_deps=options.report_deps) return 0
def Main(argv): parser = argparse.ArgumentParser( usage='%(prog)s <options>', epilog=('Produces a standalone HTML import that contains the\n' 'trace viewer.')) project = tracing_project.TracingProject() project.AddConfigNameOptionToParser(parser) parser.add_argument('--no-min', default=False, action='store_true', help='skip minification') parser.add_argument('--report-sizes', default=False, action='store_true', help='Explain what makes tracing big.') parser.add_argument('--report-deps', default=False, action='store_true', help='Print a dot-formatted deps graph.') parser.add_argument( '--output', help='Where to put the generated result. If not given, ' '$TRACING/tracing/bin/trace_viewer.html is used.') args = parser.parse_args(argv[1:]) tracing_dir = os.path.relpath( os.path.join(os.path.dirname(__file__), '..', '..')) if args.output: output_filename = args.output else: output_filename = os.path.join( tracing_dir, 'tracing/bin/trace_viewer_%s.html' % args.config_name) with codecs.open(output_filename, 'w', encoding='utf-8') as f: WriteTraceViewer(f, config_name=args.config_name, minify=not args.no_min, report_sizes=args.report_sizes, report_deps=args.report_deps) return 0
def RunTests(): project = tracing_project.TracingProject() headless_test_module_filenames = [ '/' + _RelPathToUnixPath(x) for x in project.FindAllD8TestModuleRelPaths() ] headless_test_module_filenames.sort() cmd = """ HTMLImportsLoader.loadHTML('/tracing/base/headless_tests.html'); tr.b.unittest.loadAndRunTests(sys.argv.slice(1)); """ res = vinn.RunJsString(cmd, source_paths=list(project.source_paths), js_args=headless_test_module_filenames, stdout=sys.stdout, stdin=sys.stdin) return res.returncode
def MergeHistograms(json_path, groupby=()): """Merge Histograms. Args: json_path: Path to a HistogramSet JSON file. groupby: Array of grouping keys (name, benchmark, time, storyset_repeat, story_repeat, story, label) Returns: HistogramSet dicts of the merged Histograms. """ result = vinn.RunFile( _MERGE_HISTOGRAMS_CMD_LINE, source_paths=list(tracing_project.TracingProject().source_paths), js_args=[os.path.abspath(json_path)] + list(groupby)) if result.returncode != 0: sys.stderr.write(result.stdout) raise Exception('vinn merge_histograms_cmdline.html returned ' + str(result.returncode)) return json.loads(result.stdout)
def DiscoverMetrics(modules_to_load): """ Returns a list of registered metrics. Args: modules_to_load: a list of modules (string) to be loaded before discovering the registered metrics. """ assert isinstance(modules_to_load, list) project = tracing_project.TracingProject() all_source_paths = list(project.source_paths) res = vinn.RunFile(_DISCOVER_CMD_LINE, source_paths=all_source_paths, js_args=modules_to_load) if res.returncode != 0: raise RuntimeError('Error running metrics_discover_cmdline: ' + res.stdout) else: return [str(m) for m in json.loads(res.stdout)]
def RenderHTMLView(histograms, output_stream, reset_results=False): if not reset_results: histograms += ReadExistingResults(output_stream) output_stream.seek(0) vulcanizer = tracing_project.TracingProject().CreateVulcanizer() load_sequence = vulcanizer.CalcLoadSequenceForModuleNames( ['tracing.results2_template']) html = generate.GenerateStandaloneHTMLAsString(load_sequence) output_stream.write(html) output_stream.write('<div style="display:none;">') json_tag_newline = '\n%s' % _JSON_TAG for histogram in histograms: hist_json = json.dumps(histogram, separators=(',', ':')) output_stream.write(json_tag_newline % hist_json) output_stream.write('\n</div>\n') # If the output file already existed and was longer than the new contents, # discard the old contents after this point. output_stream.truncate()
def MapSingleTrace(trace_handle, job, extra_import_options=None, timeout=None): assert (isinstance( extra_import_options, (type(None), dict))), ('extra_import_options should be a dict or None.') project = tracing_project.TracingProject() all_source_paths = list(project.source_paths) all_source_paths.append(project.trace_processor_root_path) result = mre_result.MreResult() with trace_handle.PrepareFileForProcessing() as prepared_trace_handle: js_args = [ json.dumps(prepared_trace_handle.AsDict()), json.dumps(job.AsDict()), ] if extra_import_options: js_args.append(json.dumps(extra_import_options)) # Use 8gb heap space to make sure we don't OOM'ed on big trace, but not # on ARM devices since we use 32-bit d8 binary. if platform.machine() == 'armv7l' or platform.machine() == 'aarch64': v8_args = None else: v8_args = ['--max-old-space-size=8192'] try: res = vinn.RunFile(_MAP_SINGLE_TRACE_CMDLINE_PATH, source_paths=all_source_paths, js_args=js_args, v8_args=v8_args, timeout=timeout) except RuntimeError as e: result.AddFailure( failure.Failure(job, trace_handle.canonical_url, 'Error', 'vinn runtime error while mapping trace.', e.message, 'Unknown stack')) return result stdout = res.stdout if not isinstance(stdout, str): stdout = stdout.decode('utf-8', errors='replace') if res.returncode != 0: sys.stderr.write(stdout) result.AddFailure( failure.Failure(job, trace_handle.canonical_url, 'Error', 'vinn runtime error while mapping trace.', 'vinn runtime error while mapping trace.', 'Unknown stack')) return result for line in stdout.split('\n'): m = re.match('^MRE_RESULT: (.+)', line, re.DOTALL) if m: found_dict = json.loads(m.group(1)) failures = [ failure.Failure.FromDict(f, job, _FAILURE_NAME_TO_FAILURE_CONSTRUCTOR) for f in found_dict['failures'] ] for f in failures: result.AddFailure(f) for k, v in found_dict['pairs'].items(): result.AddPair(k, v) else: if len(line) > 0: sys.stderr.write(line) sys.stderr.write('\n') if not (len(result.pairs) or len(result.failures)): raise InternalMapError('Internal error: No results were produced!') return result
def Main(argv): parser = argparse.ArgumentParser( usage='%(prog)s <options>', epilog=('Produces a standalone HTML import that contains the\n' 'trace viewer.')) project = tracing_project.TracingProject() project.AddConfigNameOptionToParser(parser) parser.add_argument('--no-min', default=False, action='store_true', help='skip minification') parser.add_argument('--report-sizes', default=False, action='store_true', help='Explain what makes tracing big.') parser.add_argument('--report-deps', default=False, action='store_true', help='Print a dot-formatted deps graph.') parser.add_argument( '--output', help='Where to put the generated result. If not given, ' '$TRACING/tracing/bin/trace_viewer.html is used.') parser.add_argument('--generate-js', default=False, action='store_true', help='Produce a js file instead of html.') parser.add_argument('--fully-qualified-config', help='Fully qualified config name.' 'For example: tracing.extras.lean_config_import. ' 'Overrides --config-name.') parser.add_argument('--extra-search-paths', nargs='+', help='Extra search paths for script imports.') args = parser.parse_args(argv[1:]) tracing_dir = os.path.relpath( os.path.join(os.path.dirname(__file__), '..', '..')) if args.output: output_filename = args.output else: if args.generate_js: output_suffix = '.js' else: output_suffix = '.html' output_filename = os.path.join( tracing_dir, 'tracing/bin/trace_viewer_%s%s' % (args.config_name, output_suffix)) print 'Writing output to %s' % output_filename with codecs.open(output_filename, 'w', encoding='utf-8') as f: WriteTraceViewer( f, config_name=args.config_name, minify=not args.no_min, report_sizes=args.report_sizes, report_deps=args.report_deps, generate_js=args.generate_js, fully_qualified_config_name=args.fully_qualified_config, extra_search_paths=args.extra_search_paths) return 0
def __init__(self): self.project = tracing_project.TracingProject()
def UpdateGypi(): tvp = tracing_project.TracingProject() _UpdateBuildFile(os.path.join(tvp.tracing_root_path, 'trace_viewer.gypi'), GypiFile)