Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(390)

Side by Side Diff: tools/profview/profile-utils.js

Issue 2730293002: [profiler] This adds function butterflies to the function list. (Closed)
Patch Set: Formatting Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/profview/profview.css » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2017 the V8 project authors. All rights reserved. 1 // Copyright 2017 the V8 project 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
5 "use strict" 5 "use strict"
6 6
7 let codeKinds = [ 7 let codeKinds = [
8 "UNKNOWN", 8 "UNKNOWN",
9 "CPPCOMP", 9 "CPPCOMP",
10 "CPPGC", 10 "CPPGC",
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 return kind; 72 return kind;
73 } 73 }
74 74
75 function createNodeFromStackEntry(code) { 75 function createNodeFromStackEntry(code) {
76 let name = code ? code.name : "UNKNOWN"; 76 let name = code ? code.name : "UNKNOWN";
77 77
78 return { name, type : resolveCodeKind(code), 78 return { name, type : resolveCodeKind(code),
79 children : [], ownTicks : 0, ticks : 0 }; 79 children : [], ownTicks : 0, ticks : 0 };
80 } 80 }
81 81
82 function childIdFromCode(codeId, code) {
83 // For JavaScript function, pretend there is one instance of optimized
84 // function and one instance of unoptimized function per SFI.
85 // Otherwise, just compute the id from code id.
86 let type = resolveCodeKind(code);
87 if (type === "JSOPT") {
88 return code.func * 4 + 1;
89 } else if (type === "JSUNOPT") {
90 return code.func * 4 + 2;
91 } else {
92 return codeId * 4;
93 }
94 }
95
96 // We store list of ticks and positions within the ticks stack by
97 // storing flattened triplets of { tickIndex, depth, count }.
98 // Triplet { 123, 2, 3 } encodes positions in ticks 123, 124, 125,
99 // all of them at depth 2. The flattened array is used to encode
100 // position within the call-tree.
101
102 // The following function helps to encode such triplets.
103 function addFrameToFrameList(paths, pathIndex, depth) {
104 // Try to combine with the previous code run.
105 if (paths.length > 0 &&
106 paths[paths.length - 3] + 1 === pathIndex &&
107 paths[paths.length - 2] === depth) {
108 paths[paths.length - 1]++;
109 } else {
110 paths.push(pathIndex, depth, 1);
111 }
112 }
113
114 // This expands a tree node (direct children only).
115 function expandTreeNode(file, node, filter) {
116 let { frameList, ascending } = node.delayedExpansion;
117
118 let step = ascending ? 2 : -2;
119
120 for (let i = 0; i < frameList.length; i+= 3) {
121 let stackIndex = frameList[i];
122 let depth = frameList[i + 1];
123 let count = frameList[i + 2];
124 for (let j = 0; j < count; j++) {
125 let tick = file.ticks[stackIndex + j];
126 let stack = tick.s;
127
128 // Get to the next frame that has not been filtered out.
129 let k = depth + step;
130 let codeId = -1;
131 let code = null;
132 while (k >= 0 && k < stack.length) {
133 codeId = stack[k];
134 code = codeId >= 0 ? file.code[codeId] : undefined;
135 if (filter) {
136 let type = code ? code.type : undefined;
137 let kind = code ? code.kind : undefined;
138 if (filter(type, kind)) break;
139 }
140 k += step;
141 }
142 if (k < 0 || k >= stack.length) {
143 // We reached the end without finding the next step.
144 // If we are doing top-down call tree, update own ticks.
145 if (!ascending) {
146 node.ownTicks++;
147 }
148 } else {
149 // We found a child node.
150 let childId = childIdFromCode(codeId, code);
151 let child = node.children[childId];
152 if (!child) {
153 child = createNodeFromStackEntry(code);
154 child.delayedExpansion = { frameList : [], ascending };
155 node.children[childId] = child;
156 }
157 child.ticks++;
158 addFrameToFrameList(child.delayedExpansion.frameList, stackIndex, k);
159 }
160 }
161 }
162 node.delayedExpansion = null;
163 }
164
82 function addStackToTree(file, stack, tree, filter, ascending, start) { 165 function addStackToTree(file, stack, tree, filter, ascending, start) {
83 if (start === undefined) { 166 if (start === undefined) {
84 start = ascending ? 0 : stack.length - 2; 167 start = ascending ? 0 : stack.length - 2;
85 } 168 }
86 tree.ticks++; 169 tree.ticks++;
87 for (let i = start; 170 for (let i = start;
88 ascending ? (i < stack.length) : (i >= 0); 171 ascending ? (i < stack.length) : (i >= 0);
89 i += ascending ? 2 : -2) { 172 i += ascending ? 2 : -2) {
90 let codeId = stack[i]; 173 let codeId = stack[i];
91 let code = codeId >= 0 ? file.code[codeId] : undefined; 174 let code = codeId >= 0 ? file.code[codeId] : undefined;
92 if (filter) { 175 if (filter) {
93 let type = code ? code.type : undefined; 176 let type = code ? code.type : undefined;
94 let kind = code ? code.kind : undefined; 177 let kind = code ? code.kind : undefined;
95 if (!filter(type, kind)) continue; 178 if (!filter(type, kind)) continue;
96 } 179 }
97 180
98 // For JavaScript function, pretend there is one instance of optimized 181 // For JavaScript function, pretend there is one instance of optimized
99 // function and one instance of unoptimized function per SFI. 182 // function and one instance of unoptimized function per SFI.
100 let type = resolveCodeKind(code); 183 let childId = childIdFromCode(codeId, code);
101 let childId;
102 if (type === "JSOPT") {
103 childId = code.func * 4 + 1;
104 } else if (type === "JSUNOPT") {
105 childId = code.func * 4 + 2;
106 } else {
107 childId = codeId * 4;
108 }
109 let child = tree.children[childId]; 184 let child = tree.children[childId];
110 if (!child) { 185 if (!child) {
111 child = createNodeFromStackEntry(code); 186 child = createNodeFromStackEntry(code);
112 tree.children[childId] = child; 187 tree.children[childId] = child;
113 } 188 }
114 child.ticks++; 189 child.ticks++;
115 tree = child; 190 tree = child;
116 } 191 }
117 tree.ownTicks++; 192 tree.ownTicks++;
118 } 193 }
119 194
120 function createEmptyNode(name) { 195 function createEmptyNode(name) {
121 return { 196 return {
122 name : name, 197 name : name,
123 type : "CAT", 198 type : "CAT",
124 children : [], 199 children : [],
125 ownTicks : 0, 200 ownTicks : 0,
126 ticks : 0 201 ticks : 0
127 }; 202 };
128 } 203 }
129 204
130 class PlainCallTreeProcessor { 205 class PlainCallTreeProcessor {
131 constructor(filter, isBottomUp) { 206 constructor(filter, isBottomUp) {
132 this.filter = filter; 207 this.filter = filter;
133 this.tree = createEmptyNode("root"); 208 this.tree = createEmptyNode("root");
134 this.isBottomUp = isBottomUp; 209 this.isBottomUp = isBottomUp;
135 } 210 }
136 211
137 addStack(file, timestamp, vmState, stack) { 212 addStack(file, tickIndex) {
213 let stack = file.ticks[tickIndex].s;
138 addStackToTree(file, stack, this.tree, this.filter, this.isBottomUp); 214 addStackToTree(file, stack, this.tree, this.filter, this.isBottomUp);
139 } 215 }
140 } 216 }
141 217
218 function buildCategoryTreeAndLookup() {
219 let root = createEmptyNode("root");
220 let categories = {};
221 function addCategory(name, types) {
222 let n = createEmptyNode(name);
223 for (let i = 0; i < types.length; i++) {
224 categories[types[i]] = n;
225 }
226 root.children.push(n);
227 }
228 addCategory("JS Optimized", [ "JSOPT" ]);
229 addCategory("JS Unoptimized", [ "JSUNOPT", "BC" ]);
230 addCategory("IC", [ "IC" ]);
231 addCategory("RegExp", [ "REGEXP" ]);
232 addCategory("Other generated", [ "STUB", "BUILTIN" ]);
233 addCategory("C++", [ "CPP", "LIB" ]);
234 addCategory("C++/GC", [ "CPPGC" ]);
235 addCategory("C++/Compiler", [ "CPPCOMP" ]);
236 addCategory("C++/External", [ "CPPEXT" ]);
237 addCategory("Unknown", [ "UNKNOWN" ]);
238
239 return { categories, root };
240 }
241
142 class CategorizedCallTreeProcessor { 242 class CategorizedCallTreeProcessor {
143 constructor(filter, isBottomUp) { 243 constructor(filter, isBottomUp) {
144 this.filter = filter; 244 this.filter = filter;
145 let root = createEmptyNode("root"); 245 let { categories, root } = buildCategoryTreeAndLookup();
146 let categories = {};
147 function addCategory(name, types) {
148 let n = createEmptyNode(name);
149 for (let i = 0; i < types.length; i++) {
150 categories[types[i]] = n;
151 }
152 root.children.push(n);
153 }
154 addCategory("JS Optimized", [ "JSOPT" ]);
155 addCategory("JS Unoptimized", [ "JSUNOPT", "BC" ]);
156 addCategory("IC", [ "IC" ]);
157 addCategory("RegExp", [ "REGEXP" ]);
158 addCategory("Other generated", [ "STUB", "BUILTIN" ]);
159 addCategory("C++", [ "CPP", "LIB" ]);
160 addCategory("C++/GC", [ "CPPGC" ]);
161 addCategory("C++/Compiler", [ "CPPCOMP" ]);
162 addCategory("C++/External", [ "CPPEXT" ]);
163 addCategory("Unknown", [ "UNKNOWN" ]);
164 246
165 this.tree = root; 247 this.tree = root;
166 this.categories = categories; 248 this.categories = categories;
167 this.isBottomUp = isBottomUp; 249 this.isBottomUp = isBottomUp;
168 } 250 }
169 251
170 addStack(file, timestamp, vmState, stack) { 252 addStack(file, tickIndex) {
253 let stack = file.ticks[tickIndex].s;
254 let vmState = file.ticks[tickIndex].vm;
171 if (stack.length === 0) return; 255 if (stack.length === 0) return;
172 let codeId = stack[0]; 256 let codeId = stack[0];
173 let code = codeId >= 0 ? file.code[codeId] : undefined; 257 let code = codeId >= 0 ? file.code[codeId] : undefined;
174 let kind = resolveCodeKindAndVmState(code, vmState); 258 let kind = resolveCodeKindAndVmState(code, vmState);
175 let node = this.categories[kind]; 259 let node = this.categories[kind];
176 260
177 this.tree.ticks++; 261 this.tree.ticks++;
178 262
179 console.assert(node); 263 console.assert(node);
180 264
181 addStackToTree(file, stack, node, this.filter, this.isBottomUp); 265 addStackToTree(file, stack, node, this.filter, this.isBottomUp);
182 } 266 }
183 } 267 }
184 268
185 class FunctionListTree { 269 class FunctionListTree {
186 constructor(filter) { 270 constructor(filter, withCategories) {
187 this.tree = { name : "root", children : [], ownTicks : 0, ticks : 0 }; 271 if (withCategories) {
272 let { categories, root } = buildCategoryTreeAndLookup();
273 this.tree = root;
274 this.categories = categories;
275 } else {
276 this.tree = { name : "root", children : [], ownTicks : 0, ticks : 0 };
277 this.categories = null;
278 }
279
188 this.codeVisited = []; 280 this.codeVisited = [];
189 this.filter = filter; 281 this.filter = filter;
190 } 282 }
191 283
192 addStack(file, timestamp, vmState, stack) { 284 addStack(file, tickIndex) {
285 let stack = file.ticks[tickIndex].s;
286 let vmState = file.ticks[tickIndex].vm;
287
193 this.tree.ticks++; 288 this.tree.ticks++;
194 let child = null; 289 let child = null;
290 let tree = null;
195 for (let i = stack.length - 2; i >= 0; i -= 2) { 291 for (let i = stack.length - 2; i >= 0; i -= 2) {
196 let codeId = stack[i]; 292 let codeId = stack[i];
197 if (codeId < 0 || this.codeVisited[codeId]) continue; 293 if (codeId < 0 || this.codeVisited[codeId]) continue;
198 294
199 let code = codeId >= 0 ? file.code[codeId] : undefined; 295 let code = codeId >= 0 ? file.code[codeId] : undefined;
200 if (this.filter) { 296 if (this.filter) {
201 let type = code ? code.type : undefined; 297 let type = code ? code.type : undefined;
202 let kind = code ? code.kind : undefined; 298 let kind = code ? code.kind : undefined;
203 if (!this.filter(type, kind)) continue; 299 if (!this.filter(type, kind)) continue;
204 } 300 }
205 child = this.tree.children[codeId]; 301 let childId = childIdFromCode(codeId, code);
302 if (this.categories) {
303 let kind = resolveCodeKindAndVmState(code, vmState);
304 tree = this.categories[kind];
305 } else {
306 tree = this.tree;
307 }
308 child = tree.children[childId];
206 if (!child) { 309 if (!child) {
207 child = createNodeFromStackEntry(code); 310 child = createNodeFromStackEntry(code);
208 this.tree.children[codeId] = child; 311 child.children[0] = createEmptyNode("Top-down tree");
312 child.children[0].delayedExpansion =
313 { frameList : [], ascending : false };
314 child.children[1] = createEmptyNode("Bottom-up tree");
315 child.children[1].delayedExpansion =
316 { frameList : [], ascending : true };
317 tree.children[childId] = child;
209 } 318 }
210 child.ticks++; 319 child.ticks++;
320 child.children[0].ticks++;
321 addFrameToFrameList(
322 child.children[0].delayedExpansion.frameList, tickIndex, i);
323 child.children[1].ticks++;
324 addFrameToFrameList(
325 child.children[1].delayedExpansion.frameList, tickIndex, i);
211 this.codeVisited[codeId] = true; 326 this.codeVisited[codeId] = true;
212 } 327 }
213 if (child) { 328 if (child) {
214 child.ownTicks++; 329 child.ownTicks++;
330 console.assert(tree !== null);
331 tree.ticks++;
332 console.assert(tree.type === "CAT");
215 } 333 }
216 334
217 for (let i = 0; i < stack.length; i += 2) { 335 for (let i = 0; i < stack.length; i += 2) {
218 let codeId = stack[i]; 336 let codeId = stack[i];
219 if (codeId >= 0) this.codeVisited[codeId] = false; 337 if (codeId >= 0) this.codeVisited[codeId] = false;
220 } 338 }
221 } 339 }
222 } 340 }
223 341
224 342
225 class CategorySampler { 343 class CategorySampler {
226 constructor(file, bucketCount) { 344 constructor(file, bucketCount) {
227 this.bucketCount = bucketCount; 345 this.bucketCount = bucketCount;
228 346
229 this.firstTime = file.ticks[0].tm; 347 this.firstTime = file.ticks[0].tm;
230 let lastTime = file.ticks[file.ticks.length - 1].tm; 348 let lastTime = file.ticks[file.ticks.length - 1].tm;
231 this.step = (lastTime - this.firstTime) / bucketCount; 349 this.step = (lastTime - this.firstTime) / bucketCount;
232 350
233 this.buckets = []; 351 this.buckets = [];
234 let bucket = {}; 352 let bucket = {};
235 for (let i = 0; i < codeKinds.length; i++) { 353 for (let i = 0; i < codeKinds.length; i++) {
236 bucket[codeKinds[i]] = 0; 354 bucket[codeKinds[i]] = 0;
237 } 355 }
238 for (let i = 0; i < bucketCount; i++) { 356 for (let i = 0; i < bucketCount; i++) {
239 this.buckets.push(Object.assign({ total : 0 }, bucket)); 357 this.buckets.push(Object.assign({ total : 0 }, bucket));
240 } 358 }
241 } 359 }
242 360
243 addStack(file, timestamp, vmState, stack) { 361 addStack(file, tickIndex) {
362 let { tm : timestamp, vm : vmState, s : stack } = file.ticks[tickIndex];
363
244 let i = Math.floor((timestamp - this.firstTime) / this.step); 364 let i = Math.floor((timestamp - this.firstTime) / this.step);
245 if (i == this.buckets.length) i--; 365 if (i == this.buckets.length) i--;
246 console.assert(i >= 0 && i < this.buckets.length); 366 console.assert(i >= 0 && i < this.buckets.length);
247 367
248 let bucket = this.buckets[i]; 368 let bucket = this.buckets[i];
249 bucket.total++; 369 bucket.total++;
250 370
251 let codeId = (stack.length > 0) ? stack[0] : -1; 371 let codeId = (stack.length > 0) ? stack[0] : -1;
252 let code = codeId >= 0 ? file.code[codeId] : undefined; 372 let code = codeId >= 0 ? file.code[codeId] : undefined;
253 let kind = resolveCodeKindAndVmState(code, vmState); 373 let kind = resolveCodeKindAndVmState(code, vmState);
254 bucket[kind]++; 374 bucket[kind]++;
255 } 375 }
256 } 376 }
257 377
258 // Generates a tree out of a ticks sequence. 378 // Generates a tree out of a ticks sequence.
259 // {file} is the JSON files with the ticks and code objects. 379 // {file} is the JSON files with the ticks and code objects.
260 // {startTime}, {endTime} is the interval. 380 // {startTime}, {endTime} is the interval.
261 // {tree} is the processor of stacks. 381 // {tree} is the processor of stacks.
262 function generateTree( 382 function generateTree(
263 file, startTime, endTime, tree) { 383 file, startTime, endTime, tree) {
264 let ticks = file.ticks; 384 let ticks = file.ticks;
265 let i = 0; 385 let i = 0;
266 while (i < ticks.length && ticks[i].tm < startTime) { 386 while (i < ticks.length && ticks[i].tm < startTime) {
267 i++; 387 i++;
268 } 388 }
269 389
270 let tickCount = 0; 390 let tickCount = 0;
271 while (i < ticks.length && ticks[i].tm < endTime) { 391 while (i < ticks.length && ticks[i].tm < endTime) {
272 tree.addStack(file, ticks[i].tm, ticks[i].vm, ticks[i].s); 392 tree.addStack(file, i);
273 i++; 393 i++;
274 tickCount++; 394 tickCount++;
275 } 395 }
276 396
277 return tickCount; 397 return tickCount;
278 } 398 }
OLDNEW
« no previous file with comments | « no previous file | tools/profview/profview.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698