Commit 926e4bc
committed
[jnienv-gen] Explore additional invocation strategies.
@migueldeicaza suggested a strategy for speeding up JNI invocations:
Bundle the exception check with the method invocation.
The logic here is that JNIEnv::ExceptionOccurred() should be a *fast*
invocation -- it only (currently) returns a field from the JNIEnv*
struct. No GC, no stopping the world, ~no overhead to speak of.
Yet most of the "important" JNI invocations *always* need to call it,
and because of how we designed things this invocation is through a
delegate:
var tmp = JniEnvironment.Current.Invoker.CallObjectMethod (JniEnvironment.Current.EnvironmentPointer, @object.SafeHandle, method.ID);
var __e - JniEnvironment.Exceptions.ExceptionOccurred();
if (__e.IsValid /* or whatever... */) {
JniEnvironment.Exceptions.ExceptionClear();
throw WrapThatException (__e);
}
return tmp;
JNI ~requires that you do these two JNI invocations (or the exception
will be left pending, and re-raised the next time you call into Java,
and possibly abort if *another* exception is then thrown...).
In the case of Xamarin.Android and the Java.Interop "SafeHandle" and
"IntPtrs" backends (commit 9b85e8d), this results in a second
delegate invocation and corresponding overhead.
@migueldeicaza asked: could we instead call
JNIEnv::ExceptionOccurred() from a C wrapper as part of the "source"
JNIEnv function pointer invocation, performing two JNI calls from
a custom C function (as opposed to one JNI call per C wrapper, as done
in commit 802842a).
The C# binding thus becomes:
// C#
IntPtr thrown;
var tmp = JavaInterop_CallObjectMethod (JniEnvironment.Current.EnvironmentPointer, out thrown, @object.SafeHandle, method.ID);
if (thrown != IntPtr.Zero) {
JniEnvironment.Exceptions.ExceptionClear();
throw WrapThatException (thrown);
}
return tmp;
While the C wrapper is:
/* C */
jobject
JavaInterop_CallObjectMethod (JNIEnv *env, jthrowable *_thrown, jobject object, jmethodID method)
{
*_thrown = NULL;
jobject _r_ = (*env)->CallObjectMethod (env, object, method);
*_thrown = (*env)->ExceptionOccurred (env);
return _r_;
}
The answer: Yes, we can, and it saves ~9% vs. the IntPtr backend.
Update jnienv-gen to emit this third backend alongside the previous
backends, and (for good measure?) emit a *fourth* Xamarin.Android-like
backend for easier/saner comparisions.
The tests/invocation-overhead results:
# SafeTiming timing: 00:00:08.2506653
# Average Invocation: 0.00082506653ms
# JIIntPtrTiming timing: 00:00:02.4018293
# Average Invocation: 0.00024018293ms
# JIPinvokeTiming timing: 00:00:02.2677633
# Average Invocation: 0.00022677633ms
# XAIntPtrTiming timing: 00:00:02.3472511
# Average Invocation: 0.00023472511ms
SafeTiming is the SafeHandle backend; as noted in commit 25de1f3, the
performance is attrocious.
JIIntPtrTiming is JniObjectReference + IntPtrs (9b85e8d).
JIPinvokeTiming is @migueldeicaza's suggestion, outlined above.
XAIntPtrTiming is a Xamarin.Android-like "all IntPtrs all the time!"
backend, for comparison purposes.
Of note is that JIIntPtrTiming -- what I was planning on using for a
future Xamarin.Android integration (commit 25de1f3) -- is ~1-2%
slower than XAIntPtrTiming. Not great, but acceptable.
Migrating to @migueldeicaza's P/Invoke approach results in performance
that's 3-4% *faster* than Xamarin.Android, and ~5-9% faster than
JIIntPtrTiming.
Which means the Xamarin.Android integration should use the P/Invoke
implementation strategy.1 parent 8c52dbd commit 926e4bc
File tree
11 files changed
+12520
-13965
lines changed- src/Java.Interop/Java.Interop
- tests/invocation-overhead
- tools/jnienv-gen
11 files changed
+12520
-13965
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
| 3 | + | |
3 | 4 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
26 | 47 | | |
27 | | - | |
| 48 | + | |
28 | 49 | | |
29 | 50 | | |
30 | 51 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
47 | | - | |
48 | | - | |
| 46 | + | |
| 47 | + | |
49 | 48 | | |
50 | | - | |
51 | | - | |
| 49 | + | |
52 | 50 | | |
53 | | - | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
54 | 55 | | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
| 56 | + | |
65 | 57 | | |
66 | 58 | | |
67 | 59 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
260 | 260 | | |
261 | 261 | | |
262 | 262 | | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
263 | 274 | | |
264 | 275 | | |
265 | 276 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
2 | 15 | | |
3 | 16 | | |
4 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
5 | 21 | | |
6 | | - | |
7 | | - | |
| 22 | + | |
| 23 | + | |
8 | 24 | | |
9 | 25 | | |
10 | 26 | | |
0 commit comments