Another request for multiple threads running multiple V8 scripts in one process

167 views
Skip to first unread message

krovosos

unread,
Sep 10, 2009, 2:51:21 PM9/10/09
to v8-users
Hello,

we are currently using V8 in a kind of server-side scripting engine.
Javascript is used for implementing business-level logic. V8 is nice,
really! It is fast and well structured. But... Suppose we want to run
a 1000+ small scripts simultaneosly. How can we achieve this? Run
1000+ processes like Chrome do? Well, not a smart idea. So we have a
single process with 1000+ V8 contexts and there can be only one script
running in V8 at the moment. If it is somehow slow we are stuck,
others are waiting.

I truly understand that V8 is destinied for client-side scripting in
Chrome. No doubt! But is adding multi-thread execution of code is very
very hard? Context are indepent, right? Let's say we compile
javascript code still in one-thread model. What about running already
generated code? Let's say there's no eval() in it. I didn't sink into
V8 source codes deeply and perhaps I don't understand a lot of its
architecture. But still script has it's (already built) context,
script has it's (already built) code, script has it's execution stack.
What is shared? Some internal routines with memory managment? Let's
say we put a simple mutex on access to memory managment routines. Is
there anything else V8 should do to start running multiple scripts at
the same time in one process?

Is it so hard to add some kind of C++ definition MULTIPLE_THREADS to
V8 source code and start locking not on the scripts-running-level, but
on internal-management-routine level?

I think lot's of people using V8 in similar projects would appreciate
this.

Thank you,
G.

Erik Corry

unread,
Sep 10, 2009, 3:09:54 PM9/10/09
to v8-u...@googlegroups.com
2009/9/10 krovosos <ggrig...@gmail.com>:

>
> Hello,
>
> we are currently using V8 in a kind of server-side scripting engine.
> Javascript is used for implementing business-level logic. V8 is nice,
> really! It is fast and well structured. But... Suppose we want to run
> a 1000+ small scripts simultaneosly. How can we achieve this? Run
> 1000+ processes like Chrome do? Well, not a smart idea. So we have a
> single process with 1000+ V8 contexts and there can be only one script
> running in V8 at the moment. If it is somehow slow we are stuck,
> others are waiting.

I appreciate this is annoying, but it's not actually that easy. The
contexts are not really independent at the VM level. The
single-threaded assumption is in 1000 undocumented places in the code.

Let me suggest some workarounds. I am guessing that you don't have
1000 CPUs. So it might be possible to have one or two V8 processes
per CPU, then a load balancer that distributes incoming requests to V8
proceses. If you run with preemption support you can switch between
V8 threads if one thread gets into a long calculation. If your V8
threads are hanging because they are doing long-running IO then you
can use the v8::Unlocker class to free up the V8 lock while IO takes
place.

--
Erik Corry, Software Engineer
Google Denmark ApS. CVR nr. 28 86 69 84
c/o Philip & Partners, 7 Vognmagergade, P.O. Box 2227, DK-1018
Copenhagen K, Denmark.

krovosos

unread,
Sep 10, 2009, 4:47:10 PM9/10/09
to v8-users


> > we are currently using V8 in a kind of server-side scripting engine.
> > Javascript is used for implementing business-level logic. V8 is nice,
> > really! It is fast and well structured. But... Suppose we want to run
> > a 1000+ small scripts simultaneosly. How can we achieve this? Run
> > 1000+ processes like Chrome do? Well, not a smart idea. So we have a
> > single process with 1000+ V8 contexts and there can be only one script
> > running in V8 at the moment. If it is somehow slow we are stuck,
> > others are waiting.
>
> I appreciate this is annoying, but it's not actually that easy.  The
> contexts are not really independent at the VM level.  The
> single-threaded assumption is in 1000 undocumented places in the code.
>

Well, isn't that a great adventure - find them all?! Build a better
structured code? :-)

