eclipsesource / J2V8

Java Bindings for V8
2.54k stars 355 forks source link

JS -> Native Functional Call Performance #194

Open activetheory opened 8 years ago

activetheory commented 8 years ago

Hi,

In my use case, I'm binding WebGL calls to their OpenGL counterpart in Java. I'm encountering some performance issues that I narrowed down to the time it takes to call a native function from JavaScript.

My test case is:

v8object.registerJavaMethod(this, "profile", "profile", new Class<?>[] { int.class });
public void profile(int time) {

}

In JavaScript:

var time = 0;
for (var i = 0; i < 100; i++) {
    let t = performance.now();
    profile(i);
    time += (performance.now() - t);
}

time /= 100;

My device is a Nexus 6P

performance.now is another native hook, so that's adding a bit to the time calculated I'm sure but the end result is the average time to call a native function according to this test is 0.4981, which at half a millisecond is already causing performance issues even just drawing a few objects in my GL scene.

I'd be very grateful to hear your thoughts on this and if there is anything I can do to speed things up.

activetheory commented 7 years ago

After a bit of research it seems like the only way to get the performance I'm looking for is to bind the OpenGL calls in C++ directly.

Is the best way to accomplish this to create a new NDK library and somehow pass the V8 reference from J2V8 into that and bind directly?

irbull commented 7 years ago

@activetheory Sorry for the delay in response.

Yes, the JNI calls do have some overhead. I've noticed that calls from V8 (C++) to Java are significantly slower than calls from Java to V8. In your case, writing tight animation loops in JavaScript, you will be hit by these performance problems.

What we did, in Tabris.js, was to batch several animation routines and make a single draw call to render the actual frame. For example, if you wanted to draw 4 lines, instead of making 4 calls, you would encode those line drawing routines as operations and make a single call draw(operations).

A few other notes, if you use java.lang.String in your encoding it won't help much, because each creation of a string results in a JNI call. We used arrays of primitives with op codes for the different draw routines.

As you mentioned, you could also bind the OpenGL directly to C++. This would be a great solution, but it will require you to build a custom J2V8 with this binding. I would like to implement this, so maybe we can find a way to work together on this solution.

activetheory commented 7 years ago

Thanks for your response, it would be great to work together on this.

The primary use case of what I'm trying to build is to be able to use three.js which means I have to match the WebGL spec. I have WebGL -> OpenGL implemented in Java and it all works -- just slow as discussed.

The structure is simple, there is a global object _gl which has all methods on it and it can be worked with directly or passed into three.js' WebGLRenderer.

I have a good reference on how to do the bindings in C++ but I don't know how to plumb this with the NDK. At first I thought I would try to hack it into com_eclipsesource_v8_V8Impl.cpp but couldn't get ndk to compile since Android.mk has references to some files in Jenkins that I couldn't find in the repo.

Thinking about how to do this going forward: Is there a way to develop some sort of C++ plugin system that exposes the V8 isolate to a new file so the _gl object can be bound directly? I'm in over my head here so looking forward to your suggestions on the best way to implement. :)

jonek commented 7 years ago

@activetheory If you want to execute a thee.js application on an Android device, why are you trying to use J2V8 instead of just a WebView?

activetheory commented 7 years ago

@jonek Great question -- there are some specific cases where the WebView is unavailable, such as Android Wear and Daydream VR, which is the real driver behind the project I'm working on. I have the VR API all set up and working great with J2V8 <-> JavaScript aside from the call overhead.

In other cases where the WebView is available, it is actually performance constrained at this time compared to Chrome.

activetheory commented 7 years ago

Just wanted to follow up on this thread :)

WolfieWerewolf commented 7 years ago

Hi guys... I have a similar interest in this. You may be interested in looking at these two projects for some inspiration. https://github.com/joeferner/node-java https://github.com/mikeseven/node-webgl The node-webgl implementation is dependent on GLFW by the same author but I expect it would be easy enough to translate. I've also recently found some performance issues when bridging in a native node.js module I developed to talk to Python. Passing strings, for example, I found the be the slowest approach whereas passing v8:: anything else is very fast and mutating, say a JSON object to a Python Dict was at least 7 times faster in C++ over JSON strings. Out of curiosity @activetheory are your WebGL / Java bindings public?

activetheory commented 7 years ago

@WolfieWerewolf

Hi :) I do not have anything public as it is all tied into our internal frameworks.

A really good reference I found for the C++ bindings are https://github.com/borisvanschooten/glesjs but I just don't understand enough about C++/NDK to figure out how to make it work.

This has become a slightly less pressing priority for me as it seems Google is working to make WebVR a first class citizen for Daydream, but I'd be interested in seeing it through nonetheless.

WolfieWerewolf commented 7 years ago

While I'm at it I may as well throw this out there.... this is an idea I had to standardize interop between these runtimes / languages. Instead of constantly calling one from the other create a native wrapper with a consistent API to and from each of the runtimes. Like NAN for node so that any runtime can consume anything from anywhere.... Clearly a lot of work but it would make for a clean overall solution.

image

WolfieWerewolf commented 7 years ago

Thanks @activetheory I'll take a look and if I find anything that I think you might benefit from I'll share it on here.