22
edits
No edit summary |
No edit summary |
||
| Line 15: | Line 15: | ||
<dd>The constructor takes no arguments | <dd>The constructor takes no arguments | ||
<dt>startProfiling() | <dt>startProfiling(obj, [sample_rate, [max_samples]]) | ||
<dd>Ensures that profiling has started. If | <dd>Ensures that profiling has started on the specified object's runtime. The sample rate and max samples are optional parameters which can tune how the profile is collected. | ||
<dt>isProfiling() | |||
<dd>Returns whether profiling is turned on | The sample rate is the time between samples of the call stack specified in microseconds (defaults to 1000 = 1ms). The sample rate is mostly a guideline as the platform being run might not guarantee the granularity of timing. Samples will not happen more frequently than the specified rate, but may occur more infrequently. | ||
A maximum number of samples can be specified as well, but the default is unlimited (0). If the maximum number of samples is reached, then the sample storage is treated as a ring buffer, discarding the oldest samples. | |||
If some other Profiler object is profiling the specified runtime, then an error is thrown if the sample rate or maximum sample count is different. Eventually a call to stopProfiling() must be paired with this call to cease data collection. | |||
<dt>isProfiling(obj) | |||
<dd>Returns whether profiling is turned on for the specified runtime | |||
<dt>frame() | <dt>frame() | ||
<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 | <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() | <dt>info(obj) | ||
<dd>Returns all profile information for the | <dd>Returns all profile information for the specified object's runtime. The data returned is all that is collected between the last invocation of clearInfo() and all the profile data. | ||
<dt>clearInfo() | <dt>clearInfo(obj) | ||
<dd>Removes all information stored | <dd>Removes all custom frame() information stored for the specified object's runtime. Also clears all profiling samples collected so far. | ||
<dt>stopProfiling() | <dt>stopProfiling(obj) | ||
<dd>Ceases profiling. This must only be called if a pairing call to startProfiling() has been made. | <dd>Ceases profiling on the specified runtime. This must only be called if a pairing call to startProfiling(obj) has been made. | ||
</dl> | </dl> | ||
| Line 34: | Line 40: | ||
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: | 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: | ||
// input.js | |||
var p = new Profiler(); | |||
function foo(n) { | |||
function | var sum = 0; | ||
for (var i = 0; i < n; i++) { | |||
sum += i; | |||
} | |||
var fac = 1; | |||
for (var i = 1; i < 2 * n; i++) { | |||
fac *= i; | |||
} | |||
return sum + fac; | |||
} | |||
function bar(n) { | |||
p.frame().one = 1; | |||
var info = p.frame(); | |||
info.two = 2; | |||
info.n = n; | |||
} | |||
p.startProfiling(p); | |||
foo(4000000); | |||
bar(200); | |||
p.stopProfiling(p); | |||
print(JSON.stringify(p.info(p))) | |||
And the following hash would be printed: | |||
{ | |||
ticks: 624, | |||
children: [ | |||
{ | |||
function: { file: 'input.js', line: 1 }, | |||
site: { file: 'input.js', line: 25 }, | |||
ticks: 624, | |||
children: [ | |||
{ | |||
function: { file: 'input.js', line: 1, name: 'foo' }, | |||
site: { file: 'input.js', line: 7 }, | |||
ticks: 195, | |||
self: 195 | |||
}, { | |||
function: { file: 'input.js', line: 1, name: 'foo' }, | |||
site: { file: 'input.js', line: 11 }, | |||
ticks: 429, | |||
self: 429 | |||
} | |||
] | |||
}, { | |||
function: { file: 'input.js', line: 1}, | |||
site: { file: 'input.js', line: 26}, | |||
children: [ | |||
{ | |||
function: { file: 'input.js', line: 18, name: 'bar' }, | |||
site: { file: 'input.js', line: 18 }, | |||
data: { one: 1 } | |||
}, { | |||
function: { file: 'input.js', line: 18, name: 'bar' }, | |||
site: { file: 'input.js', line: 19 }, | |||
data: { two: 2, n: 200 } | |||
} | |||
] | |||
} | |||
] | |||
} | |||
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. | 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. | ||
| Line 48: | Line 115: | ||
<dl> | <dl> | ||
<dt> | <dt>ticks | ||
<dd>This is an integer value of the | <dd>This is an integer value of the number of ticks while this function's frame was on the stack. This is useful when counting total time spent in a function. It should be true that: <tt>ticks = self + children.sum('ticks')</tt> | ||
<dt> | <dt>self | ||
<dd>This is a | <dd>This is an integer value like "ticks," but instead only counts the time spent in the function itself. When a sample is taken and a function is currently running (it's the top of the stack), it's self count is increased. | ||
<dt>gc | |||
<dd>This integer represents the number of times that garbage collection was invoked at the site | |||
<dt>compile | |||
<dd>This integer represents the number of times a function was compiled when invoked from this site. | |||
</dl> | </dl> | ||
edits