Ok, just kidding, I understand your point but I was thinking of...
well...
Of not 1000 very-local-locks, but 10 not-so-global locks.
Locks that lock big parts but anyway allow to keep running several
scripts. All we need is not stopping others forever.

If threads would spend 10% their time waiting
on those not-so-global-locks that's okay anyway, because they now
run on 4 CPU instead of 1 (for example).

> Let me suggest some workarounds.  I am guessing that you don't have
> 1000 CPUs.  So it might be possible to have one or two V8 processes
> per CPU, then a load balancer that distributes incoming requests to V8
> proceses.  If you run with preemption support you can switch between
> V8 threads if one thread gets into a long calculation.  If your V8
> threads are hanging because they are doing long-running IO then you
> can use the v8::Unlocker class to free up the V8 lock while IO takes
> place.

Well, several processes is a some sort of solution. But it's not an
easy solution.
IPC comes in place, load balancing, something else. It's a solution if
nothing else helps :-)


You are saying that I can do V8::unlock inside the C++ function that
was called from JS if this C++ function not interfere with V8? Hmm...

That's interesting. I use SQLITE embedded in V8 script and if I can
run V8 while SQLITE is doing his job it's some sort of optimization...

What if this C++ function has to call another V8 function in turn (so
the stack is JS-function C++-function JS-function)?
I need to V8::Lock again before javascript-function call?


void foo()
{
v8::Locker locker;
some_code.Run(); // this javascript code calls cpp_foo ()
// release lock on destructor call
}

Handle<Value> cpp_foo(const Arguments& args) // called from V8
{
string abc = to_string(args[0]);


{
// okay, since this moment let's forget about V8
v8::Unlocker unlocker;
sqlengine.execute(abc);
} // release unlock on destructor call

// now I can again use V8? And I can run another javascript code?

some_else_code.Run();

}

Is this right?


Thanks for your help and fast reply, anyway.

Erik Corry

unread,
Sep 11, 2009, 4:39:45 AM9/11/09
to v8-u...@googlegroups.com
2009/9/10 krovosos <ggrig...@gmail.com>:

Yes, you need a new V8::Locker. Alternating V8::Locker and
V8::Unlockers can be stacked up on the stack.

> void foo()
> {
>   v8::Locker locker;
>   some_code.Run(); // this javascript code calls cpp_foo ()
> //  release lock on destructor call
> }
>
> Handle<Value> cpp_foo(const Arguments& args) // called from V8
> {
>   string abc = to_string(args[0]);
>
>
>   {
>  // okay, since this moment let's forget about V8
>      v8::Unlocker unlocker;
>      sqlengine.execute(abc);
>   } // release unlock on destructor call
>
> // now I can again use V8?  And I can run another javascript code?
>
>  some_else_code.Run();
>
> }
>
> Is this right?


This all looks right. If you use v8::Locker anywhere you have to use
it everywhere, so the some_else_code.Run() must also be in a
v8::Locker scope.

Stephan Beal

unread,
Sep 11, 2009, 4:44:04 AM9/11/09
to v8-u...@googlegroups.com
On Fri, Sep 11, 2009 at 10:39 AM, Erik Corry <erik....@gmail.com> wrote:
2009/9/10 krovosos <ggrig...@gmail.com>:> void foo()
> {
>   v8::Locker locker;
>   some_code.Run(); // this javascript code calls cpp_foo ()
> //  release lock on destructor call
> }
>
> Handle<Value> cpp_foo(const Arguments& args) // called from V8
> {
>   string abc = to_string(args[0]);
... 
>  some_else_code.Run();
>
> }
>

This all looks right.  If you use v8::Locker anywhere you have to use
it everywhere, so the some_else_code.Run() must also be in a
v8::Locker scope.

Isn't that implicit here, because some_else_code() is triggered by cpp_foo(), which uses the Locker? Or do we really need one locker per function?

--
----- stephan beal
http://wanderinghorse.net/home/stephan/

