jurassic icon indicating copy to clipboard operation
jurassic copied to clipboard

Self-executing function changing dramatically the execution time

Open rodrigoroma opened this issue 9 years ago • 8 comments

Hi,

the first thing that I want to say is congratulations for your excellent work on Jurassic!

I've got an interesting case that I don't know if it is the normal behavior, a bug or if I'm doing something wrong.

Take the following code as an example:

Line 0001: (function () {
Line 0002:     var a = 0;
Line 0003:     
Line 0004:     a++;
Line 0005:     a++;
               .
               .
               .
Line 2002:     a++;
Line 2003:     a++;
Line 2004: })();

The above code runs in approximately 80ms but if I remove the self-executing function (lines 1 and 2004), it runs in something about 900ms.

If the "a++;" instruction is repeated 10k times instead of 2k, with the self-executing function it takes 120ms and without this function it gives "An unhandled exception of type 'System.StackOverflowException' occurred in Jurassic.dll"

Before running this Javascript code I do some other stuffs in the Jurassic engine but I don't think it's relevant. I can provide further details if necessary.

rodrigoroma avatar Oct 29 '16 01:10 rodrigoroma

That's very strange. I can't take a look right now, sorry, I'm on holiday :-) But I'll take a look when I get back.

paulbartrum avatar Nov 16 '16 08:11 paulbartrum

I tried it, but both the self-executing and non-self-executing function took about the same amount of time. Can you clarify exactly what code you were using when you experienced the slow execution and/or the stack overflow exception?

paulbartrum avatar Dec 08 '16 01:12 paulbartrum

Hi @paulbartrum,

I can reproduce the StackOverflowException and the long run time just by creating a new ScriptEngine and executing the code from @rodrigoroma without the self-executing function expression, using Jurassic from the current master branch.

I have created a repro with commit https://github.com/kpreisser/jurassic/commit/49dda065691f54f63805abbbb5e5a20ef69b16dc. When I run this project on a 64-Bit machine (using VS 2015), I'm getting a StackOverflowException.

Thanks!

kpreisser avatar Dec 08 '16 08:12 kpreisser

Hi @paulbartrum and @kpreisser,

I've also created a simple program to reproduce this issue (it's attached).

My environment is Visual Studio Community 2015 in Windows 10 Pro (64 bits version) using the latest version of Jurassic available in NuGet (I've just created a new Console Application and ran Install-Package Jurassic).

My guess is that the long time has something to do with global variables because if I put the declaration of "a" out of the self-executing function (that is, in the global scope), it also takes a long time.

Line 0001: var a = 0;
Line 0002:     
Line 0003: (function () {
Line 0004:     a++;
Line 0005:     a++;
               .
               .
               .
Line 2002:     a++;
Line 2003:     a++;
Line 2004: })();

Thanks!

Program.txt

rodrigoroma avatar Dec 08 '16 16:12 rodrigoroma

Accessing global variables is quite a bit slower than accessing local variables. But I'm not sure that's the problem here. Separating out the compilation and the execution:

ScriptEngine engine = new ScriptEngine();
var compiledCode = engine.Compile(new StringScriptSource(generateCode(false)));
compiledCode.Execute();

~~99% of the elapsed time is in the compilation, not the execution. I'll keep looking.~~ EDIT: I got mixed up, the majority of the time is in reading or writing the global variables.

paulbartrum avatar Dec 09 '16 00:12 paulbartrum

Ok, thanks again for your attention!

rodrigoroma avatar Dec 09 '16 00:12 rodrigoroma

Oh no, I'm wrong, the elapsed time is in the execution.

------------------------------------
Without the self executing function
Compile time: 154, execution time: 1086 (b=2000)
Compile time: 54, execution time: 1071 (b=2000)
Compile time: 56, execution time: 1067 (b=2000)
Compile time: 62, execution time: 1065 (b=2000)
Compile time: 56, execution time: 1073 (b=2000)
------------------------------------
With the self executing function
Compile time: 27, execution time: 44 (b=2000)
Compile time: 24, execution time: 42 (b=2000)
Compile time: 15, execution time: 41 (b=2000)
Compile time: 11, execution time: 41 (b=2000)
Compile time: 13, execution time: 42 (b=2000)

That means it's likely to be a problem with the codegen for reading or writing a global variable (or both).

paulbartrum avatar Dec 09 '16 00:12 paulbartrum

I made some small changes to the Jurassic code, I hope @paulbartrum understanding。 In class CompiledScript I use EvalMethodGenerator instead of GlobalMethodGenerator so that CompiledScript.Compile can be compiled with the return value of a function (global functions are written into (function (args) {body}), the compilation of these functions results in a filename as a key The static Dictionary <string,CompiledScript>, can then be used in a multithreaded environment, I use a ReaderWriterLock to deal with concurrency Now very quickly, because it no longer needs to be repeated Parse

zgsxtyzgd avatar Mar 29 '17 14:03 zgsxtyzgd