JINT performance is significantly worse when an application is run as a 64bit application

1.2k Views Asked by At

The application requires JS support (the program is written in C#) and JINT is being used as the interpreter. I have noticed how performance significantly degrades when the application is run as a 64bit application.

I have simplified this down to the following example which illustrates the issue:

Stopwatch sw = new Stopwatch();
sw.Start();

for (int i = 0; i < 1000; i++)
{
    var engine = new Jint.Engine(cfg =>
    {
        cfg.Strict(true); // Good practive for javascript
        cfg.AllowClr(); // Access to .net
        cfg.LimitRecursion(16); // Help stop broken scripts taking down application
        cfg.CatchClrExceptions(ex => ex is Exception);
    });

    try
    {
        engine.Execute(@"
              function test() 
              { 
                throw 'Error';
              };

              test();
        ");
    }
    catch (Exception) { }
}

sw.Stop();

Debug.WriteLine(sw.Elapsed);

When this is compiled as a 32bit application it takes around 11 seconds. When this is compiled as a 64bit application is takes around 35 seconds. Please that the exceptions are thrown quite frequently in the real application.

Does anyone know why this is the case?

Note this only appears to be an issue when running under the debugger. Outside the debugger the performance seems to be similar.


Update #1

I have still been working on this and now have this example:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Stopwatch sw = new Stopwatch();
        sw.Start();

        for (int i = 0; i < 20000; i++)
        {
            DefinedDotNetApi();
        }

        sw.Stop();
        MessageBox.Show(sw.Elapsed.ToString());
    }

    public static void DefinedDotNetApi()
    {
        var engine = new Jint.Engine();

        engine.SetValue("demoJSApi", new DemoJavascriptApi());

        var result = engine.Execute("demoJSApi.helloWorldFromDotNet('TestTest');demoJSApi.helloWorldFromDotNet('TestTest')").GetCompletionValue();
    }

    public class DemoJavascriptApi
    {
        public string helloWorldFromDotNet(string name)
        {
            return $"Hello {name} - this is executed in {typeof(Program).FullName}";
        }
    }
}

When runs a 32bit app this is 20-30% faster than when built as a 64bit app.

Even doing this:

    public static void DefinedDotNetApi()
    {
        var engine = new Jint.Engine();

        engine.SetValue("demoJSApi", new DemoJavascriptApi());

        // var result = engine.Execute("demoJSApi.helloWorldFromDotNet('TestTest');demoJSApi.helloWorldFromDotNet('TestTest')").GetCompletionValue();
        var result = engine.Execute("function test() { return 'test'; };test();").GetCompletionValue();
    }

So without a .NET callback and it is still 10-20% slower in 64bit mode.

Does anyone know why this is?


Update #2

This example shows the difference in speed between a 32bit and 64bit process. I have used benchmarkdotnet.org to show the difference.

public class Program
{
    static void Main(string[] args)
    {
        var summary = BenchmarkRunner.Run<JintTest>();
    }
}

[LegacyJitX86Job, LegacyJitX64Job]
[MinColumn, MaxColumn, MeanColumn, MedianColumn]
public class JintTest
{
    public JintTest()
    {
        Test();
    }

    private const string ContextString = @"/*var test1;var LineupScheduleItem1 = undefined;var LineupScheduleItem2 = undefined;var LineupScheduleItem3 = undefined;var LineupScheduleItem4 = undefined;*/";

    [Benchmark]
    public void Test()
    {
        Jint.Engine engine = new Jint.Engine(cfg =>
        {
            cfg.Strict(true); // Good practive for javascript
            cfg.AllowClr(); // Access to .net
            cfg.LimitRecursion(16); // Help stop broken scripts taking down application
            cfg.CatchClrExceptions(ex => ex is Exception);
        });

        JavaScriptParser parser = new Jint.Parser.JavaScriptParser(true);

        int maxIterations = 500;
        for (int i = 0; i < maxIterations; i++)
        {
            engine.Execute(parser.Parse(ContextString));
        }
    }
}

The script is all commented out and it is just being executed. The 64bit process is about 30% slower. It does not seem to make a difference if the script is parsed or not.

Does anyone know why this would be the case?

0

There are 0 best solutions below