Erik Corry

unread,
Sep 11, 2009, 4:48:44 AM9/11/09
to v8-u...@googlegroups.com
2009/9/11 Stephan Beal <sgb...@googlemail.com>:

> On Fri, Sep 11, 2009 at 10:39 AM, Erik Corry <erik....@gmail.com> wrote:
>>
>> 2009/9/10 krovosos <ggrig...@gmail.com>:> void foo()
>> > {
>> >   v8::Locker locker;
>> >   some_code.Run(); // this javascript code calls cpp_foo ()
>> > //  release lock on destructor call
>> > }
>> >
>> > Handle<Value> cpp_foo(const Arguments& args) // called from V8
>> > {
>> >   string abc = to_string(args[0]);
>> ...
>>
>> >  some_else_code.Run();
>> >
>> > }
>> >
>>
>> This all looks right.  If you use v8::Locker anywhere you have to use
>> it everywhere, so the some_else_code.Run() must also be in a
>> v8::Locker scope.
>
> Isn't that implicit here, because some_else_code() is triggered
> by cpp_foo(),

Yes, you are right. I wasn't paying attention to the braces.

ryan dahl

unread,
Sep 11, 2009, 7:56:56 AM9/11/09
to v8-u...@googlegroups.com
On Thu, Sep 10, 2009 at 8:51 PM, krovosos <ggrig...@gmail.com> wrote:
>
> we are currently using V8 in a kind of server-side scripting engine.
> Javascript is used for implementing business-level logic. V8 is nice,
> really! It is fast and well structured. But... Suppose we want to run
> a 1000+ small scripts simultaneosly. How can we achieve this? Run
> 1000+ processes like Chrome do? Well, not a smart idea. So we have a
> single process with 1000+ V8 contexts and there can be only one script
> running in V8 at the moment. If it is somehow slow we are stuck,
> others are waiting.

