blob: 86ff219ee46c698c0b7f878df84598ca4c423fc0 [file] [log] [blame]
# Copyright (c) 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import codecs
import os
import sys
import json
from perf_insights.mre import corpus_driver_cmdline
from perf_insights.mre import corpus_query
from perf_insights.mre import function_handle
from perf_insights.mre import map_runner
from perf_insights.mre import progress_reporter as progress_reporter_module
from perf_insights.mre import job as job_module
from py_vulcanize import generate
import perf_insights_project
import bs4
def Main(argv, pi_report_file=None):
parser = argparse.ArgumentParser(
description='Runs a PerfInsights report and outputs it to html')
corpus_driver_cmdline.AddArguments(parser)
if pi_report_file is None:
parser.add_argument('pi_report_file')
parser.add_argument('--query')
parser.add_argument('-j', '--jobs', type=int, default=1)
parser.add_argument('--json', action='store_true')
parser.add_argument('-o', '--output-file')
parser.add_argument('-s', '--stop-on-error',
action='store_true')
args = parser.parse_args(argv[1:])
corpus_driver = corpus_driver_cmdline.GetCorpusDriver(parser, args)
if not args.output_file:
parser.error('Must provide -o')
if pi_report_file is None:
pi_report_file = os.path.abspath(args.pi_report_file)
if args.query is None:
query = corpus_query.CorpusQuery.FromString('True')
else:
query = corpus_query.CorpusQuery.FromString(
args.query)
with codecs.open(args.output_file, mode='w', encoding='utf-8') as ofile:
return PiReportToHTML(ofile, corpus_driver, pi_report_file, query,
args.json, args.stop_on_error, args.jobs)
def _GetMapFunctionHrefFromPiReport(html_contents):
soup = bs4.BeautifulSoup(html_contents)
elements = soup.findAll('polymer-element')
for element in elements:
if element.attrs.get('extends').lower() == 'pi-ui-r-pi-report':
map_function_href = element.attrs.get('map-function-href', None)
if map_function_href is None:
raise Exception('Report is missing map-function-href attribute')
map_function_name = element.attrs.get('map-function-name', None)
if map_function_name is None:
raise Exception('Report is missing map-function-name attribute')
pi_report_element_name = element.attrs.get('name', None)
if pi_report_element_name is None:
raise Exception('Report is missing name attribute')
return map_function_href, map_function_name, pi_report_element_name
raise Exception('No element that extends pi-ui-r-pi-report was found')
def PiReportToHTML(ofile, corpus_driver, pi_report_file, query,
json_output=False, stop_on_error=False, jobs=1, quiet=False):
project = perf_insights_project.PerfInsightsProject()
with open(pi_report_file, 'r') as f:
pi_report_file_contents = f.read()
map_function_href, map_function_name, pi_report_element_name = (
_GetMapFunctionHrefFromPiReport(pi_report_file_contents))
map_file = project.GetAbsPathFromHRef(map_function_href)
module = function_handle.ModuleToLoad(filename=map_file)
map_function_handle = function_handle.FunctionHandle([module],
map_function_name)
job = job_module.Job(map_function_handle, None)
if map_file == None:
raise Exception('Could not find %s' % map_function_href)
results = _MapTraces(corpus_driver, job, query, stop_on_error,
jobs, quiet)
if stop_on_error and results.had_failures:
sys.stderr.write('There were mapping errors. Aborting.')
return 255
if json_output:
json.dump([result.AsDict() for result in results], ofile, indent=2)
else:
WriteResultsToFile(ofile, project,
pi_report_file, pi_report_element_name,
results)
return 0
def _MapTraces(corpus_driver, job, query, stop_on_error=False,
jobs=1, quiet=False):
trace_handles = corpus_driver.GetTraceHandlesMatchingQuery(query)
if quiet:
alt_progress_reporter = progress_reporter_module.ProgressReporter()
else:
alt_progress_reporter = None
runner = map_runner.MapRunner(trace_handles, job,
stop_on_error=stop_on_error,
progress_reporter=alt_progress_reporter,
jobs=jobs)
return runner.Run()
def WriteResultsToFile(ofile, project,
pi_report_file, pi_report_element_name,
results):
vulcanizer = project.CreateVulcanizer()
modules = []
modules.append(vulcanizer.LoadModule(
module_filename=os.path.join(project.perf_insights_root_path,
'perf_insights_build/pi_report_to_html.html')))
modules.append(vulcanizer.LoadModule(
module_filename=pi_report_file))
load_sequence = vulcanizer.CalcLoadSequenceForModules(modules)
results_string = json.dumps([result.AsDict() for result in results])
bootstrap_script = generate.ExtraScript(text_content="""
document.addEventListener('DOMContentLoaded', function() {
pib.initPiReportNamed('%s');
});""" % pi_report_element_name)
scripts = [bootstrap_script, DataScript(results_string)]
generate.GenerateStandaloneHTMLToFile(
ofile, load_sequence, 'Perf Insights Report', extra_scripts=scripts)
class DataScript(generate.ExtraScript):
def __init__(self, trace_data_string):
super(DataScript, self).__init__()
self._trace_data_string = trace_data_string
def WriteToFile(self, output_file):
output_file.write('<script id="pi-report-data" type="application/json">\n')
output_file.write(self._trace_data_string)
output_file.write('\n</script>\n')