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 WebInspector.TimelineJSProfileProcessor = {}; |
5 | |
6 WebInspector.TimelineJSProfileProcessor = { }; | |
7 | 5 |
8 /** | 6 /** |
9 * @param {!WebInspector.CPUProfileDataModel} jsProfileModel | 7 * @param {!WebInspector.CPUProfileDataModel} jsProfileModel |
10 * @param {!WebInspector.TracingModel.Thread} thread | 8 * @param {!WebInspector.TracingModel.Thread} thread |
11 * @return {!Array<!WebInspector.TracingModel.Event>} | 9 * @return {!Array<!WebInspector.TracingModel.Event>} |
12 */ | 10 */ |
13 WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile = fu
nction(jsProfileModel, thread) | 11 WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile = fu
nction(jsProfileModel, thread) { |
14 { | 12 var idleNode = jsProfileModel.idleNode; |
15 var idleNode = jsProfileModel.idleNode; | 13 var programNode = jsProfileModel.programNode; |
16 var programNode = jsProfileModel.programNode; | 14 var gcNode = jsProfileModel.gcNode; |
17 var gcNode = jsProfileModel.gcNode; | 15 var samples = jsProfileModel.samples; |
18 var samples = jsProfileModel.samples; | 16 var timestamps = jsProfileModel.timestamps; |
19 var timestamps = jsProfileModel.timestamps; | 17 var jsEvents = []; |
20 var jsEvents = []; | 18 /** @type {!Map<!Object, !Array<!RuntimeAgent.CallFrame>>} */ |
21 /** @type {!Map<!Object, !Array<!RuntimeAgent.CallFrame>>} */ | 19 var nodeToStackMap = new Map(); |
22 var nodeToStackMap = new Map(); | 20 nodeToStackMap.set(programNode, []); |
23 nodeToStackMap.set(programNode, []); | 21 for (var i = 0; i < samples.length; ++i) { |
24 for (var i = 0; i < samples.length; ++i) { | 22 var node = jsProfileModel.nodeByIndex(i); |
25 var node = jsProfileModel.nodeByIndex(i); | 23 if (!node) { |
26 if (!node) { | 24 console.error(`Node with unknown id ${samples[i]} at index ${i}`); |
27 console.error(`Node with unknown id ${samples[i]} at index ${i}`); | 25 continue; |
28 continue; | 26 } |
29 } | 27 if (node === gcNode || node === idleNode) |
30 if (node === gcNode || node === idleNode) | 28 continue; |
31 continue; | 29 var callFrames = nodeToStackMap.get(node); |
32 var callFrames = nodeToStackMap.get(node); | 30 if (!callFrames) { |
33 if (!callFrames) { | 31 callFrames = /** @type {!Array<!RuntimeAgent.CallFrame>} */ (new Array(nod
e.depth + 1)); |
34 callFrames = /** @type {!Array<!RuntimeAgent.CallFrame>} */ (new Arr
ay(node.depth + 1)); | 32 nodeToStackMap.set(node, callFrames); |
35 nodeToStackMap.set(node, callFrames); | 33 for (var j = 0; node.parent; node = node.parent) |
36 for (var j = 0; node.parent; node = node.parent) | 34 callFrames[j++] = /** @type {!RuntimeAgent.CallFrame} */ (node); |
37 callFrames[j++] = /** @type {!RuntimeAgent.CallFrame} */ (node); | 35 } |
38 } | 36 var jsSampleEvent = new WebInspector.TracingModel.Event( |
39 var jsSampleEvent = new WebInspector.TracingModel.Event(WebInspector.Tra
cingModel.DevToolsTimelineEventCategory, | 37 WebInspector.TracingModel.DevToolsTimelineEventCategory, WebInspector.Ti
melineModel.RecordType.JSSample, |
40 WebInspector.TimelineModel.RecordType.JSSample, | 38 WebInspector.TracingModel.Phase.Instant, timestamps[i], thread); |
41 WebInspector.TracingModel.Phase.Instant, timestamps[i], thread); | 39 jsSampleEvent.args['data'] = {stackTrace: callFrames}; |
42 jsSampleEvent.args["data"] = { stackTrace: callFrames }; | 40 jsEvents.push(jsSampleEvent); |
43 jsEvents.push(jsSampleEvent); | 41 } |
44 } | 42 return jsEvents; |
45 return jsEvents; | |
46 }; | 43 }; |
47 | 44 |
48 /** | 45 /** |
49 * @param {!Array<!WebInspector.TracingModel.Event>} events | 46 * @param {!Array<!WebInspector.TracingModel.Event>} events |
50 * @return {!Array<!WebInspector.TracingModel.Event>} | 47 * @return {!Array<!WebInspector.TracingModel.Event>} |
51 */ | 48 */ |
52 WebInspector.TimelineJSProfileProcessor.generateJSFrameEvents = function(events) | 49 WebInspector.TimelineJSProfileProcessor.generateJSFrameEvents = function(events)
{ |
53 { | 50 /** |
54 /** | 51 * @param {!RuntimeAgent.CallFrame} frame1 |
55 * @param {!RuntimeAgent.CallFrame} frame1 | 52 * @param {!RuntimeAgent.CallFrame} frame2 |
56 * @param {!RuntimeAgent.CallFrame} frame2 | 53 * @return {boolean} |
57 * @return {boolean} | 54 */ |
58 */ | 55 function equalFrames(frame1, frame2) { |
59 function equalFrames(frame1, frame2) | 56 return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2
.functionName; |
60 { | 57 } |
61 return frame1.scriptId === frame2.scriptId && frame1.functionName === fr
ame2.functionName; | 58 |
62 } | 59 /** |
63 | 60 * @param {!WebInspector.TracingModel.Event} e |
64 /** | 61 * @return {number} |
65 * @param {!WebInspector.TracingModel.Event} e | 62 */ |
66 * @return {number} | 63 function eventEndTime(e) { |
67 */ | 64 return e.endTime || e.startTime; |
68 function eventEndTime(e) | 65 } |
69 { | 66 |
70 return e.endTime || e.startTime; | 67 /** |
71 } | 68 * @param {!WebInspector.TracingModel.Event} e |
72 | 69 * @return {boolean} |
73 /** | 70 */ |
74 * @param {!WebInspector.TracingModel.Event} e | 71 function isJSInvocationEvent(e) { |
75 * @return {boolean} | 72 switch (e.name) { |
76 */ | 73 case WebInspector.TimelineModel.RecordType.RunMicrotasks: |
77 function isJSInvocationEvent(e) | 74 case WebInspector.TimelineModel.RecordType.FunctionCall: |
78 { | 75 case WebInspector.TimelineModel.RecordType.EvaluateScript: |
79 switch (e.name) { | 76 return true; |
80 case WebInspector.TimelineModel.RecordType.RunMicrotasks: | 77 } |
81 case WebInspector.TimelineModel.RecordType.FunctionCall: | 78 return false; |
82 case WebInspector.TimelineModel.RecordType.EvaluateScript: | 79 } |
83 return true; | 80 |
84 } | 81 var jsFrameEvents = []; |
85 return false; | 82 var jsFramesStack = []; |
86 } | 83 var lockedJsStackDepth = []; |
87 | 84 var ordinal = 0; |
88 var jsFrameEvents = []; | 85 var filterNativeFunctions = !WebInspector.moduleSetting('showNativeFunctionsIn
JSProfile').get(); |
89 var jsFramesStack = []; | 86 |
90 var lockedJsStackDepth = []; | 87 /** |
91 var ordinal = 0; | 88 * @param {!WebInspector.TracingModel.Event} e |
92 var filterNativeFunctions = !WebInspector.moduleSetting("showNativeFunctions
InJSProfile").get(); | 89 */ |
93 | 90 function onStartEvent(e) { |
94 /** | 91 e.ordinal = ++ordinal; |
95 * @param {!WebInspector.TracingModel.Event} e | 92 extractStackTrace(e); |
96 */ | 93 // For the duration of the event we cannot go beyond the stack associated wi
th it. |
97 function onStartEvent(e) | 94 lockedJsStackDepth.push(jsFramesStack.length); |
98 { | 95 } |
99 e.ordinal = ++ordinal; | 96 |
100 extractStackTrace(e); | 97 /** |
101 // For the duration of the event we cannot go beyond the stack associate
d with it. | 98 * @param {!WebInspector.TracingModel.Event} e |
102 lockedJsStackDepth.push(jsFramesStack.length); | 99 * @param {?WebInspector.TracingModel.Event} parent |
103 } | 100 */ |
104 | 101 function onInstantEvent(e, parent) { |
105 /** | 102 e.ordinal = ++ordinal; |
106 * @param {!WebInspector.TracingModel.Event} e | 103 if (parent && isJSInvocationEvent(parent)) |
107 * @param {?WebInspector.TracingModel.Event} parent | 104 extractStackTrace(e); |
108 */ | 105 } |
109 function onInstantEvent(e, parent) | 106 |
110 { | 107 /** |
111 e.ordinal = ++ordinal; | 108 * @param {!WebInspector.TracingModel.Event} e |
112 if (parent && isJSInvocationEvent(parent)) | 109 */ |
113 extractStackTrace(e); | 110 function onEndEvent(e) { |
114 } | 111 truncateJSStack(lockedJsStackDepth.pop(), e.endTime); |
115 | 112 } |
116 /** | 113 |
117 * @param {!WebInspector.TracingModel.Event} e | 114 /** |
118 */ | 115 * @param {number} depth |
119 function onEndEvent(e) | 116 * @param {number} time |
120 { | 117 */ |
121 truncateJSStack(lockedJsStackDepth.pop(), e.endTime); | 118 function truncateJSStack(depth, time) { |
122 } | 119 if (lockedJsStackDepth.length) { |
123 | 120 var lockedDepth = lockedJsStackDepth.peekLast(); |
124 /** | 121 if (depth < lockedDepth) { |
125 * @param {number} depth | 122 console.error( |
126 * @param {number} time | 123 'Child stack is shallower (' + depth + ') than the parent stack (' +
lockedDepth + ') at ' + time); |
127 */ | 124 depth = lockedDepth; |
128 function truncateJSStack(depth, time) | 125 } |
129 { | 126 } |
130 if (lockedJsStackDepth.length) { | 127 if (jsFramesStack.length < depth) { |
131 var lockedDepth = lockedJsStackDepth.peekLast(); | 128 console.error('Trying to truncate higher than the current stack size at '
+ time); |
132 if (depth < lockedDepth) { | 129 depth = jsFramesStack.length; |
133 console.error("Child stack is shallower (" + depth + ") than the
parent stack (" + lockedDepth + ") at " + time); | 130 } |
134 depth = lockedDepth; | 131 for (var k = 0; k < jsFramesStack.length; ++k) |
135 } | 132 jsFramesStack[k].setEndTime(time); |
136 } | 133 jsFramesStack.length = depth; |
137 if (jsFramesStack.length < depth) { | 134 } |
138 console.error("Trying to truncate higher than the current stack size
at " + time); | 135 |
139 depth = jsFramesStack.length; | 136 /** |
140 } | 137 * @param {!Array<!RuntimeAgent.CallFrame>} stack |
141 for (var k = 0; k < jsFramesStack.length; ++k) | 138 */ |
142 jsFramesStack[k].setEndTime(time); | 139 function filterStackFrames(stack) { |
143 jsFramesStack.length = depth; | 140 for (var i = 0, j = 0; i < stack.length; ++i) { |
144 } | 141 var url = stack[i].url; |
145 | 142 if (url && url.startsWith('native ')) |
146 /** | 143 continue; |
147 * @param {!Array<!RuntimeAgent.CallFrame>} stack | 144 stack[j++] = stack[i]; |
148 */ | 145 } |
149 function filterStackFrames(stack) | 146 stack.length = j; |
150 { | 147 } |
151 for (var i = 0, j = 0; i < stack.length; ++i) { | 148 |
152 var url = stack[i].url; | 149 /** |
153 if (url && url.startsWith("native ")) | 150 * @param {!WebInspector.TracingModel.Event} e |
154 continue; | 151 */ |
155 stack[j++] = stack[i]; | 152 function extractStackTrace(e) { |
156 } | 153 var recordTypes = WebInspector.TimelineModel.RecordType; |
157 stack.length = j; | 154 var callFrames; |
158 } | 155 if (e.name === recordTypes.JSSample) { |
159 | 156 var eventData = e.args['data'] || e.args['beginData']; |
160 /** | 157 callFrames = /** @type {!Array<!RuntimeAgent.CallFrame>} */ (eventData &&
eventData['stackTrace']); |
161 * @param {!WebInspector.TracingModel.Event} e | 158 } else { |
162 */ | 159 callFrames = /** @type {!Array<!RuntimeAgent.CallFrame>} */ ( |
163 function extractStackTrace(e) | 160 jsFramesStack.map(frameEvent => frameEvent.args['data']).reverse()); |
164 { | 161 } |
165 var recordTypes = WebInspector.TimelineModel.RecordType; | 162 if (filterNativeFunctions) |
166 var callFrames; | 163 filterStackFrames(callFrames); |
167 if (e.name === recordTypes.JSSample) { | 164 var endTime = eventEndTime(e); |
168 var eventData = e.args["data"] || e.args["beginData"]; | 165 var numFrames = callFrames.length; |
169 callFrames = /** @type {!Array<!RuntimeAgent.CallFrame>} */ (eventDa
ta && eventData["stackTrace"]); | 166 var minFrames = Math.min(numFrames, jsFramesStack.length); |
170 } else { | 167 var i; |
171 callFrames = /** @type {!Array<!RuntimeAgent.CallFrame>} */ (jsFrame
sStack.map(frameEvent => frameEvent.args["data"]).reverse()); | 168 for (i = lockedJsStackDepth.peekLast() || 0; i < minFrames; ++i) { |
172 } | 169 var newFrame = callFrames[numFrames - 1 - i]; |
173 if (filterNativeFunctions) | 170 var oldFrame = jsFramesStack[i].args['data']; |
174 filterStackFrames(callFrames); | 171 if (!equalFrames(newFrame, oldFrame)) |
175 var endTime = eventEndTime(e); | 172 break; |
176 var numFrames = callFrames.length; | 173 jsFramesStack[i].setEndTime(Math.max(jsFramesStack[i].endTime, endTime)); |
177 var minFrames = Math.min(numFrames, jsFramesStack.length); | 174 } |
178 var i; | 175 truncateJSStack(i, e.startTime); |
179 for (i = lockedJsStackDepth.peekLast() || 0; i < minFrames; ++i) { | 176 for (; i < numFrames; ++i) { |
180 var newFrame = callFrames[numFrames - 1 - i]; | 177 var frame = callFrames[numFrames - 1 - i]; |
181 var oldFrame = jsFramesStack[i].args["data"]; | 178 var jsFrameEvent = new WebInspector.TracingModel.Event( |
182 if (!equalFrames(newFrame, oldFrame)) | 179 WebInspector.TracingModel.DevToolsTimelineEventCategory, recordTypes.J
SFrame, |
183 break; | 180 WebInspector.TracingModel.Phase.Complete, e.startTime, e.thread); |
184 jsFramesStack[i].setEndTime(Math.max(jsFramesStack[i].endTime, endTi
me)); | 181 jsFrameEvent.ordinal = e.ordinal; |
185 } | 182 jsFrameEvent.addArgs({data: frame}); |
186 truncateJSStack(i, e.startTime); | 183 jsFrameEvent.setEndTime(endTime); |
187 for (; i < numFrames; ++i) { | 184 jsFramesStack.push(jsFrameEvent); |
188 var frame = callFrames[numFrames - 1 - i]; | 185 jsFrameEvents.push(jsFrameEvent); |
189 var jsFrameEvent = new WebInspector.TracingModel.Event(WebInspector.
TracingModel.DevToolsTimelineEventCategory, recordTypes.JSFrame, | 186 } |
190 WebInspector.TracingModel.Phase.Complete, e.startTime, e.thread)
; | 187 } |
191 jsFrameEvent.ordinal = e.ordinal; | 188 |
192 jsFrameEvent.addArgs({ data: frame }); | 189 /** |
193 jsFrameEvent.setEndTime(endTime); | 190 * @param {!Array<!WebInspector.TracingModel.Event>} events |
194 jsFramesStack.push(jsFrameEvent); | 191 * @return {?WebInspector.TracingModel.Event} |
195 jsFrameEvents.push(jsFrameEvent); | 192 */ |
196 } | 193 function findFirstTopLevelEvent(events) { |
197 } | 194 for (var i = 0; i < events.length; ++i) { |
198 | 195 if (WebInspector.TracingModel.isTopLevelEvent(events[i])) |
199 /** | 196 return events[i]; |
200 * @param {!Array<!WebInspector.TracingModel.Event>} events | 197 } |
201 * @return {?WebInspector.TracingModel.Event} | 198 return null; |
202 */ | 199 } |
203 function findFirstTopLevelEvent(events) | 200 |
204 { | 201 var firstTopLevelEvent = findFirstTopLevelEvent(events); |
205 for (var i = 0; i < events.length; ++i) { | 202 if (firstTopLevelEvent) |
206 if (WebInspector.TracingModel.isTopLevelEvent(events[i])) | 203 WebInspector.TimelineModel.forEachEvent( |
207 return events[i]; | 204 events, onStartEvent, onEndEvent, onInstantEvent, firstTopLevelEvent.sta
rtTime); |
208 } | 205 return jsFrameEvents; |
209 return null; | |
210 } | |
211 | |
212 var firstTopLevelEvent = findFirstTopLevelEvent(events); | |
213 if (firstTopLevelEvent) | |
214 WebInspector.TimelineModel.forEachEvent(events, onStartEvent, onEndEvent
, onInstantEvent, firstTopLevelEvent.startTime); | |
215 return jsFrameEvents; | |
216 }; | 206 }; |
OLD | NEW |