You can checkout node (http://tinyclouds.org/node) which can do
concurrent I/O on V8.

krovosos

unread,
Sep 11, 2009, 4:06:07 PM9/11/09
to v8-users
I think I found some idea... Well, some way of solving the problem of
v8 one-at-a-time model...

To be short:

Handle<Value> yield(const Arguments& args)
{
v8::Unlocker unlocker;
Sleep(5); // for example
// or even Sleep(0) just to give away control of v8 mutex
}


So suppose I have a long-running script.
And it calls this function from time to time inside the depth of its
loop.
Or maybe every iteration if speed if not an issue for this long-
running in background thread.
Than other scripts in different threads can still run? Am I right?



krovosos

unread,
Sep 11, 2009, 4:07:41 PM9/11/09
to v8-users
Thank you, that's interesting.

Stephan Beal

unread,
Sep 11, 2009, 6:01:41 PM9/11/09
to v8-u...@googlegroups.com
On Fri, Sep 11, 2009 at 10:06 PM, krovosos <ggrig...@gmail.com> wrote:
Handle<Value> yield(const Arguments& args)
{
  v8::Unlocker unlocker;
  Sleep(5); // for example
// or even Sleep(0) just to give away control of v8 mutex
}


Don't use the word "yield" - if i'm not mistaken it is a reserved word for potential future use in the JS language.

Or maybe every iteration if speed if not an issue for this long-
running in background thread.
Than other scripts in different threads can still run? Am I right?

Coincidentally (and inspired by Ryan's post, above), i just (over the past few hours) implemented setTimeout() for v8 and to test it i implemented sleep() using the approach you just used. Thus, it appears that the answer to your question is Yes. That said, i haven't tried running several contexts, only a few threads within a single context.

My sleep() impl looks like:

    v8::Handle<v8::Value> sleep(const v8::Arguments& argv)
    {
        int st = argv.Length() ? static_cast<uint32_t>( argv[0]->ToInteger()->Value() ) : -1;
        int rc = -1;
        if(0<=st)
        {
            v8::Unlocker ul;
            rc = ::sleep( st );
        }
        return v8::Integer::New(rc);
    }

the set/cancelTimeout() impls are somewhat more involved, but mostly because the ability to cancelTimeout() requires so much internal overhead (e.g. locking the timer list, which means adding a mutex class to your tree, if you don't already have one, which i didn't).

Kei Yuen (Kenji)

unread,
Sep 12, 2009, 2:21:00 AM9/12/09
to v8-u...@googlegroups.com
Hi, I have a similar situation too. 
In my case, my server needs to host a large number of long running scripts, but many of them are idle most of the time.

If creating 1000 threads for 1000 scripts isn't a problem, that is to create 1 thread, 1 V8 context for 1 script.
How well can V8 perform in this case?
Since V8 has a lot of static global data, would that be a problem for V8?

Thanks,

Kenji

krovosos

unread,
Sep 14, 2009, 3:02:40 AM9/14/09
to v8-users
> Don't use the word "yield" - if i'm not mistaken it is a reserved word for
> potential future use in the JS language.

Ok, I renamed it to wait_until_V8_manages_multi_threads()

;-)

>
> Coincidentally (and inspired by Ryan's post, above), i just (over the past
> few hours) implemented setTimeout() for v8 and to test it i implemented
> sleep() using the approach you just used. Thus, it appears that the answer
> to your question is Yes.

Yeah, it worked, I've just implemented and wrote a test.
A small problem considering long-running scripts with this call is how
to stop them accurately.
I've added a check for a session to be requested to terminate:

Handle<Value> wait_until_V8_manages_multi_threads(const Arguments&
args)
{
if (session_of_this_script_is_required_to_terminate)
return ThrowException(String::New("session was terminated"));
{
v8::Unlocker unlocker;
Sleep(args.Length() > 0 ? args[0]->Int32Value() : 0);
}
return Undefined();
}


That said, i haven't tried running several
> contexts, only a few threads within a single context.

My case is several threas, different contexts.

> the set/cancelTimeout() impls are somewhat more involved, but mostly because
> the ability to cancelTimeout() requires so much internal overhead (e.g.
> locking the timer list, which means adding a mutex class to your tree, if
> you don't already have one, which i didn't).

My system implements special call that every script can define that
will be called each second.
So the need for setTimeout() is somehow not so strong:

function each_second()
{
// this code will be called each second
}

krovosos

unread,
Sep 14, 2009, 3:10:28 AM9/14/09
to v8-users
If you scripts are idle most of the time - that means that are simply
processing request, right?
Then you should do something like this. Just manage requests...

// compile script and save pointer to func

Local<Script> code = Script::Compile(String::New(script_code.data
()));
if (!try_catch.HasCaught())
Local<Value> result = code->Run();

if (!try_catch.HasCaught())
{
Local<Value> func = client_context.v8_context->Global()->Get
(String::New(func_name));
if (func->IsFunction())
Persistent<Function> func_ptr = Persistent<Function>::New
(Handle<Function>::Cast(func));

}


And later than you have a request to processed you enter context and
call the function and pass a request data.

...
const int argc = 1;
Local<Value> argv[argc] = { String::New("some bla bla bla") };
Local<Value> result = func_ptr->Call(client_context.v8_context-
>Global(), argc, argv);
...

Erik Corry

unread,
Sep 14, 2009, 3:15:49 AM9/14/09
to v8-u...@googlegroups.com
2009/9/12 Stephan Beal <sgb...@googlemail.com>:
> On Fri, Sep 11, 2009 at 10:06 PM, krovosos <ggrig...@gmail.com> wrote:
>>
>> Handle<Value> yield(const Arguments& args)
>> {
>>   v8::Unlocker unlocker;
>>   Sleep(5); // for example
>> // or even Sleep(0) just to give away control of v8 mutex
>> }
>>
>
> Don't use the word "yield" - if i'm not mistaken it is a reserved word for
> potential future use in the JS language.
>>
>> Or maybe every iteration if speed if not an issue for this long-
>> running in background thread.
>> Than other scripts in different threads can still run? Am I right?
>
> Coincidentally (and inspired by Ryan's post, above), i just (over the past
> few hours) implemented setTimeout() for v8 and to test it i implemented

"setTimeOut" is an interesting choice for the name of the function.
Browser-based JS environments also have a call with this name, but it
implements something rather different. In the browser there is only
one thread and you have to return from the current JS invocation in
order for new events (mouse clicks, timeouts, etc.) to trigger new JS
invocations. Implementing the setTimeOut function that is known from
browsers would not involve threads.

From the programmers point of view the concurrency model is rather
different. In the browser implementation the functions registered
with setTimeOut can only run when the previous bit of JS code
relinquished control. With your implementation you can potentially
get another JS call running whenever a callback to C++ code occurs.

On a slightly different note, people on this thread may be interested
in the preemption support that is built into d8. Implementing
something similar in your libv8-using program would allow JS code in
tight loops to be interrupted and other threads to be run even without
explicit flag polling in the JS or callback code. Since there are no
locks or other synchronization primitives available in JS this model
requires separate contexts per thread or a lot of very careful thought
about asynchronous operations at the JS level.

> sleep() using the approach you just used. Thus, it appears that the answer
> to your question is Yes. That said, i haven't tried running several
> contexts, only a few threads within a single context.
> My sleep() impl looks like:
>     v8::Handle<v8::Value> sleep(const v8::Arguments& argv)
>     {
>         int st = argv.Length() ? static_cast<uint32_t>(
> argv[0]->ToInteger()->Value() ) : -1;
>         int rc = -1;
>         if(0<=st)
>         {
>             v8::Unlocker ul;
>             rc = ::sleep( st );
>         }
>         return v8::Integer::New(rc);
>     }
> the set/cancelTimeout() impls are somewhat more involved, but mostly because
> the ability to cancelTimeout() requires so much internal overhead (e.g.
> locking the timer list, which means adding a mutex class to your tree, if
> you don't already have one, which i didn't).
> --
> ----- stephan beal
> http://wanderinghorse.net/home/stephan/
>
> >
>



Stephan Beal

unread,
Sep 14, 2009, 10:26:35 AM9/14/09
to v8-u...@googlegroups.com
On Mon, Sep 14, 2009 at 9:15 AM, Erik Corry <erik....@gmail.com> wrote:
"setTimeOut" is an interesting choice for the name of the function.
Browser-based JS environments also have a call with this name, but it
implements something rather different.  In the browser there is only
one thread and you have to return from the current JS invocation in
order for new events (mouse clicks, timeouts, etc.) to trigger new JS
invocations.  Implementing the setTimeOut function that is known from
browsers would not involve threads.

i wasn't aware that browsers' behaves that way internally. i was aware that long-running (or too many) setTimeout handlers can be problematic, but i wasn't aware that they block for their whole lives.
 
From the programmers point of view the concurrency model is rather
different.  In the browser implementation the functions registered
with setTimeOut can only run when the previous bit of JS code
relinquished control.

In JS there is no explicit way to relinquish control, so we're always required to rely on engine-specific definitions of "when is control handed over". AFAIK, in v8 this check is done when functions are called (or only native functions???). Are there other places where v8 checks whether it should give control to another thread?


> With your implementation you can potentially
> get another JS call running whenever a callback to C++ code occurs.

Yes, that's what i was hoping for :). However, i wasn't aware that this was different from what browsers do. Since any use of setTimeout() is, by nature, subject to race conditions and such (since we cannot know exactly when it will run, and JS has no built-in locking/threading mechanisms), i don't expect that my impl is, in terms of use, much different than a browser impl. That is, anyone who uses setTimout() inherently relies on nondeterminstic order of operations, and therefore probably wouldn't notice any functional difference between an MT- or single-threaded setTimeout() implementation unless they're doing questionable operations on objects from both the setTimeout callback and the originating thread. i hope, anyway.


On a slightly different note, people on this thread may be interested
in the preemption support that is built into d8.  Implementing
something similar in your libv8-using program would allow JS code in
tight loops to be interrupted and other threads to be run even without
explicit flag polling in the JS or callback code.  Since there are no
locks or other synchronization primitives available in JS this model
requires separate contexts per thread or a lot of very careful thought
about asynchronous operations at the JS level.

i found the StartPreemption(someNumericType) (or something like that) function, but i'm not at all clear what it does. The API docs say only the obvious: "starts preemption", but doesn't tell us what that really means. Is it to be run once from each thread, once globally, or what? My assumption that it is a global toggle which tells v8 to check ever N millis to see if it should hand control to another thread, but that's just a guess.

:)

