Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Tracing execution

74 views
Skip to first unread message

Olivier Lefevre

unread,
Jul 28, 2011, 2:48:15 PM7/28/11
to
How difficult would it be to add functionality to SpiderMonkey
to trace JS execution, for use within the Web Console or Firebug
Console? There are various hacks to do this in JS but they are
awkward and the JS engine looks like the logical place to do it.

Thanks,

-- O.L.

Mike Shaver

unread,
Jul 28, 2011, 2:56:12 PM7/28/11
to Olivier Lefevre, dev-tech-...@lists.mozilla.org

What would you want to trace, exactly? Can you give a small script
and an example of the sort of output you'd want?

Mike

Olivier Lefevre

unread,
Jul 28, 2011, 3:11:13 PM7/28/11
to
On 7/28/2011 8:56 PM, Mike Shaver wrote:
> What would you want to trace, exactly? Can you give a small script
> and an example of the sort of output you'd want?

I'd just like to have a printout (properly indented) of every JS
function executed as a result of a user input, e.g., a click on the
page. With things like addEventListener adding functions to a page in
such a way that you can't retrieve them after the fact (no corresponding
getEventListener), scripts rewriting or augmenting the DOM at load time
etc it's really hard to figure out what really happens.

I cannot give "a small script": if this were my own code I wouldn't
need to trace it. I want to gain some insight into third-party web
sites with complicated JS on them.

-- O.L.

Mike Shaver

unread,
Jul 28, 2011, 3:27:02 PM7/28/11
to Olivier Lefevre, dev-tech-...@lists.mozilla.org

Well, you don't need to give a real world example to demonstrate what
you want done. Imagine writing a test case for the feature, to make
sure it did what you want.

Would this be a small script that is a good example?

function f() { }
function g() { f(); }

document.addEventListener("click", function () { f(); g(); });

anonymous
-> f
-> g
----> f

?

Mike

Jens Ayton

unread,
Jul 28, 2011, 7:26:35 PM7/28/11
to dev-tech-...@lists.mozilla.org

Unless it has been removed since FF4, this already exists as a compile-time option, MOZ_TRACE_JSCALLS, which allows an embedding to register a per-context "function callback". The callback is invoked whenever a function is entered or exited. My embedding uses this to implement call trace and profiling functionality.

I presume it's a compile-time option because of the necessary overhead, at least when interpreting, although when compiling the cost shouldn't have to be more than an easily-predicted if when the facility isn't being used.


--
Jens Ayton

Olivier Lefevre

unread,
Jul 29, 2011, 10:34:57 AM7/29/11
to
> Would this be a small script that is a good example?
>
> function f() { }
> function g() { f(); }
>
> document.addEventListener("click", function () { f(); g(); });
>
> anonymous
> -> f
> -> g
> ----> f
>
> ?

Yes, that is what I meant, with full path info for named functions
and the actual definition for anonymous ones.

-- O.L.

Olivier Lefevre

unread,
Jul 29, 2011, 10:37:52 AM7/29/11
to
On 7/29/2011 1:26 AM, Jens Ayton wrote:
> Unless it has been removed since FF4, this already exists as a compile-time option, MOZ_TRACE_JSCALLS, which allows an embedding to register a per-context "function callback". The callback is invoked whenever a function is entered or exited. My embedding uses this to implement call trace and profiling functionality.

I thought it might already exist, indeed. Is this what the tracing
flag of the Mozilla Javascript shell is about? See here:
https://developer.mozilla.org/en/introduction_to_the_javascript_shell

-- O.L.

Steve Fink

unread,
Jul 29, 2011, 8:35:15 PM7/29/11
to Jens Ayton, dev-tech-...@lists.mozilla.org

It's still there. Put

ac_add_options --enable-trace-jscalls

in your mozconfig, then see

https://developer.mozilla.org/en/SpiderMonkey/JSAPI_Reference/JS_SetFunctionCallback

You're correct about the reasoning for the compile-time option. It was
judged to be too much overhead for the interpreter. For the JITs, if it
is unused then it's only a quick check during compilation; the generated
JIT code doesn't change. If it *is* used, the JIT code is deoptimized a
fair amount. (But you'll still be JITted, unlike eg debug mode which
will disable the tracer entirely.)

