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

Side by Side Diff: tools/profile.js

Issue 99181: Enhancing profiling data processing code with functionality needed for the Dev Tools Profiler. (Closed)
Patch Set: Created 11 years, 7 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
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 } else { 178 } else {
179 this.handleUnknownCode( 179 this.handleUnknownCode(
180 devtools.profiler.Profile.Operation.TICK, stack[i], i); 180 devtools.profiler.Profile.Operation.TICK, stack[i], i);
181 } 181 }
182 } 182 }
183 return result; 183 return result;
184 }; 184 };
185 185
186 186
187 /** 187 /**
188 * Returns the root of the top down call graph. 188 * Performs a BF traversal of the top down call graph.
189 */
190 devtools.profiler.Profile.prototype.getTopDownTreeRoot = function() {
191 this.topDownTree_.computeTotalWeights();
192 return this.topDownTree_.getRoot();
193 };
194
195
196 /**
197 * Returns the root of the bottom up call graph.
198 */
199 devtools.profiler.Profile.prototype.getBottomUpTreeRoot = function() {
200 this.bottomUpTree_.computeTotalWeights();
201 return this.bottomUpTree_.getRoot();
202 };
203
204
205 /**
206 * Traverses the top down call graph in preorder.
207 * 189 *
208 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 190 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
209 */ 191 */
210 devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) { 192 devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) {
211 this.topDownTree_.traverse(f); 193 this.topDownTree_.traverse(f);
212 }; 194 };
213 195
214 196
215 /** 197 /**
216 * Traverses the bottom up call graph in preorder. 198 * Performs a BF traversal of the bottom up call graph.
217 * 199 *
218 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 200 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
219 */ 201 */
220 devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) { 202 devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) {
221 this.bottomUpTree_.traverse(f); 203 this.bottomUpTree_.traverse(f);
222 }; 204 };
223 205
224 206
225 /** 207 /**
226 * Calculates a top down profile starting from the specified node. 208 * Calculates a top down profile for a node with the specified label.
209 * If no name specified, returns the whole top down calls tree.
227 * 210 *
228 * @param {devtools.profiler.CallTree.Node} opt_root Starting node. 211 * @param {string} opt_label Node label.
229 */ 212 */
230 devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_root) { 213 devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_label) {
231 if (!opt_root) { 214 return this.getTreeProfile_(this.topDownTree_, opt_label);
232 this.topDownTree_.computeTotalWeights(); 215 };
233 return this.topDownTree_; 216
217
218 /**
219 * Calculates a bottom up profile for a node with the specified label.
220 * If no name specified, returns the whole bottom up calls tree.
221 *
222 * @param {string} opt_label Node label.
223 */
224 devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_label) {
225 return this.getTreeProfile_(this.bottomUpTree_, opt_label);
226 };
227
228
229 /**
230 * Helper function for calculating a tree profile.
231 *
232 * @param {devtools.profiler.Profile.CallTree} tree Call tree.
233 * @param {string} opt_label Node label.
234 */
235 devtools.profiler.Profile.prototype.getTreeProfile_ = function(tree, opt_label) {
236 if (!opt_label) {
237 tree.computeTotalWeights();
238 return tree;
234 } else { 239 } else {
235 throw Error('not implemented'); 240 var subTree = tree.cloneSubtree(opt_label);
241 subTree.computeTotalWeights();
242 return subTree;
236 } 243 }
237 }; 244 };
238 245
239 246
240 /** 247 /**
241 * Calculates a bottom up profile starting from the specified node. 248 * Calculates a flat profile of callees starting from a node with
249 * the specified label. If no name specified, starts from the root.
242 * 250 *
243 * @param {devtools.profiler.CallTree.Node} opt_root Starting node. 251 * @param {string} opt_label Starting node label.
244 */ 252 */
245 devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_root) { 253 devtools.profiler.Profile.prototype.getFlatProfile = function(opt_label) {
246 if (!opt_root) { 254 var counters = new devtools.profiler.CallTree();
247 this.bottomUpTree_.computeTotalWeights(); 255 var rootLabel = opt_label || devtools.profiler.CallTree.ROOT_NODE_LABEL;
248 return this.bottomUpTree_; 256 var precs = {};
249 } else { 257 precs[rootLabel] = 0;
250 throw Error('not implemented'); 258 var root = counters.findOrAddChild(rootLabel);
251 }
252 };
253 259
254
255 /**
256 * Calculates a flat profile of callees starting from the specified node.
257 *
258 * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
259 */
260 devtools.profiler.Profile.prototype.getFlatProfile = function(opt_root) {
261 var counters = new devtools.profiler.CallTree();
262 var precs = {};
263 this.topDownTree_.computeTotalWeights(); 260 this.topDownTree_.computeTotalWeights();
264 this.topDownTree_.traverseInDepth( 261 this.topDownTree_.traverseInDepth(
265 function onEnter(node) { 262 function onEnter(node) {
266 if (!(node.label in precs)) { 263 if (!(node.label in precs)) {
267 precs[node.label] = 0; 264 precs[node.label] = 0;
268 } 265 }
269 var rec = counters.findOrAddChild(node.label); 266 var nodeLabelIsRootLabel = node.label == rootLabel;
270 rec.selfWeight += node.selfWeight; 267 if (nodeLabelIsRootLabel || precs[rootLabel] > 0) {
271 if (precs[node.label] == 0) { 268 if (precs[rootLabel] == 0) {
272 rec.totalWeight += node.totalWeight; 269 root.selfWeight += node.selfWeight;
270 root.totalWeight += node.totalWeight;
271 } else {
272 var rec = root.findOrAddChild(node.label);
273 rec.selfWeight += node.selfWeight;
274 if (nodeLabelIsRootLabel || precs[node.label] == 0) {
275 rec.totalWeight += node.totalWeight;
276 }
277 }
278 precs[node.label]++;
273 } 279 }
274 precs[node.label]++;
275 }, 280 },
276 function onExit(node) { 281 function onExit(node) {
277 precs[node.label]--; 282 if (node.label == rootLabel || precs[rootLabel] > 0) {
283 precs[node.label]--;
284 }
278 }, 285 },
279 opt_root); 286 null);
287
288 if (!opt_label) {
289 // If we have created a flat profile for the whole program, we don't
290 // need an explicit root in it. Thus, replace the counters tree
291 // root with the node corresponding to the whole program.
292 counters.root_ = root;
293 } else {
294 // Propagate weights so percents can be calculated correctly.
295 counters.getRoot().selfWeight = root.selfWeight;
296 counters.getRoot().totalWeight = root.totalWeight;
297 }
280 return counters; 298 return counters;
281 }; 299 };
282 300
283 301
284 /** 302 /**
285 * Creates a dynamic code entry. 303 * Creates a dynamic code entry.
286 * 304 *
287 * @param {number} size Code size. 305 * @param {number} size Code size.
288 * @param {string} type Code type. 306 * @param {string} type Code type.
289 * @param {string} name Function name. 307 * @param {string} name Function name.
(...skipping 19 matching lines...) Expand all
309 return this.type + ': ' + name; 327 return this.type + ': ' + name;
310 }; 328 };
311 329
312 330
313 /** 331 /**
314 * Constructs a call graph. 332 * Constructs a call graph.
315 * 333 *
316 * @constructor 334 * @constructor
317 */ 335 */
318 devtools.profiler.CallTree = function() { 336 devtools.profiler.CallTree = function() {
319 this.root_ = new devtools.profiler.CallTree.Node(''); 337 this.root_ = new devtools.profiler.CallTree.Node(
338 devtools.profiler.CallTree.ROOT_NODE_LABEL);
320 }; 339 };
321 340
322 341
323 /** 342 /**
343 * The label of the root node.
344 */
345 devtools.profiler.CallTree.ROOT_NODE_LABEL = '';
346
347
348 /**
324 * @private 349 * @private
325 */ 350 */
326 devtools.profiler.CallTree.prototype.totalsComputed_ = false; 351 devtools.profiler.CallTree.prototype.totalsComputed_ = false;
327 352
328 353
329 /** 354 /**
330 * Returns the tree root. 355 * Returns the tree root.
331 */ 356 */
332 devtools.profiler.CallTree.prototype.getRoot = function() { 357 devtools.profiler.CallTree.prototype.getRoot = function() {
333 return this.root_; 358 return this.root_;
(...skipping 18 matching lines...) Expand all
352 }; 377 };
353 378
354 379
355 /** 380 /**
356 * Finds an immediate child of the specified parent with the specified 381 * Finds an immediate child of the specified parent with the specified
357 * label, creates a child node if necessary. If a parent node isn't 382 * label, creates a child node if necessary. If a parent node isn't
358 * specified, uses tree root. 383 * specified, uses tree root.
359 * 384 *
360 * @param {string} label Child node label. 385 * @param {string} label Child node label.
361 */ 386 */
362 devtools.profiler.CallTree.prototype.findOrAddChild = function( 387 devtools.profiler.CallTree.prototype.findOrAddChild = function(label) {
363 label, opt_parent) { 388 return this.root_.findOrAddChild(label);
364 var parent = opt_parent || this.root_;
365 return parent.findOrAddChild(label);
366 }; 389 };
367 390
368 391
392 /**
393 * Creates a subtree by cloning and merging all subtrees rooted at nodes
394 * with a given label. E.g. cloning the following call tree on label 'A'
395 * will give the following result:
396 *
397 * <A>--<B> <B>
398 * / /
399 * <root> == clone on 'A' ==> <root>--<A>
400 * \ \
401 * <C>--<A>--<D> <D>
402 *
403 * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the
404 * source call tree.
405 *
406 * @param {string} label The label of the new root node.
407 */
408 devtools.profiler.CallTree.prototype.cloneSubtree = function(label) {
409 var subTree = new devtools.profiler.CallTree();
410 this.traverse(function(node, parent) {
411 if (!parent && node.label != label) {
412 return null;
413 }
414 var child = (parent ? parent : subTree).findOrAddChild(node.label);
415 child.selfWeight += node.selfWeight;
416 return child;
417 });
418 return subTree;
419 };
420
421
369 /** 422 /**
370 * Computes total weights in the call graph. 423 * Computes total weights in the call graph.
371 */ 424 */
372 devtools.profiler.CallTree.prototype.computeTotalWeights = function() { 425 devtools.profiler.CallTree.prototype.computeTotalWeights = function() {
373 if (this.totalsComputed_) { 426 if (this.totalsComputed_) {
374 return; 427 return;
375 } 428 }
376 this.root_.computeTotalWeight(); 429 this.root_.computeTotalWeight();
377 this.totalsComputed_ = true; 430 this.totalsComputed_ = true;
378 }; 431 };
379 432
380 433
381 /** 434 /**
382 * Traverses the call graph in preorder. This function can be used for 435 * Traverses the call graph in preorder. This function can be used for
383 * building optionally modified tree clones. This is the boilerplate code 436 * building optionally modified tree clones. This is the boilerplate code
384 * for this scenario: 437 * for this scenario:
385 * 438 *
386 * callTree.traverse(function(node, parentClone) { 439 * callTree.traverse(function(node, parentClone) {
387 * var nodeClone = cloneNode(node); 440 * var nodeClone = cloneNode(node);
388 * if (parentClone) 441 * if (parentClone)
389 * parentClone.addChild(nodeClone); 442 * parentClone.addChild(nodeClone);
390 * return nodeClone; 443 * return nodeClone;
391 * }); 444 * });
392 * 445 *
393 * @param {function(devtools.profiler.CallTree.Node, *)} f Visitor function. 446 * @param {function(devtools.profiler.CallTree.Node, *)} f Visitor function.
394 * The second parameter is the result of calling 'f' on the parent node. 447 * The second parameter is the result of calling 'f' on the parent node.
395 * @param {devtools.profiler.CallTree.Node} opt_start Starting node.
396 */ 448 */
397 devtools.profiler.CallTree.prototype.traverse = function(f, opt_start) { 449 devtools.profiler.CallTree.prototype.traverse = function(f) {
398 var pairsToProcess = new ConsArray(); 450 var pairsToProcess = new ConsArray();
399 pairsToProcess.concat([{node: opt_start || this.root_, param: null}]); 451 pairsToProcess.concat([{node: this.root_, param: null}]);
400 while (!pairsToProcess.atEnd()) { 452 while (!pairsToProcess.atEnd()) {
401 var pair = pairsToProcess.next(); 453 var pair = pairsToProcess.next();
402 var node = pair.node; 454 var node = pair.node;
403 var newParam = f(node, pair.param); 455 var newParam = f(node, pair.param);
404 var morePairsToProcess = []; 456 var morePairsToProcess = [];
405 node.forEachChild(function (child) { 457 node.forEachChild(function (child) {
406 morePairsToProcess.push({node: child, param: newParam}); }); 458 morePairsToProcess.push({node: child, param: newParam}); });
407 pairsToProcess.concat(morePairsToProcess); 459 pairsToProcess.concat(morePairsToProcess);
408 } 460 }
409 }; 461 };
410 462
411 463
412 /** 464 /**
413 * Performs an indepth call graph traversal. 465 * Performs an indepth call graph traversal.
414 * 466 *
415 * @param {function(devtools.profiler.CallTree.Node)} enter A function called 467 * @param {function(devtools.profiler.CallTree.Node)} enter A function called
416 * prior to visiting node's children. 468 * prior to visiting node's children.
417 * @param {function(devtools.profiler.CallTree.Node)} exit A function called 469 * @param {function(devtools.profiler.CallTree.Node)} exit A function called
418 * after visiting node's children. 470 * after visiting node's children.
419 * @param {devtools.profiler.CallTree.Node} opt_start Starting node.
420 */ 471 */
421 devtools.profiler.CallTree.prototype.traverseInDepth = function( 472 devtools.profiler.CallTree.prototype.traverseInDepth = function(enter, exit) {
422 enter, exit, opt_start) {
423 function traverse(node) { 473 function traverse(node) {
424 enter(node); 474 enter(node);
425 node.forEachChild(traverse); 475 node.forEachChild(traverse);
426 exit(node); 476 exit(node);
427 } 477 }
428 traverse(opt_start || this.root_); 478 traverse(this.root_);
429 }; 479 };
430 480
431 481
432 /** 482 /**
433 * Constructs a call graph node. 483 * Constructs a call graph node.
434 * 484 *
435 * @param {string} label Node label. 485 * @param {string} label Node label.
436 * @param {devtools.profiler.CallTree.Node} opt_parent Node parent. 486 * @param {devtools.profiler.CallTree.Node} opt_parent Node parent.
437 */ 487 */
438 devtools.profiler.CallTree.Node = function(label, opt_parent) { 488 devtools.profiler.CallTree.Node = function(label, opt_parent) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 return this.children[label] || null; 550 return this.children[label] || null;
501 }; 551 };
502 552
503 553
504 /** 554 /**
505 * Finds an immediate child with the specified label, creates a child 555 * Finds an immediate child with the specified label, creates a child
506 * node if necessary. 556 * node if necessary.
507 * 557 *
508 * @param {string} label Child node label. 558 * @param {string} label Child node label.
509 */ 559 */
510 devtools.profiler.CallTree.Node.prototype.findOrAddChild = function( 560 devtools.profiler.CallTree.Node.prototype.findOrAddChild = function(label) {
511 label) {
512 return this.findChild(label) || this.addChild(label); 561 return this.findChild(label) || this.addChild(label);
513 }; 562 };
514 563
515 564
516 /** 565 /**
517 * Calls the specified function for every child. 566 * Calls the specified function for every child.
518 * 567 *
519 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 568 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
520 */ 569 */
521 devtools.profiler.CallTree.Node.prototype.forEachChild = function(f) { 570 devtools.profiler.CallTree.Node.prototype.forEachChild = function(f) {
(...skipping 25 matching lines...) Expand all
547 labels, opt_f) { 596 labels, opt_f) {
548 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) { 597 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) {
549 var child = curr.findChild(labels[pos]); 598 var child = curr.findChild(labels[pos]);
550 if (opt_f) { 599 if (opt_f) {
551 opt_f(child, pos); 600 opt_f(child, pos);
552 } 601 }
553 curr = child; 602 curr = child;
554 } 603 }
555 return curr; 604 return curr;
556 }; 605 };
OLDNEW
« no previous file with comments | « test/mjsunit/tools/profile.js ('k') | tools/profile_view.js » ('j') | tools/profile_view.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698