Erik Corry

unread,
Sep 14, 2009, 10:40:33 AM9/14/09
to v8-u...@googlegroups.com
2009/9/14 Stephan Beal <sgb...@googlemail.com>:

> On Mon, Sep 14, 2009 at 9:15 AM, Erik Corry <erik....@gmail.com> wrote:
>>
>> "setTimeOut" is an interesting choice for the name of the function.
>> Browser-based JS environments also have a call with this name, but it
>> implements something rather different.  In the browser there is only
>>
>> one thread and you have to return from the current JS invocation in
>> order for new events (mouse clicks, timeouts, etc.) to trigger new JS
>> invocations.  Implementing the setTimeOut function that is known from
>> browsers would not involve threads.
>
> i wasn't aware that browsers' behaves that way internally. i was aware that
> long-running (or too many) setTimeout handlers can be problematic, but i
> wasn't aware that they block for their whole lives.
>
>>
>> From the programmers point of view the concurrency model is rather
>> different.  In the browser implementation the functions registered
>> with setTimeOut can only run when the previous bit of JS code
>> relinquished control.
>
> In JS there is no explicit way to relinquish control, so we're always

In a browser the way it works is that your JS code is called in
response to some event. That can be a timeout, registered earlier or
it can be an event (onMouseDown, onPageLoaded, I don't remember the
exact names). You relinquish control by returning from the callback.
That's pretty explicit. It's a fairly lame programming model, but it
has the advantage that you don't have to think about concurrency.
Other JS code can only run when you let it by returning at the top
level you were called.

