I tried playing with observeInstructionCount, but since I can't
imitate a
continuation from there, there is no way for me to return control
back to a
worker thread. I am trying to execute a large number of scripts
simultaneously and continuously, but each script needs only a very
small and
measured amount of CPU time (as a simplified example consider, 1000
instructions allowed per second per script max).
Unless I am missing something obvious (and don't put missing the
obvious
past me, I am plenty capable of that) :), then I would need to fully
instantiate 10k threads if I have 10k scripts running. This is
because there
is no clean way of saving _and resuming_ the state of the script
execution
at the call to observeInstructionCount (the example usage for that
method
only breaks execution, but does not allow it to resume). So I can't
see a
way to use an efficient threadpool to iterate through all 10k scripts
allowing them to execute only their allotted timeslice without
continuations
either at the JS level or the thread level.
But your comment makes me a little nervous that I did miss something
obvious, is there something you see here, or does this situation
make sense?
I heard from one other person when I originally posted the question
related
to this post that he was interested in similar functionality.
Thanks!
Dave
-----Original Message-----
From:
[EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED]
a.org] On Behalf Of Norris Boyd
Sent: Monday, December 01, 2008 3:24 PM
To: [email protected]
Subject: Re: Info: A way to break script execution from outside the JS
environment
On Nov 29, 11:12 am, "David Parks" <[EMAIL PROTECTED]> wrote:
Well, at least one person asked me to post or blog something if I
found a
way to limit how much processing any given script is allowed.
So I'm posing this to provide one such solution (it's a hack, but
it works
well for my particular need). Perhaps the info will be useful to
others as
well.
The solution/workaround for those interested:
----------------------------------------------------------
Based on the upcoming Rhino version 1.7R2 (release candidate 1 is
currently
available, a link is in this forums archives), there are some new
features
around the continuation capabilities that allow you to capture and
resume
a
continuation outside the JS environment. The limitation is that the
continuation must be initiated from within a JS function (it can be a
Native
Java Method as in the provided test example ContinuationsApiTest
class).
So the trick I've come up with (mind you, I'm quite sure that there
are
cleaner ways to implement this, I just don't know them nor want to
make
the
numerous changes to the base code that would be required) is to
inject a
call to a JS function that will initiate the continuation.
I've done this with some code in the interpreter that watches for
line
breaks (those appear to be safe places to inject a function call)
and also
watches for a Boolean condition to be set (in my case I'm counting
instructions and breaking when the # of instructions executed
exceeds a
threshold). At that point, instead of continuing execution of the
compiled
bytecode, I inject 5 operations, and allow them to process in
sequence
(the
same 5 operations that would be used to make a JS function call),
then
restore the registers I used to their original state at the end.
I've included the source that I changed Interpreter.class. It's set
up to
call the same object/function used in the ContinuationsApiTest class.
There
are only 2 areas in the code that I updated, you can identify them by
searching for the word "hack" added in comments anywhere I made
changes.
The
first is the code in the interpretLoop to inject the function when
appropriate, and the other is in the compiler to force it to
include line
changes even if the script doesn't have any newline characters
(this is
just
to avoid a script stripping all newlines in an attempt to bypass this
mechanism, and will have the side effect of calling the onLineChange
method
in the debugger multiple times for the same source line in some
cases).
As part of my particular case I am executing many different
scripts, each
in
their own scope, and each time I resume a particular scope/script I
have a
debugger object and contextData object associated with that scope.
I set
the
debugger and contextData object that I've associated with that
scope each
time I resume processing a new script
(Context.SetDebugger(myDebugger,
myContextDataObj)). The Context Data object that is passed in
contains the
variables used by the workaround code in the interpertLoop, so it's
important to make sure that the contextData object stays with the
particular
scope.
As far as performance, I've been able to call a bit over 2000
scripts,
have
each of them performing a resume and suspend operation after
executing
their
allotment of ~1000 bytecode operations, then perform a few other
minor
operations, all in 1 second on average using a laptops 1.9 ghz
single cpu
core processor. I am pretty happy with the scalability of JS
continuations.
Anyway, if someone tries this out I'd be happy to explain in more
detail.
If
you want to play with this you should start with the included
ContinuationsApiTest.class and tweak that example with this little
hack in
place to see it working.
Dave
p.s. A big thanks to everyone contributing to Rhino!! And for
adding the
new
continuation functionality, that was a homerun for me!
I don't understand why you need to use continuations for this. What
are you trying to achieve that just using observeInstructionCount
alone was insufficient for?