Note that it doesn't have the magic interlocking that things like debug
mode have, so if you set a callback after something has already been
JITted, you won't immediately start seeing all calls. You'll see calls
from the interpreter, and calls for the subset of scripts that happen to
have been JITted, which will change over time (we sometimes throw out
and recompiled JIT code.) This is technically a bug, but given that it's
a compile-time option and most users will install a callback immediately
after context creation, it shouldn't matter too much.

In its current state, this is not all that useful for the Web or Firebug
Consoles, because of the compilation flag. I would guess that jsdbg2's
debug mode will be the way to implement that functionality in the
nearish future.

Steve Fink

unread,
Jul 29, 2011, 8:35:15 PM7/29/11
to Jens Ayton, dev-tech-...@lists.mozilla.org
On 07/28/2011 04:26 PM, Jens Ayton wrote:

It's still there. Put

Olivier Lefevre

unread,
Aug 1, 2011, 7:14:51 PM8/1/11
to
Yes this is what I was looking for but how would you invoke it from JS?
This is a C-level facility. I guess you need to add a corresponding top-
level method (i.e., in the global object) to the JS language. Is there
a tutorial somewhere on how to do that in SpiderMonkey?

-- O.L.

Donny Viszneki

unread,
Aug 2, 2011, 10:59:46 AM8/2/11
to Olivier Lefevre, dev-tech-...@lists.mozilla.org
In the Script tab of Firebug, you can "break on next." That halts
Javascript execution as soon as the next event fires.

In other tabs there are other "break on .." buttons that do different things.

Unfortunately something like a short setInterval() can really
interrupt you if what you want to do is catch a mouse click. Best way
to deal with that is anyone's guess.

> _______________________________________________
> dev-tech-js-engine mailing list
> dev-tech-...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-tech-js-engine
>

--
http://codebad.com/

Miles

unread,
Aug 3, 2011, 11:37:01 AM8/3/11
to
> You're correct about the reasoning for the compile-time option. It was
> judged to be too much overhead for the interpreter. For the JITs, if it
> is unused then it's only a quick check during compilation; the generated
> JIT code doesn't change. If it *is* used, the JIT code is deoptimized a
> fair amount. (But you'll still be JITted, unlike eg debug mode which
> will disable the tracer entirely.)