> required to rely on engine-specific definitions of "when is control handed
> over". AFAIK, in v8 this check is done when functions are called (or only
> native functions???). Are there other places where v8 checks whether it
> should give control to another thread?

V8 can check for preemption on a function call (non-native) or a
backwards loop branch. But the support for this is almost unused in
the browser (it's used for the debugger). If you use preemption then
it can be used to switch to a different thread, but there are no V8
threads in the browser. This support is not used for setTimeOut in
the browser because the timeout callbacks are run in the same one
thread that other events also run in.

>> With your implementation you can potentially
>> get another JS call running whenever a callback to C++ code occurs.
>
> Yes, that's what i was hoping for :). However, i wasn't aware that this was
> different from what browsers do. Since any use of setTimeout() is, by
> nature, subject to race conditions

Not if you implement setTimeout in the way a browser does.

>> On a slightly different note, people on this thread may be interested
>> in the preemption support that is built into d8.  Implementing
>> something similar in your libv8-using program would allow JS code in
>> tight loops to be interrupted and other threads to be run even without
>> explicit flag polling in the JS or callback code.  Since there are no
>> locks or other synchronization primitives available in JS this model
>> requires separate contexts per thread or a lot of very careful thought
>> about asynchronous operations at the JS level.
>
> i found the StartPreemption(someNumericType) (or something like that)
> function, but i'm not at all clear what it does. The API docs say only the
> obvious: "starts preemption", but doesn't tell us what that really means. Is
> it to be run once from each thread, once globally, or what? My assumption
> that it is a global toggle which tells v8 to check ever N millis to see if
> it should hand control to another thread, but that's just a guess.

That's pretty much right. The checks are only performed when running
JS code. If you are running C++ code then it is the responsibility of
the embedder to use V8::Locker and V8::Unlocker to let other threads
run. As ever if the documentation is lacking (and it is) then the
uses of the function in the tests and in the shell and d8 can shed
light on their function.

Stephan Beal

unread,
Sep 14, 2009, 11:05:26 AM9/14/09
to v8-u...@googlegroups.com
On Mon, Sep 14, 2009 at 4:40 PM, Erik Corry <erik....@gmail.com> wrote:
In a browser the way it works is that your JS code is called in
response to some event.  That can be a timeout, registered earlier or
it can be an event (onMouseDown, onPageLoaded, I don't remember the
exact names).  You relinquish control by returning from the callback.
That's pretty explicit.  It's a fairly lame programming model, but it
has the advantage that you don't have to think about concurrency.
Other JS code can only run when you let it by returning at the top
level you were called.

Thanks very much for that clarification :). i'll take a look to see how i can implement it without the second thread, but i'm not at all clear how i can do that without using a timer thread.

