Using ClearScript in a video game.

Jan 26, 2014 at 4:55 AM
Hey, I was making a video game engine (with SFML.Net) and using JavaScript as the game programming language.

I had been using Jurassic until I saw this, I made a new branch of my code and switched over.

I then ran some performance tests and realized this ClearScript was much slower, even when running V8. The game FPS more than halved under this.

So, here's an example of the game code:
var image = LoadImage("image.png"); // exposes a C# image object from my game engine

while (!IsAnyKeyPressed()) {
    image.blit(0, 0);
    FlipScreen();
}
In Jurassic the above code had 0 performance penalty and the game ran at over 10000fps, but under ClearScript it's around 7400 fps.

Now, when I do this the fps goes up again, to 11000fps:
var image = LoadImage("image.png");
var blit = image.blit;

while (!IsAnyKeyPressed()) {
    blit(0, 0);
    FlipScreen();
}
I wonder why? Is the host-to-JS that slow? In Jurassic it's cleaner what you say goes into the JS environment, but it seems in ClearScript a lot of 'baggage' is tied to an object. What can I do to make this go faster?

LoadImage just returns a C# instance of an image object (an SFML texture with the ability to draw it to the render window). I feel like there is a way to make this faster, or if it is the case that the 'miracle C#-JS' conversion is slow, then I'm going to have to ditch ClearScript and move back to Jurassic, but I want the power of V8. I need to use a lot of exposed objects. I'm not always running raw JS (which is far faster than Jurassic, btw).
Coordinator
Jan 26, 2014 at 7:28 PM
Greetings Radnen!

Thanks for giving ClearScript a spin! This is great feedback.

We're actually encouraged by your numbers. When you use ClearScript with V8, calls across the managed/native boundary are indeed expensive. Since Jurassic avoids this transition by compiling JavaScript to CIL, we'd expect the code in your second example to still be faster with Jurassic than ClearScript.

So the question is, why is the code in your first example so much slower? The answer has to do with the way V8 embedding works. As is natural for JavaScript, V8 does not recognize any difference between properties and methods. The expression image.blit(0,0) causes V8 to first retrieve the blit property, and then to invoke its value as a function. Because image is a managed object, this results in two round trips across the managed/native boundary. Eliminating one of them from the body of your loop - as the code in your second example does - makes a big difference.

We took a look and it turns out that we can fix this very easily for most managed objects and types. We've already coded the fix and will include it with the next release of ClearScript.

Thanks!
Jan 26, 2014 at 9:30 PM
Thank you! What I love about this project is that it's actively worked on still and you are quick to respond, way more than half of the discussions here ended in positive progress. :)

I still have hope for ClearScript since having a good v8 wrapper would be nice (especially one not so cryptic to use or lacking in documentation as some others).
Coordinator
Jan 28, 2014 at 2:15 PM
Edited Jan 28, 2014 at 8:30 PM
Thanks, Radnen!

By the way, if image, blit, FlipScreen, or IsAnyKeyPressed in your test code above are global (as opposed to being local variables in a function), try rerunning the tests with V8ScriptEngineFlags.DisableGlobalMembers. The GlobalMembers feature is expensive even when not used and should always be disabled in performance-critical applications.

Good luck!