1# Copyright (c) 2015 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4import json 5import os 6import re 7import sys 8import tempfile 9import types 10 11import perf_insights_project 12import vinn 13 14from perf_insights.mre import failure 15from perf_insights.mre import mre_result 16 17_MAP_SINGLE_TRACE_CMDLINE_PATH = os.path.join( 18 perf_insights_project.PerfInsightsProject.perf_insights_src_path, 19 'map_single_trace_cmdline.html') 20 21class TemporaryMapScript(object): 22 def __init__(self, js): 23 temp_file = tempfile.NamedTemporaryFile(delete=False) 24 temp_file.write(""" 25<!DOCTYPE html> 26<script> 27%s 28</script> 29""" % js) 30 temp_file.close() 31 self._filename = temp_file.name 32 33 def __enter__(self): 34 return self 35 36 def __exit__(self, *args, **kwargs): 37 os.remove(self._filename) 38 self._filename = None 39 40 @property 41 def filename(self): 42 return self._filename 43 44 45class FunctionLoadingFailure(failure.Failure): 46 pass 47 48class FunctionNotDefinedFailure(failure.Failure): 49 pass 50 51class MapFunctionFailure(failure.Failure): 52 pass 53 54class FileLoadingFailure(failure.Failure): 55 pass 56 57class TraceImportFailure(failure.Failure): 58 pass 59 60class NoResultsAddedFailure(failure.Failure): 61 pass 62 63class InternalMapError(Exception): 64 pass 65 66_FAILURE_NAME_TO_FAILURE_CONSTRUCTOR = { 67 'FileLoadingError': FileLoadingFailure, 68 'FunctionLoadingError': FunctionLoadingFailure, 69 'FunctionNotDefinedError': FunctionNotDefinedFailure, 70 'TraceImportError': TraceImportFailure, 71 'MapFunctionError': MapFunctionFailure, 72 'NoResultsAddedError': NoResultsAddedFailure 73} 74 75 76def MapSingleTrace(trace_handle, 77 job, 78 extra_import_options=None): 79 assert (type(extra_import_options) is types.NoneType or 80 type(extra_import_options) is types.DictType), ( 81 'extra_import_options should be a dict or None.') 82 project = perf_insights_project.PerfInsightsProject() 83 84 all_source_paths = list(project.source_paths) 85 all_source_paths.append(project.perf_insights_root_path) 86 87 result = mre_result.MreResult() 88 89 with trace_handle.PrepareFileForProcessing() as prepared_trace_handle: 90 js_args = [ 91 json.dumps(prepared_trace_handle.AsDict()), 92 json.dumps(job.AsDict()), 93 ] 94 if extra_import_options: 95 js_args.append(json.dumps(extra_import_options)) 96 97 res = vinn.RunFile( 98 _MAP_SINGLE_TRACE_CMDLINE_PATH, source_paths=all_source_paths, 99 js_args=js_args) 100 101 if res.returncode != 0: 102 try: 103 sys.stderr.write(res.stdout) 104 except Exception: 105 pass 106 result.AddFailure(failure.Failure( 107 job.map_function_handle.AsUserFriendlyString(), 108 trace_handle.canonical_url, 109 'Error', 'vinn runtime error while mapping trace.', 110 'vinn runtime error while mapping trace.', 'Unknown stack')) 111 return result 112 113 for line in res.stdout.split('\n'): 114 m = re.match('^MRE_RESULT: (.+)', line, re.DOTALL) 115 if m: 116 found_dict = json.loads(m.group(1)) 117 failures = [failure.Failure.FromDict( 118 f, job, _FAILURE_NAME_TO_FAILURE_CONSTRUCTOR) 119 for f in found_dict['failures']] 120 121 for f in failures: 122 result.AddFailure(f) 123 124 for k, v in found_dict['pairs'].iteritems(): 125 result.AddPair(k, v) 126 127 else: 128 if len(line) > 0: 129 sys.stderr.write(line) 130 sys.stderr.write('\n') 131 132 if not (len(result.pairs) or len(result.failures)): 133 raise InternalMapError('Internal error: No results were produced!') 134 135 return result 136