In any case, i was tickled pink to see that it was indeed possible to get access to v8 via multiple threads without much hackery involved. i've tried to put the MT setTimeout code through the ringer, and so far it all works as i'd like it to. However, given the different semantics vis-a-vis browsers, i should really rename it.

krovosos

unread,
Sep 16, 2009, 9:58:44 AM9/16/09
to v8-users
I am facing a strange problem while trying to run V8 using several
threads: endless growth of used memory in some cases of some intense
calls to precompiled scripts (and process some kind of messages).

I use v8::Locker anywhere before I do v8 stuff. Code is not changed.
The only change is number of threads to use. Contexts are distributed
to threads. Each context is used by the only thread: thread creates
context, compiles and runs code using it.

If I use just one thread and all context belong to it: the problem
dissapears - memory usage goes up and down as expected.

If I use more than one thread (two): memory growth. This memory growth
is endless and very fast as if my program looses about 10 mb per
second.

I don't get any idea what is happening. Code is rather big. May be I
should try and write some small text reproducing this problem?..

krovosos

unread,
Sep 17, 2009, 9:30:30 AM9/17/09
to v8-users
#include "v8/v8.h"
#include <string>
#include "windows.h"
#include "stdio.h"
#include "process.h"
#include <map>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "winmm.lib")

using namespace std;
using namespace v8;

LONG n_active = 0;

typedef map<string, string> s2s;
typedef s2s::iterator is2s;

Handle<Value> cppfoo(const Arguments& args)
{
Handle<Context> context = Context::GetCurrent();
{
v8::Unlocker unlocker;
Sleep(0);
}
return Integer::New(1);
}



void thread (void* p)
{
int m = (int) p;

InterlockedIncrement(&n_active);

Persistent<Context> context;
Persistent<Function> foo;

{
v8::Locker locker;
HandleScope handle_scope;

Handle<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::NewSymbol("cppfoo"), FunctionTemplate::New
(cppfoo));

context = Context::New(NULL, global);
TryCatch try_catch;
Context::Scope context_scope(context);

Local<Script> script = Script::Compile(String::New("function foo(o)
{ var a = new Array(10000); a = []; "
"var s = ''; for (var i in o) s += o[i]; return s + cppfoo(); }"));
Local<Value> result = script->Run();
foo = Persistent<Function>::New(Handle<Function>::Cast(context-
>Global()->Get(String::New("foo"))));
}

s2s meta;
const char* names[] = {"A","B","C","D","E","F","G","H"};
for (int i = 0; i < 8; i++)
meta[ names[i] ] = "gone fishing";

while (m--)
{



int n_calls = 1000;
while (n_calls--)
{

{
v8::Locker locker;
HandleScope handle_scope;
Context::Scope context_scope(context);
TryCatch try_catch;

Local<Object> obj = Object::New();

for (is2s I = meta.begin(); I != meta.end(); I++)
obj->Set (
String::NewSymbol(I->first.data(), I->first.size()),
String::New(I->second.data(), I->second.size())
);

const int argc = 1;
Local<Value> argv[argc] = { obj };
Local<Value> result = foo->Call(context->Global(), argc, argv);

}

Sleep(0);

}

Sleep(1);

}

v8::Locker locker;
foo.Dispose();
context.Dispose();

InterlockedDecrement(&n_active);

}


