22
edits
No edit summary |
No edit summary |
||
| Line 20: | Line 20: | ||
<dd>Returns whether the specified object's global is being profiled or not by this instance. | <dd>Returns whether the specified object's global is being profiled or not by this instance. | ||
<dt>frame() | <dt>frame() | ||
<dd>Fetch the current | <dd>Fetch the current object instance representing the current stack trace of invocation for the invoking context's global. Properties can be added to this object and will be persisted across invocations of this method so long as each invocation has the same backtrace. If the invoking context's global is not being profiled by the <tt>Profiler</tt> instance, then an error is thrown | ||
<dt>info(object) | <dt>info(object) | ||
<dd>Returns | <dd>Returns all information profiled for the object's global given. The format of the information is described below | ||
<dt>clearInfo(object) | <dt>clearInfo(object) | ||
<dd>Removes all known frame instances for the given object's global. Throws an error if the global is not being profiled | <dd>Removes all known frame instances for the given object's global. Throws an error if the global is not being profiled | ||
| Line 30: | Line 30: | ||
</dl> | </dl> | ||
=== The return of <tt>.info()</tt> === | |||
== | The return value is an object which is a hash containing all the information. The hash can loosely be viewed as a trie. Here's some example code: | ||
profiler = new Profiler(); | |||
profiler.startProfiling(this); | |||
function b() { profiler.frame().b = true; } | |||
function a() { b(); profiler.frame().a = 4; } | |||
a(); | |||
profiler.info() // => { 'input.js:3 (a)': {a: 4, 'input.js:2 (b)': {b: true}}} | |||
With this structure, each "stack trace" has its own object which is persisted across invocations. Each object also has information about whatever children were invoked from it. | |||
=== Profiled Statistics === | === Profiled Statistics === | ||
| Line 116: | Line 119: | ||
* Biased, operational callbacks are only invoked at particular points in the code, so true line-by-line sampling is impossible. It is possible with signal-based sampling, but that has a large number of other issues with it. | * Biased, operational callbacks are only invoked at particular points in the code, so true line-by-line sampling is impossible. It is possible with signal-based sampling, but that has a large number of other issues with it. | ||
* Might still require some wonky code maybe? Not quite sure about this... | * Might still require some wonky code maybe? Not quite sure about this... | ||
==== Pseudocode ==== | |||
def Profiler.startProfiling(object) | |||
compartment = object.root.compartment | |||
compartment.setOperationCallback(sample, FREQ) | |||
compartment.root_node = {} | |||
def Profiler.isProfiling(object) ... | |||
def Profiler.stopProfling(object) | |||
compartment = object.root.compartment | |||
compartment.removeOperationCallback(sample) | |||
def Profiler.frame(object) | |||
compartment = object.root.compartment | |||
node = compartment.root_node | |||
for (frame in compartment.js_stack) | |||
if (node[frame] == NULL) | |||
node[frame] = new node(parent=node) | |||
node = node[frame.script] | |||
return node | |||
def Profiler.info(object) | |||
return object.root.compartment.root_node | |||
def Profiler.clearInfo(object) | |||
object.root.compartment.root_node.clear() | |||
def Profiler.sample(): | |||
compartment = this.upvalues.compartment | |||
node = compartment.root_node | |||
for (frame in compartment.js_stack) | |||
node2 = node[frame.str] | |||
if (node == NULL) | |||
node2 = new node(parent=node) | |||
node[frame.str] = node2 | |||
node = node2 | |||
node.ticks++ | |||
if (frame == compartment.js_stack.top) | |||
node.self_ticks++ | |||
=== Choice === | === Choice === | ||
edits