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

Side by Side Diff: tools/profile.js

Issue 92120: Added ProfileView object for performing sorting, searching and filtering operations on a profile. (Closed)
Patch Set: Created 11 years, 8 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 * Should be overriden by subclasses. 49 * Should be overriden by subclasses.
50 * 50 *
51 * @param {string} name Function name. 51 * @param {string} name Function name.
52 */ 52 */
53 devtools.profiler.Profile.prototype.skipThisFunction = function(name) { 53 devtools.profiler.Profile.prototype.skipThisFunction = function(name) {
54 return false; 54 return false;
55 }; 55 };
56 56
57 57
58 /** 58 /**
59 * Enum for profiler operations that involve looking up existing
60 * code entries.
61 *
62 * @enum {number}
63 */
64 devtools.profiler.Profile.Operation = {
65 MOVE: 0,
66 DELETE: 1,
67 TICK: 2
68 };
69
70
71 /**
59 * Called whenever the specified operation has failed finding a function 72 * Called whenever the specified operation has failed finding a function
60 * containing the specified address. Should be overriden by subclasses. 73 * containing the specified address. Should be overriden by subclasses.
61 * Operation is one of the following: 'move', 'delete', 'tick'. 74 * See the devtools.profiler.Profile.Operation enum for the list of
75 * possible operations.
62 * 76 *
63 * @param {string} operation Operation name. 77 * @param {number} operation Operation.
64 * @param {number} addr Address of the unknown code. 78 * @param {number} addr Address of the unknown code.
79 * @param {number} opt_stackPos If an unknown address is encountered
80 * during stack strace processing, specifies a position of the frame
81 * containing the address.
65 */ 82 */
66 devtools.profiler.Profile.prototype.handleUnknownCode = function( 83 devtools.profiler.Profile.prototype.handleUnknownCode = function(
67 operation, addr) { 84 operation, addr, opt_stackPos) {
68 }; 85 };
69 86
70 87
71 /** 88 /**
72 * Registers static (library) code entry. 89 * Registers static (library) code entry.
73 * 90 *
74 * @param {string} name Code entry name. 91 * @param {string} name Code entry name.
75 * @param {number} startAddr Starting address. 92 * @param {number} startAddr Starting address.
76 * @param {number} endAddr Ending address. 93 * @param {number} endAddr Ending address.
77 */ 94 */
78 devtools.profiler.Profile.prototype.addStaticCode = function( 95 devtools.profiler.Profile.prototype.addStaticCode = function(
79 name, startAddr, endAddr) { 96 name, startAddr, endAddr) {
80 this.codeMap_.addStaticCode(startAddr, 97 var entry = new devtools.profiler.CodeMap.CodeEntry(
81 new devtools.profiler.CodeMap.CodeEntry(endAddr - startAddr, name)); 98 endAddr - startAddr, name);
99 this.codeMap_.addStaticCode(startAddr, entry);
100 return entry;
82 }; 101 };
83 102
84 103
85 /** 104 /**
86 * Registers dynamic (JIT-compiled) code entry. 105 * Registers dynamic (JIT-compiled) code entry.
87 * 106 *
88 * @param {string} type Code entry type. 107 * @param {string} type Code entry type.
89 * @param {string} name Code entry name. 108 * @param {string} name Code entry name.
90 * @param {number} start Starting address. 109 * @param {number} start Starting address.
91 * @param {number} size Code entry size. 110 * @param {number} size Code entry size.
92 */ 111 */
93 devtools.profiler.Profile.prototype.addCode = function( 112 devtools.profiler.Profile.prototype.addCode = function(
94 type, name, start, size) { 113 type, name, start, size) {
95 this.codeMap_.addCode(start, 114 var entry = new devtools.profiler.Profile.DynamicCodeEntry(size, type, name);
96 new devtools.profiler.Profile.DynamicCodeEntry(size, type, name)); 115 this.codeMap_.addCode(start, entry);
116 return entry;
97 }; 117 };
98 118
99 119
100 /** 120 /**
101 * Reports about moving of a dynamic code entry. 121 * Reports about moving of a dynamic code entry.
102 * 122 *
103 * @param {number} from Current code entry address. 123 * @param {number} from Current code entry address.
104 * @param {number} to New code entry address. 124 * @param {number} to New code entry address.
105 */ 125 */
106 devtools.profiler.Profile.prototype.moveCode = function(from, to) { 126 devtools.profiler.Profile.prototype.moveCode = function(from, to) {
107 try { 127 try {
108 this.codeMap_.moveCode(from, to); 128 this.codeMap_.moveCode(from, to);
109 } catch (e) { 129 } catch (e) {
110 this.handleUnknownCode('move', from); 130 this.handleUnknownCode(devtools.profiler.Profile.Operation.MOVE, from);
111 } 131 }
112 }; 132 };
113 133
114 134
115 /** 135 /**
116 * Reports about deletion of a dynamic code entry. 136 * Reports about deletion of a dynamic code entry.
117 * 137 *
118 * @param {number} start Starting address. 138 * @param {number} start Starting address.
119 */ 139 */
120 devtools.profiler.Profile.prototype.deleteCode = function(start) { 140 devtools.profiler.Profile.prototype.deleteCode = function(start) {
121 try { 141 try {
122 this.codeMap_.deleteCode(start); 142 this.codeMap_.deleteCode(start);
123 } catch (e) { 143 } catch (e) {
124 this.handleUnknownCode('delete', start); 144 this.handleUnknownCode(devtools.profiler.Profile.Operation.DELETE, start);
125 } 145 }
126 }; 146 };
127 147
128 148
129 /** 149 /**
130 * Records a tick event. Stack must contain a sequence of 150 * Records a tick event. Stack must contain a sequence of
131 * addresses starting with the program counter value. 151 * addresses starting with the program counter value.
132 * 152 *
133 * @param {Array<number>} stack Stack sample. 153 * @param {Array<number>} stack Stack sample.
134 */ 154 */
(...skipping 14 matching lines...) Expand all
149 devtools.profiler.Profile.prototype.resolveAndFilterFuncs_ = function(stack) { 169 devtools.profiler.Profile.prototype.resolveAndFilterFuncs_ = function(stack) {
150 var result = []; 170 var result = [];
151 for (var i = 0; i < stack.length; ++i) { 171 for (var i = 0; i < stack.length; ++i) {
152 var entry = this.codeMap_.findEntry(stack[i]); 172 var entry = this.codeMap_.findEntry(stack[i]);
153 if (entry) { 173 if (entry) {
154 var name = entry.getName(); 174 var name = entry.getName();
155 if (!this.skipThisFunction(name)) { 175 if (!this.skipThisFunction(name)) {
156 result.push(name); 176 result.push(name);
157 } 177 }
158 } else { 178 } else {
159 this.handleUnknownCode('tick', stack[i]); 179 this.handleUnknownCode(
180 devtools.profiler.Profile.Operation.TICK, stack[i], i);
160 } 181 }
161 } 182 }
162 return result; 183 return result;
163 }; 184 };
164 185
165 186
166 /** 187 /**
167 * Returns the root of the top down call graph. 188 * Returns the root of the top down call graph.
168 */ 189 */
169 devtools.profiler.Profile.prototype.getTopDownTreeRoot = function() { 190 devtools.profiler.Profile.prototype.getTopDownTreeRoot = function() {
170 this.topDownTree_.computeTotalWeights(); 191 this.topDownTree_.computeTotalWeights();
171 return this.topDownTree_.root_; 192 return this.topDownTree_.getRoot();
172 }; 193 };
173 194
174 195
175 /** 196 /**
176 * Returns the root of the bottom up call graph. 197 * Returns the root of the bottom up call graph.
177 */ 198 */
178 devtools.profiler.Profile.prototype.getBottomUpTreeRoot = function() { 199 devtools.profiler.Profile.prototype.getBottomUpTreeRoot = function() {
179 this.bottomUpTree_.computeTotalWeights(); 200 this.bottomUpTree_.computeTotalWeights();
180 return this.bottomUpTree_.root_; 201 return this.bottomUpTree_.getRoot();
181 }; 202 };
182 203
183 204
184 /** 205 /**
185 * Traverses the top down call graph in preorder. 206 * Traverses the top down call graph in preorder.
186 * 207 *
187 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 208 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
188 */ 209 */
189 devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) { 210 devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) {
190 this.topDownTree_.traverse(f); 211 this.topDownTree_.traverse(f);
191 }; 212 };
192 213
193 214
194 /** 215 /**
195 * Traverses the bottom up call graph in preorder. 216 * Traverses the bottom up call graph in preorder.
196 * 217 *
197 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 218 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function.
198 */ 219 */
199 devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) { 220 devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) {
200 this.bottomUpTree_.traverse(f); 221 this.bottomUpTree_.traverse(f);
201 }; 222 };
202 223
203 224
204 /** 225 /**
226 * Calculates a top down profile starting from the specified node.
227 *
228 * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
229 */
230 devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_root) {
231 if (!opt_root) {
232 this.topDownTree_.computeTotalWeights();
233 return this.topDownTree_;
234 } else {
235 throw Error('not implemented');
236 }
237 };
238
239
240 /**
241 * Calculates a bottom up profile starting from the specified node.
242 *
243 * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
244 */
245 devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_root) {
246 if (!opt_root) {
247 this.bottomUpTree_.computeTotalWeights();
248 return this.bottomUpTree_;
249 } else {
250 throw Error('not implemented');
251 }
252 };
253
254
255 /**
205 * Calculates a flat profile of callees starting from the specified node. 256 * Calculates a flat profile of callees starting from the specified node.
206 * 257 *
207 * @param {devtools.profiler.CallTree.Node} opt_root Starting node. 258 * @param {devtools.profiler.CallTree.Node} opt_root Starting node.
208 */ 259 */
209 devtools.profiler.Profile.prototype.getFlatProfile = function(opt_root) { 260 devtools.profiler.Profile.prototype.getFlatProfile = function(opt_root) {
210 var counters = new devtools.profiler.CallTree.Node(''); 261 var counters = new devtools.profiler.CallTree();
211 var precs = {}; 262 var precs = {};
212 this.topDownTree_.computeTotalWeights(); 263 this.topDownTree_.computeTotalWeights();
213 this.topDownTree_.traverseInDepth( 264 this.topDownTree_.traverseInDepth(
214 function onEnter(node) { 265 function onEnter(node) {
215 if (!(node.label in precs)) { 266 if (!(node.label in precs)) {
216 precs[node.label] = 0; 267 precs[node.label] = 0;
217 } 268 }
218 var rec = counters.findOrAddChild(node.label); 269 var rec = counters.findOrAddChild(node.label);
219 rec.selfWeight += node.selfWeight; 270 rec.selfWeight += node.selfWeight;
220 if (precs[node.label] == 0) { 271 if (precs[node.label] == 0) {
221 rec.totalWeight += node.totalWeight; 272 rec.totalWeight += node.totalWeight;
222 } 273 }
223 precs[node.label]++; 274 precs[node.label]++;
224 }, 275 },
225 function onExit(node) { 276 function onExit(node) {
226 precs[node.label]--; 277 precs[node.label]--;
227 }, 278 },
228 opt_root); 279 opt_root);
229 return counters.exportChildren(); 280 return counters;
230 }; 281 };
231 282
232 283
233 /** 284 /**
234 * Creates a dynamic code entry. 285 * Creates a dynamic code entry.
235 * 286 *
236 * @param {number} size Code size. 287 * @param {number} size Code size.
237 * @param {string} type Code type. 288 * @param {string} type Code type.
238 * @param {string} name Function name. 289 * @param {string} name Function name.
239 * @constructor 290 * @constructor
(...skipping 29 matching lines...) Expand all
269 }; 320 };
270 321
271 322
272 /** 323 /**
273 * @private 324 * @private
274 */ 325 */
275 devtools.profiler.CallTree.prototype.totalsComputed_ = false; 326 devtools.profiler.CallTree.prototype.totalsComputed_ = false;
276 327
277 328
278 /** 329 /**
330 * Returns the tree root.
331 */
332 devtools.profiler.CallTree.prototype.getRoot = function() {
333 return this.root_;
334 };
335
336
337 /**
279 * Adds the specified call path, constructing nodes as necessary. 338 * Adds the specified call path, constructing nodes as necessary.
280 * 339 *
281 * @param {Array<string>} path Call path. 340 * @param {Array<string>} path Call path.
282 */ 341 */
283 devtools.profiler.CallTree.prototype.addPath = function(path) { 342 devtools.profiler.CallTree.prototype.addPath = function(path) {
284 if (path.length == 0) { 343 if (path.length == 0) {
285 return; 344 return;
286 } 345 }
287 var curr = this.root_; 346 var curr = this.root_;
288 for (var i = 0; i < path.length; ++i) { 347 for (var i = 0; i < path.length; ++i) {
289 curr = curr.findOrAddChild(path[i]); 348 curr = curr.findOrAddChild(path[i]);
290 } 349 }
291 curr.selfWeight++; 350 curr.selfWeight++;
292 this.totalsComputed_ = false; 351 this.totalsComputed_ = false;
293 }; 352 };
294 353
295 354
296 /** 355 /**
356 * 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
358 * specified, uses tree root.
359 *
360 * @param {string} label Child node label.
361 */
362 devtools.profiler.CallTree.prototype.findOrAddChild = function(
363 label, opt_parent) {
364 var parent = opt_parent || this.root_;
365 return parent.findOrAddChild(label);
366 };
367
368
369 /**
297 * Computes total weights in the call graph. 370 * Computes total weights in the call graph.
298 */ 371 */
299 devtools.profiler.CallTree.prototype.computeTotalWeights = function() { 372 devtools.profiler.CallTree.prototype.computeTotalWeights = function() {
300 if (this.totalsComputed_) { 373 if (this.totalsComputed_) {
301 return; 374 return;
302 } 375 }
303 this.root_.computeTotalWeight(); 376 this.root_.computeTotalWeight();
304 this.totalsComputed_ = true; 377 this.totalsComputed_ = true;
305 }; 378 };
306 379
307 380
308 /** 381 /**
309 * Traverses the call graph in preorder. 382 * Traverses the call graph in preorder. This function can be used for
383 * building optionally modified tree clones. This is the boilerplate code
384 * for this scenario:
310 * 385 *
311 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 386 * callTree.traverse(function(node, parentClone) {
387 * var nodeClone = cloneNode(node);
388 * if (parentClone)
389 * parentClone.addChild(nodeClone);
390 * return nodeClone;
391 * });
392 *
393 * @param {function(devtools.profiler.CallTree.Node, *)} f Visitor function.
394 * The second parameter is the result of calling 'f' on the parent node.
312 * @param {devtools.profiler.CallTree.Node} opt_start Starting node. 395 * @param {devtools.profiler.CallTree.Node} opt_start Starting node.
313 */ 396 */
314 devtools.profiler.CallTree.prototype.traverse = function(f, opt_start) { 397 devtools.profiler.CallTree.prototype.traverse = function(f, opt_start) {
315 var nodesToVisit = [opt_start || this.root_]; 398 var pairsToProcess = [{node: opt_start || this.root_, param: null}];
316 while (nodesToVisit.length > 0) { 399 while (pairsToProcess.length > 0) {
317 var node = nodesToVisit.shift(); 400 var pair = pairsToProcess.shift();
318 f(node); 401 var node = pair.node;
319 nodesToVisit = nodesToVisit.concat(node.exportChildren()); 402 var newParam = f(node, pair.param);
403 node.forEachChild(
404 function (child) { pairsToProcess.push({node: child, param: newParam}); }
405 );
320 } 406 }
321 }; 407 };
322 408
323 409
324 /** 410 /**
325 * Performs an indepth call graph traversal. 411 * Performs an indepth call graph traversal.
326 * 412 *
327 * @param {function(devtools.profiler.CallTree.Node)} enter A function called 413 * @param {function(devtools.profiler.CallTree.Node)} enter A function called
328 * prior to visiting node's children. 414 * prior to visiting node's children.
329 * @param {function(devtools.profiler.CallTree.Node)} exit A function called 415 * @param {function(devtools.profiler.CallTree.Node)} exit A function called
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 labels, opt_f) { 545 labels, opt_f) {
460 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) { 546 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) {
461 var child = curr.findChild(labels[pos]); 547 var child = curr.findChild(labels[pos]);
462 if (opt_f) { 548 if (opt_f) {
463 opt_f(child, pos); 549 opt_f(child, pos);
464 } 550 }
465 curr = child; 551 curr = child;
466 } 552 }
467 return curr; 553 return curr;
468 }; 554 };
OLDNEW
« no previous file with comments | « test/mjsunit/tools/profileview.js ('k') | tools/profileview.js » ('j') | tools/profileview.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698