OLD | NEW |
| (Empty) |
1 <!DOCTYPE html> | |
2 <!-- | |
3 Copyright 2015 The Chromium Authors. All rights reserved. | |
4 Use of this source code is governed by a BSD-style license that can be | |
5 found in the LICENSE file. | |
6 --> | |
7 <link rel="import" href="/perf_insights/mappers/slice_cost.html"> | |
8 <link rel="import" href="/perf_insights/mappers/thread_grouping.html"> | |
9 <link rel="import" href="/perf_insights/mre/function_handle.html"> | |
10 <link rel="import" href="/tracing/base/iteration_helpers.html"> | |
11 <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> | |
12 <link rel="import" href="/tracing/model/ir_coverage.html"> | |
13 <link rel="import" href="/tracing/model/user_model/user_expectation.html"> | |
14 <link rel="import" href="/tracing/value/unit.html"> | |
15 | |
16 <script> | |
17 'use strict'; | |
18 | |
19 | |
20 tr.exportTo('pi.m', function() { | |
21 function v8ReportMapFunction(result, model) { | |
22 var allIRs = []; | |
23 model.userModel.expectations.forEach(function(ir) { | |
24 if (!(ir instanceof tr.model.um.UserExpectation)) | |
25 return; | |
26 allIRs.push(ir); | |
27 }); | |
28 | |
29 var railTypeNameByGUID = getStageTitleForEventsByGUID(model, allIRs); | |
30 | |
31 var threadGrouping = new pi.m.ThreadGrouping(); | |
32 threadGrouping.autoInitUsingHelpers(model); | |
33 var last_known_framework = ['Unknown/Uncategorized']; | |
34 | |
35 var sliceCosts = []; | |
36 | |
37 model.iterateAllEvents(function(event) { | |
38 if (!(event instanceof tr.model.ThreadSlice)) | |
39 return; | |
40 | |
41 if (!event.title.startsWith('V8.') && !event.title.startsWith('V8Test.')) | |
42 return; | |
43 | |
44 function _get_parent_data(event) { | |
45 var curSlice = event; | |
46 | |
47 var data = {}; | |
48 data['js'] = 'Unknown'; | |
49 while (curSlice) { | |
50 if (curSlice.title === 'v8.run') { | |
51 data['js'] = curSlice.args['fileName']; | |
52 } else if (curSlice.title === 'v8.compile') { | |
53 data['js'] = curSlice.args['fileName']; | |
54 } else if (curSlice.title === 'v8.callModuleMethod') { | |
55 data['js'] = 'Unknown'; | |
56 } else if (curSlice.title === 'FunctionCall') { | |
57 var scriptName = curSlice.args['data']['scriptName']; | |
58 if (scriptName.indexOf('http') != -1) { | |
59 data['js'] = scriptName; | |
60 } | |
61 } else if (curSlice.title === 'V8Test.ParseScript') { | |
62 data['js'] = curSlice.args['name']; | |
63 } else if (curSlice.title === 'V8Test.Compile') { | |
64 data['js'] = curSlice.args['name']; | |
65 } else if (curSlice.title === 'V8Test.CompileFullCode') { | |
66 data['js'] = curSlice.args['name']; | |
67 } | |
68 curSlice = curSlice.parentSlice; | |
69 } | |
70 return data; | |
71 } | |
72 | |
73 function _guess_framework_from_js_file(js_file) { | |
74 var frameworks = { | |
75 // Some commone js libs. | |
76 'jQuery': ['jquery'], | |
77 'Angular': ['angular'], | |
78 'Underscore': ['underscore'], | |
79 'Respond.js': ['respond.js'], | |
80 'Easeljs': ['easeljs'], | |
81 'Modernizr': ['modernizr'], | |
82 'Cloudflare': ['cloudflare.min.js'], | |
83 'Greensock': ['gsap/'], | |
84 'Mootools': ['mootools'], | |
85 'Zepto': ['zepto.'], | |
86 'Webfont': ['webfont.js'], | |
87 'Closure': ['closure/'], | |
88 'Ektron': ['ektron'], | |
89 'SWFObject': ['swfobject'], | |
90 'Html5shiv': ['html5shiv'], | |
91 'Requirejs': ['require.js'], | |
92 'Tweenjs': ['tweenjs'], | |
93 | |
94 // Just dividing these out into common sites. | |
95 'Google - Search': ['google.com/search?', 'www.google.'], | |
96 'Google - Adsense': ['pagead2.googlesyndication.com/pagead/'], | |
97 'Google - Analytics': ['google-analytics.com'], | |
98 'Google - Misc': ['google.', 'googleapis.'], | |
99 'Adobe - Misc': ['adobe.'], | |
100 'Facebook': ['facebook.', 'fbcdn.'], | |
101 'Outlook': ['outlook.', '.live.'], | |
102 'Craigslist': ['craigslist.'], | |
103 'Amazon': ['amazon.'], | |
104 'Yandex': ['yandex.'], | |
105 'Scene7': ['s7sdk/'], | |
106 'DoubleClick': [ | |
107 '.doubleclick', 'gpt.js', 'gtm.js', '.googletagservices.'], | |
108 'Baidu': ['baidu.'], | |
109 'Bing': ['bing.'], | |
110 'Twitter': ['twitter.'], | |
111 'Wish': ['MobileWebsiteCore'], | |
112 'Extensions - Misc': ['chrome-extension://', 'chrome://'] | |
113 }; | |
114 | |
115 var js_file_lowercase = js_file.toLowerCase(); | |
116 for (var k in frameworks) { | |
117 var keywords = frameworks[k]; | |
118 for (var i = 0; i < keywords.length; i++) { | |
119 if (js_file_lowercase.indexOf(keywords[i]) > -1) { | |
120 //last_known_framework[0] = k; | |
121 return k; | |
122 } | |
123 } | |
124 } | |
125 | |
126 // TODO: This is terrible, find a better way to attribute the | |
127 // unknown callers to a framework. Ideally we'd actually have | |
128 // access to data about the script or method that's running. | |
129 return last_known_framework[0]; | |
130 } | |
131 | |
132 function _cleanup_framework_name(name) { | |
133 var js_name = name; | |
134 if (js_name === '') { | |
135 js_name = 'Unknown'; | |
136 } | |
137 if (js_name.length > 120) { | |
138 js_name = js_name.substring(0, 120) + '...'; | |
139 } | |
140 return js_name; | |
141 } | |
142 | |
143 var ufc = model.getUserFriendlyCategoryFromEvent(event); | |
144 var data = _get_parent_data(event); | |
145 data.framework = _guess_framework_from_js_file(data.js); | |
146 var scriptURLClean = _cleanup_framework_name(data.js); | |
147 | |
148 var slice = event; | |
149 if (slice.title == 'V8.Execute') { | |
150 | |
151 // V8.Execute events may generate several sliceCostInfo, based on the | |
152 // origin of the JS being executed. | |
153 var range = new tr.b.Range(); | |
154 slice.addBoundsToRange(range); | |
155 var filtered = range.filterArray( | |
156 slice.parentContainer.samples, | |
157 function(sample) {return sample.start;}); | |
158 filtered.forEach(function(sample) { | |
159 // Let's use the state of the leaf frame. TODO(chiniforooshan): | |
160 // understand what it means if frames of a sample stack are in | |
161 // different states (BUG #1542). | |
162 var sliceData = { | |
163 threadGroup: threadGrouping.getGroupNameForEvent(slice), | |
164 railTypeName: railTypeNameByGUID[slice.guid], | |
165 userFriendlyCategory: ufc || 'other', | |
166 title: tr.e.chrome.SliceTitleFixer.fromEvent(slice), | |
167 selfTime: sample.weight, | |
168 cpuSelfTime: sample.weight, | |
169 scriptURL: data.js, | |
170 scriptURLClean: scriptURLClean, | |
171 framework: data.framework, | |
172 traceURL: model.canonicalUrl | |
173 }; | |
174 | |
175 var JSSourceState = tr.model.source_info.JSSourceState; | |
176 sliceData.jsTimeByState = {}; | |
177 for (var state in JSSourceState) { | |
178 sliceData.jsTimeByState[JSSourceState[state]] = 0; | |
179 } | |
180 | |
181 var sourceInfo = sample.leafStackFrame.sourceInfo; | |
182 if (sourceInfo === undefined || | |
183 !(sourceInfo instanceof tr.model.source_info.JSSourceInfo)) { | |
184 sliceData.jsTime = sample.weight; | |
185 sliceData.jsTimeByState[JSSourceState.UNKNOWN] = sample.weight; | |
186 } else { | |
187 sliceData.jsTimeByState[sourceInfo.state] = sample.weight; | |
188 } | |
189 | |
190 var key = sliceData.threadGroup + '/' + | |
191 sliceData.railTypeName + '/' + | |
192 sliceData.framework + '/' + | |
193 //sliceData.scriptURLClean + '/' + | |
194 sliceData.title; | |
195 sliceCosts.push({key: key, value: sliceData}); | |
196 }); | |
197 return; | |
198 } | |
199 | |
200 var sliceData = { | |
201 threadGroup: threadGrouping.getGroupNameForEvent(event), | |
202 railTypeName: railTypeNameByGUID[event.guid], | |
203 userFriendlyCategory: ufc || 'other', | |
204 title: tr.e.chrome.SliceTitleFixer.fromEvent(event), | |
205 selfTime: event.selfTime, | |
206 cpuSelfTime: event.cpuSelfTime, | |
207 scriptURL: data.js, | |
208 scriptURLClean: scriptURLClean, | |
209 framework: data.framework, | |
210 traceURL: model.canonicalUrl | |
211 }; | |
212 | |
213 var key = sliceData.threadGroup + '/' + | |
214 sliceData.railTypeName + '/' + | |
215 sliceData.framework + '/' + | |
216 //sliceData.scriptURLClean + '/' + | |
217 sliceData.title; | |
218 | |
219 var newElement = { | |
220 key: key, | |
221 value: sliceData | |
222 }; | |
223 sliceCosts.push(newElement); | |
224 }); | |
225 | |
226 result.addPair('wr', sliceCosts); | |
227 } | |
228 | |
229 function getStageTitleForEventsByGUID(model, expectations) { | |
230 var stageTitleByGUID = {}; | |
231 expectations.forEach(function applyAssociatedToRTN(ir) { | |
232 ir.associatedEvents.forEach(function applyEventToRTN(event) { | |
233 // Unassociated events have already been assigned to a RTN. | |
234 if (stageTitleByGUID[event.guid] !== undefined) | |
235 return; | |
236 stageTitleByGUID[event.guid] = ir.stageTitle; | |
237 }, this); | |
238 }, this); | |
239 | |
240 model.iterateAllEvents(function storeEventToUnassociatedSet(event) { | |
241 if (stageTitleByGUID[event.guid] !== undefined) | |
242 return; | |
243 stageTitleByGUID[event.guid] = 'Unknown'; | |
244 }); | |
245 return stageTitleByGUID; | |
246 } | |
247 | |
248 pi.FunctionRegistry.register(v8ReportMapFunction); | |
249 | |
250 // Exporting for tests. | |
251 return { | |
252 v8ReportMapFunction: v8ReportMapFunction | |
253 }; | |
254 }); | |
255 | |
256 </script> | |
OLD | NEW |