I've been following this thread with interest.
I've been developing a basic debugger for our application which embeds
Spidermonkey (I've just upgraded to Spidermonkey 1.8.5) and I've been
pondering if it would be possible to also create a profiler.
This looks like it fits the bill perfectly.
I just want to confirm my understanding of this. Can anyone confirm/
correct the following which is what I *think* is possible?

1. I can trace function entering/leaving by using
JS_SetFunctionCallback to register a hook but to do that I would have
to recompile Spidermonkey with MOZ_TRACE_JSCALLS defined.
2. If it is used performance will be hit but JIT is still active
3. If it is NOT used there there is no effect on performance (well
negligable anyway). The last thing I want to do is to slow down
scripts if the profiler is not being used.
4. This is not possible if the script is in debug mode (by calling
JS_SetRuntimeDebugMode and JS_SetDebugMode) as the tracer is disabled?
That's how I interpret the previous post. Is that correct?
If so is there any other way of doing it? If not, it doesn't matter.
I'm happy to have to run the 'profiler' separately from a 'debugger'.
I'm just curious.

Miles

Olivier Lefevre

unread,
Aug 5, 2011, 1:08:31 PM8/5/11
to
On 8/2/2011 4:59 PM, Donny Viszneki wrote:
> In the Script tab of Firebug, you can "break on next." That halts
> Javascript execution as soon as the next event fires.

Thanks but I find heavy use of the debugger mind-numbing. I would
much rather look at a nice printout of traces.

-- O.L.

Steve Fink

unread,
Aug 16, 2011, 2:44:33 PM8/16/11
to Olivier Lefevre, dev-tech-...@lists.mozilla.org

Sorry, this mechanism is not accessible via JS. It cannot call out to JS
code because that would interfere with execution too much. (It would
force us to maintain consistent internal state, which would defeat the
purpose of the feature.) If you want something accessible from JS,
you'll currently need to use JSD, which will disable the tracing JIT and
have a small performance impact on the method JIT. (But getting a
callback for every function call is already going to have a fairly high
perf impact, even if your callback does very little.)

There is also the jsdbg2 API that just landed -
https://wiki.mozilla.org/Debugger

It will probably end up with similar characteristics as JSD, and I don't
think it's exposed quite yet. (See bug 679031.)

Steve Fink

unread,
Aug 16, 2011, 2:58:17 PM8/16/11
to Miles, dev-tech-...@lists.mozilla.org
On 08/03/2011 08:37 AM, Miles wrote:
>> You're correct about the reasoning for the compile-time option. It was
>> judged to be too much overhead for the interpreter. For the JITs, if it
>> is unused then it's only a quick check during compilation; the generated
>> JIT code doesn't change. If it *is* used, the JIT code is deoptimized a
>> fair amount. (But you'll still be JITted, unlike eg debug mode which
>> will disable the tracer entirely.)
>
> I've been following this thread with interest.
> I've been developing a basic debugger for our application which embeds
> Spidermonkey (I've just upgraded to Spidermonkey 1.8.5) and I've been
> pondering if it would be possible to also create a profiler.
> This looks like it fits the bill perfectly.
> I just want to confirm my understanding of this. Can anyone confirm/
> correct the following which is what I *think* is possible?
>
> 1. I can trace function entering/leaving by using
> JS_SetFunctionCallback to register a hook but to do that I would have
> to recompile Spidermonkey with MOZ_TRACE_JSCALLS defined.

If by "function" you mean "Javascript function", then yes. It won't
track calls to native code. (Actually, what's currently there might get
a couple of them, but claim them to be the calling JS function. I can't
remember the current state.)

The easiest way to get MOZ_TRACE_JSCALLS defined is to configure with
--enable-trace-jscalls

> 2. If it is used performance will be hit but JIT is still active

Yes, though the implication that the JIT will be inactive using another
approach, namely JSD, is not entirely correct -- JSD disables the
tracing JIT, but only slightly slows down the method JIT.

> 3. If it is NOT used there there is no effect on performance (well
> negligable anyway). The last thing I want to do is to slow down
> scripts if the profiler is not being used.

I confess I haven't measured it, but I expected it to induce enough of a
slowdown that I hid it behind MOZ_TRACE_JSCALLS. If there were really no
impact, I would just have it available by default.

Still, I'd be surprised if it were more than a few percentage points.

> 4. This is not possible if the script is in debug mode (by calling
> JS_SetRuntimeDebugMode and JS_SetDebugMode) as the tracer is disabled?
> That's how I interpret the previous post. Is that correct?
> If so is there any other way of doing it? If not, it doesn't matter.
> I'm happy to have to run the 'profiler' separately from a 'debugger'.
> I'm just curious.
>
> Miles
>

If I am understanding correctly, then no, this is not correct. The
JS_SetFunctionCallback callback will still fire when in debug mode. Or
it's supposed to, at least. (There's been at least one bug in that.)

You are correct that the tracer will be disabled, but
JS_SetFunctionCallback hooks into the interpreter and both JITs separately.

I am working on a couple of other routes to get profiling for JS. One is
bug 642054, which is probably exactly what you want -- a profiler for
JS. But it's further out. I'm also exposing JIT information to various
external native profilers, so you can tell what JS function is executing
in their outputs -- oprofile, vtune, shark, callgrind, etc. Which isn't
quite what you want, since (1) it only gives the JS function name of the
youngest JS stack frame, not the whole JS stack, and (2) it ironically
gives better information for JITted code than interpreted code because
the interpreted code just shows up as JS_Execute or whatever.

But none of that's done yet. For now, I think you're going down the
right route.

Olivier Lefevre

unread,
Aug 16, 2011, 3:37:44 PM8/16/11
to
On 8/16/2011 8:44 PM, Steve Fink wrote:
> Sorry, this mechanism is not accessible via JS. It cannot call out to JS code because that would interfere with execution too much. (It would force us to maintain consistent internal state, which would defeat the purpose of the feature.)

Wrt. calling out to JS my wish was very modest: I just wanted a way to turn tracing on and off from JS.

-- O.L.

David Rees

unread,
Aug 24, 2011, 10:36:10 AM8/24/11
to

I assume you could write your tracing in C and then just expose an XPC
interface to JS to turn it on/off, right? If there are threading
concerns, you can mutex around setting that variable. Then the C side
when the variable changes you can register or unregister the callback.

d

0 new messages