single-threaded JSRuntime

113 views
Skip to first unread message

Luke Wagner

unread,
Jul 14, 2011, 3:29:32 PM7/14/11
to
Right now (on SpiderMonkey tip), the capacity for multi-threading in a
JSRuntime is limited: a single compartment
(http://andreasgal.com/2010/10/13/compartments) can only be accessed by
a single thread at a time. What that means is that, although multiple
threads may concurrently run with the same JSRuntime, they must access a
disjoint set of objects. If multiple threads were to access the same
compartment (or anything contained in a compartment: object, script,
function, string) at the same time, this would be a race condition and
produce undefined behavior. (Unfortunately, I don't even think the
engine would catch such misuse in debug builds at the moment!)

Another issue is that currently compartmental GC waits on and blocks all
threads running in a JSRuntime. To achieve competitive web worker
performance on parallel workloads (e.g.,
https://bugzilla.mozilla.org/show_bug.cgi?id=617569), the Firefox
SpiderMonkey embedding resorted to using multiple runtimes
(https://bugzilla.mozilla.org/show_bug.cgi?id=649537).

Thus, on SpiderMonkey tip, multi-threading support in a single JSRuntime
is limited at best, dangerous and slow at worst. (The older, less
limited and more concurrent multi-threading strategy was removed,
providing a significant speedup and reduction in code complexity
(https://bugzilla.mozilla.org/show_bug.cgi?id=606029).)

I'm proposing (and have been working in
https://bugzilla.mozilla.org/show_bug.cgi?id=650411) to make JSRuntime
single-threaded. This bug is nearing completion, but it is still
probably a week or more from potentially landing.

For embeddings that are correctly (in theory, at least :) using
compartments in a single-threaded manner, this is not a significant
change. For example, after the runtime-per-web-worker change, there
were only a few loose ends to fix up in Mozilla (some of which were
pre-existing potential threading bugs only caught by the new, stronger
assertions).

From a JSAPI-usage perspective, this change mostly translates to
creating more JSRuntimes (at least one per thread that wants to run JS).
Most other use should stay the same. See
https://bugzilla.mozilla.org/show_bug.cgi?id=650411 for discussion on
topics such as resource usage and script sharing in server embeddings.

This new single-threaded model makes it easy for SpiderMonkey to assert
correct single-threaded use which should benefit multi-threaded
embeddings that may have been using compartments incorrectly.

Internal to SpiderMonkey, this is a massive simplification. I have
removed at least 600 lines of complex multi-threaded code so far and
there is much more to go. Although requests and most aspects of locking
have been optimized on hot paths, this ultimately should yield speedup
when code does a lot of: context creation/destruction, request
entering/exiting, and GC.

Lastly, this bug enables important future SpiderMonkey improvements (see
dependency tree in bug). From a JSAPI perspective, one benefit will be
removing the currently-required request model (this change will be saved
for a followup bug since there are some subtle interactions with
conservative stack marking and other parts of the VM that probably
require Igor's delicate touch).

Questions, comments, suggestions welcome

Nicholas Nethercote

unread,
Jul 14, 2011, 9:21:28 PM7/14/11
to Luke Wagner, dev-tech-...@lists.mozilla.org
On Fri, Jul 15, 2011 at 5:29 AM, Luke Wagner <lu...@mozilla.com> wrote:
>
> I'm proposing (and have been working in
> https://bugzilla.mozilla.org/show_bug.cgi?id=650411) to make JSRuntime
> single-threaded.  This bug is nearing completion, but it is still probably a
> week or more from potentially landing.

Does this affect memory consumption of Firefox? Or will that happen
with subsequent changes?

Do we still have a single JSRuntime in Firefox? (Hmm, do we have a
single JSRuntime now? I had an idea that web workers got their own
JSRuntime, but maybe that's a planned change.)

Thanks!

Nick

Wes Garland

unread,
Jul 14, 2011, 10:31:59 PM7/14/11
to Luke Wagner, dev-tech-...@lists.mozilla.org
Hi, Luke!

This sounds like a real win from my POV.

Question:

I have an embedding with lots of blocking I/O; cx gets suspended around
blocking I/O, and JS_MaybeGC() runs regularly on another thread.

I haven't measured, but I believe this means that a lot of my GC runs when
the main thread is blocked for I/O.

Does the new model still allow for suspending/resuming
contexts^H^H^H^H^H^H^H^Hthreads like this? Or will the GC rendezvous wait
until the thread is in JS or joins?

I've been assuming thus far that we keep begin/suspend/resume/end request
for purposes of GC synchronization, eliminating all the MT prop access, but
your post sounds like you may want to go a step further.

Wes

--
Wesley W. Garland
Director, Product Development
PageMail, Inc.
+1 613 542 2787 x 102

Slava

unread,
Jul 15, 2011, 7:12:27 AM7/15/11
to
Would it be possible to eliminate dependency on NSPR after this patch
is landed?

Thanks,
Slava

Luke Wagner

unread,
Jul 15, 2011, 11:57:39 AM7/15/11
to Nicholas Nethercote, dev-tech-...@lists.mozilla.org

> Does this affect memory consumption of Firefox? Or will that happen
> with subsequent changes?
This patch, not at all. Bug 649537 (about to be landed) gives a runtime
per web-worker. FWIW, if measured web workloads demonstrate high
resource usage we can reuse (thread,runtime) pairs to service multiple
workers. Also, bug 668915 may need to add an additional runtime for the
IndexedDB thread.

The potentially resource-consumption-changing bug is 650353
(compartment-per-global). The plan to minimize the impact on
resource-consumption is to hoist stuff out of the compartment into the
newly-singled-threaded JSRuntime, hence this bug. (It may be a net win
since there will be less JSRuntimes than per-domain compartments;
depends on the size of hoisted stuff vs. per-compartment stuff.)


> Do we still have a single JSRuntime in Firefox? (Hmm, do we have a
> single JSRuntime now? I had an idea that web workers got their own
> JSRuntime, but maybe that's a planned change.)

Nope, multiple runtimes. Note: there is still a single 'main thread
runtime' -- the one that all content JS and DOM objects live in, the one
associated with the XPConnect runtime singleton, etc.

Luke Wagner

unread,
Jul 15, 2011, 12:14:28 PM7/15/11
to Wes Garland, dev-tech-...@lists.mozilla.org
Hi Wes,

That is an excellent question and a great use case; doing GC while you
are doing blocking I/O sounds like a good thing to do.

Based on the simplest model of single-threaded-JSRuntime, it would be
illegal to call JS_MaybeGC(cx) on a thread different than cx->runtime's
owner thread.

The initial solution to doing this without engine support is to put the
slow IO operation on a different thread:

NativeCalledFromJS(cx, ...) {
// enqueue slow IO operation on IO thread
JS_MaybeGC(cx);
// wait on slow IO operation to complete
}

Problems I can think of would be if the IO operations were often really
fast (but unpredictably so) so that queuing/synchronization was costly.

What do you think?

Wes Garland

unread,
Jul 15, 2011, 12:48:33 PM7/15/11
to lu...@mozilla.com, dev-tech-...@lists.mozilla.org
On 15 July 2011 12:14, Luke Wagner <lu...@mozilla.com> wrote:

>
> Problems I can think of would be if the IO operations were often really
> fast (but unpredictably so) so that queuing/synchronization was costly.
>
> What do you think?
>
>

Re-tooling costs would be high enough that I would just lose the ability to
GC-while-blocked. We also don't have data on how long a given blocking
operation would take -- we treat reading a file over internet-tunnelled-NFS
the same as acquiring a lock on a local disk or printing to stdout.

Loosing GC-while-blocked may or may not be a huge problem, it's really tough
to say when I'm thinking about the framework but it's the perf of the apps
under load that really matter long-term. Who knows; it's possible that these
changes make up any gains we get with these "opportunistic" GCs.

You know, if there was a way to hand off the JSRuntime to a different
thread, and that way was cheap, that would work - you could hand off the JS
runtime to a maybe-GC thread where we currently JS_SuspendRequest().

How difficult/expensive this is probably dependent on how the JS engine uses
TLS. If it's indexed through a single pointer, it should be possible
without major pain, but might impact the ST use-case.

Nicholas Nethercote

unread,
Jul 15, 2011, 5:34:37 PM7/15/11
to lu...@mozilla.com, dev-tech-...@lists.mozilla.org
On Sat, Jul 16, 2011 at 1:57 AM, Luke Wagner <lu...@mozilla.com> wrote:
>
> This patch, not at all.  Bug 649537 (about to be landed) gives a runtime per
> web-worker.  FWIW, if measured web workloads demonstrate high resource usage
> we can reuse (thread,runtime) pairs to service multiple workers.  Also, bug
> 668915 may need to add an additional runtime for the IndexedDB thread.

Ok. I'm not too worried about web workers, because they're still not
common AFAIK.

> The potentially resource-consumption-changing bug is 650353
> (compartment-per-global).  The plan to minimize the impact on
> resource-consumption is to hoist stuff out of the compartment into the
> newly-singled-threaded JSRuntime, hence this bug.  (It may be a net win
> since there will be less JSRuntimes than per-domain compartments; depends on
> the size of hoisted stuff vs. per-compartment stuff.)

Thanks for the explanation. That sounds reasonable, and I'm glad to
hear that memory consumption is front and centre among your
considerations :)

N

Luke Wagner

unread,
Jul 18, 2011, 5:46:47 PM7/18/11
to Slava

Good question. As much as pbiggar and I would like to remove the
dependency, NSPR will still be used to manage the threads involved in
parallel marking and background sweeping. In general, I would expect
the JS engine to continue to use (internal, controlled) concurrency to
improve performance on multi-core systems.

Sebastien Marinier

unread,
Jul 19, 2011, 4:41:08 PM7/19/11
to
Hy,

As I've added a thread object in my SpiderMonkey implements, this is a
blocking issue for me. I can understand your point of view, but this
could at least be handled by #define/#ifdef.

Thanks.

Le 14/07/11 21:29, Luke Wagner a écrit :


> Right now (on SpiderMonkey tip), the capacity for multi-threading in a
> JSRuntime is limited: a single compartment
> (http://andreasgal.com/2010/10/13/compartments) can only be accessed by
> a single thread at a time. What that means is that, although multiple
> threads may concurrently run with the same JSRuntime, they must access a
> disjoint set of objects. If multiple threads were to access the same
> compartment (or anything contained in a compartment: object, script,
> function, string) at the same time, this would be a race condition and
> produce undefined behavior. (Unfortunately, I don't even think the
> engine would catch such misuse in debug builds at the moment!)
>

> [...]
> Questions, comments, suggestions welcome

Igor Bukanov

unread,
Jul 21, 2011, 8:05:00 AM7/21/11
to Luke Wagner, dev-tech-...@lists.mozilla.org
On 14 July 2011 21:29, Luke Wagner <lu...@mozilla.com> wrote:
> Thus, on SpiderMonkey tip, multi-threading support in a single JSRuntime is
> limited at best, dangerous and slow at worst.

Strictly speaking this is not true. On the tip the runtime is
perfectly capable of running JS on multiple threads including the GC
invocations. What was removed is the possibility to share a standard
JSObject between threads. An embedding still can expose its native
thread-shared data to the different threads using different objects.

What is proposed is the removal of the possibility to run the GC that
can properly synchronize across multiple threads as FF would not need
it for web workers soon.

> From a JSAPI perspective, one benefit will be
> removing the currently-required request model (this change will be saved for
> a followup bug since there are some subtle interactions with conservative
> stack marking

>From the conservative GC point of view the ideal situation would be if
any API that works with GC things is invoked only from a callback
like:

JS_Run(cx, callback, callback_arg).

This way the conservative GC can accurately calculate the stack bounds
and access the stack that is only inside the callback. Currently
BeginRequest/EndRequest is hacked to for that purpose, but that is not
ideal.

Luke Wagner

unread,
Jul 21, 2011, 11:28:06 AM7/21/11
to Igor Bukanov, dev-tech-...@lists.mozilla.org
On 07/21/2011 05:05 AM, Igor Bukanov wrote:
> On 14 July 2011 21:29, Luke Wagner<lu...@mozilla.com> wrote:
>> Thus, on SpiderMonkey tip, multi-threading support in a single JSRuntime is
>> limited at best, dangerous and slow at worst.
>
> Strictly speaking this is not true. On the tip the runtime is
> perfectly capable of running JS on multiple threads including the GC
> invocations. What was removed is the possibility to share a standard
> JSObject between threads. An embedding still can expose its native
> thread-shared data to the different threads using different objects.

Yes, not being able to share a single JSObject across multiple threads
is what I meant by "limited" since, as you know, this was originally
supported.

Luke Wagner

unread,
Jul 21, 2011, 11:28:06 AM7/21/11
to Igor Bukanov, dev-tech-...@lists.mozilla.org
On 07/21/2011 05:05 AM, Igor Bukanov wrote:
> On 14 July 2011 21:29, Luke Wagner<lu...@mozilla.com> wrote:
>> Thus, on SpiderMonkey tip, multi-threading support in a single JSRuntime is
>> limited at best, dangerous and slow at worst.
>
> Strictly speaking this is not true. On the tip the runtime is
> perfectly capable of running JS on multiple threads including the GC
> invocations. What was removed is the possibility to share a standard
> JSObject between threads. An embedding still can expose its native
> thread-shared data to the different threads using different objects.

Yes, not being able to share a single JSObject across multiple threads

Alta27Roy

unread,
Feb 3, 2012, 8:41:29 AM2/3/12
to
freelance writer


Reply all
Reply to author
Forward
0 new messages