int usage()
{
printf("Usage:\r\n\r\n memeater.exe <num_of_threads>\r\n\r
\n");
return 1;
}

int main(int argc, char *argv[])
{
if (argc <= 1) return usage();

int n = atoi(*++argv);

printf("running %d threads\n", n);

while (true)
{
if (n_active < n)
{
_beginthread(thread, 0, (void*) 100);
printf("another thread started\n");
}

Sleep(1000);
}

return 0;

}

krovosos

unread,
Sep 17, 2009, 9:32:55 AM9/17/09
to v8-users
Put the above source to memeater.cpp.

Add v8.lib to project and compile ( /MT).

Run:

memeater.exe 5

for example.

Memory runs away with about 10 mb per second speed...

I'm using Windows Vista, Microsoft Visual Studio Express Edition 2008.

krovosos

unread,
Sep 17, 2009, 9:34:45 AM9/17/09
to v8-users
If you want to NOT eat memory just comment Unlocker line.

Mads Sig Ager

unread,
Sep 17, 2009, 9:35:20 AM9/17/09
to v8-u...@googlegroups.com
We should have a look at this.

Could you file a bug report with the file attached at:

http://code.google.com/p/v8/issues/list

Thanks a lot, -- Mads

krovosos

unread,
Sep 17, 2009, 9:38:32 AM9/17/09
to v8-users
Sure!

krovosos

unread,
Sep 17, 2009, 9:44:00 AM9/17/09
to v8-users

krovosos

unread,
Sep 18, 2009, 5:10:45 AM9/18/09
to v8-users
// This one eats 100 Mb per second

#include "v8.h"
#include "windows.h"
#include "stdio.h"
#include "process.h"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "winmm.lib")
using namespace v8;

Handle<Value> cppfoo(const Arguments& args)
{
Handle<Context> context = Context::GetCurrent();
{
v8::Unlocker unlocker;
Sleep(0);
}
return Integer::New(1);
}



void thread (void* p)
{

Persistent<Context> context;
Persistent<Function> foo;

{
v8::Locker locker;
HandleScope handle_scope;

Handle<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::NewSymbol("cppfoo"), FunctionTemplate::New
(cppfoo));
context = Context::New(NULL, global);

Context::Scope context_scope(context);
TryCatch try_catch;
Script::Compile(String::New("function foo(){ cppfoo(); }"))->Run();

foo = Persistent<Function>::New(Handle<Function>::Cast(context-
>Global()->Get(String::New("foo"))));
}

while (true)
{

int n_calls = 1000;
while (n_calls--)
{

{
v8::Locker locker;
HandleScope handle_scope;
Context::Scope context_scope(context);
TryCatch try_catch;

const int argc = 1;
Local<Value> argv[argc] = { String::New("some_string") };
Local<Value> result = foo->Call(context->Global(), argc, argv);

}

Sleep(0);

}

Sleep(1);

}

v8::Locker locker;
foo.Dispose();
context.Dispose();

}



int main(int argc, char *argv[])
{
_beginthread(thread, 0, 0);
_beginthread(thread, 0, 0);
while (true) Sleep(1000);
return 0;
}
Reply all
Reply to author
Forward
0 new messages