Javascript Profiling: Difference between revisions

no edit summary
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 <tt>Profiler.Frame</tt> 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(object)
<dt>info(object)
<dd>Returns an array of <tt>Profiler.Frame</tt> instances. Each instance is present for some internal event having been traced at that stack location, or the <tt>frame()</tt> method was called at that location
<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 Profiler.Frame object ==
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}}}


A <tt>Profiler.Frame</tt> object represents an event at a particular stack trace. An instance cannot be directly instantiated, but rather it is created through the profiler's <tt>frame()</tt> method.
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.
 
<dl>
<dt>stack
<dd>This attribute is a list of hashes with two keys: <tt>file</tt> and <tt>line</tt>. Each element in the array is the caller of the previous element. All <tt>Profiler.Frame</tt> instances are equivalent based on their stack traces. Some frames may be filtered out based on the permissions of the viewing context.
</dl>


=== 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 ===
22

edits