Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[jnienv-gen] Add possible C#9 function pointer backend #938

Merged
merged 1 commit into from
Jan 5, 2022

Conversation

jonpryor
Copy link
Member

@jonpryor jonpryor commented Jan 4, 2022

Context: 926e4bc
Context: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers
Context? #666

Commit 926e4bc allowed jnienv-gen to emit multiple different
JNIEnv invocation strategies at the same time, allowing
tests/invocation-overhead to try them "all at once" for side-by-
side comparisons.

Add support for a new JNIEnv invocation strategy which relies on
C#9 Function Pointers, a'la:

partial struct JNIEnv {
    public  delegate* unmanaged <IntPtr /* env */, jobject> ExceptionOccurred;
}
partial class JniEnvironment {
    partial class Exceptions {
        public static unsafe JniObjectReference ExceptionOccurred ()
        {
            IntPtr __env = JniEnvironment.EnvironmentPointer;
            var tmp = (*((JNIEnv**)__env))->ExceptionOccurred (__env);
            return new JniObjectReference (tmp, JniObjectReferenceType.Local);
        }
    }
}

This could allow for performance better than "JIPinvokeTiming",
as it avoids P/Invoke overheads to a set of java_interop_* C
functions (926e4bc), while also avoiding the overheads involved
with using Marshal.GetDelegateForFunctionPointer() as used by
"JIIntPtrs".

…but it doesn't necessarily provide better performance:

$ JI_JVM_PATH=$HOME/android-toolchain/jdk-11/lib/jli/libjli.dylib dotnet tests/invocation-overhead/bin/Debug/net6.0/invocation-overhead.dll
# SafeTiming timing: 00:00:04.2123508
#	Average Invocation: 0.00042123508ms
# XAIntPtrTiming timing: 00:00:02.1625501
#	Average Invocation: 0.00021625500999999998ms
# JIIntPtrTiming timing: 00:00:02.3620239
#	Average Invocation: 0.00023620239ms
# JIPinvokeTiming timing: 00:00:01.8993587
#	Average Invocation: 0.00018993587ms
# JIFunctionPointersTiming timing: 00:00:02.0278083
#	Average Invocation: 0.00020278083ms

(Compare and contrast with 926e4bc, circa 2015!)

Of particular note is that the Average Invocation time for
JIFunctionPointersTiming takes 7% longer than JIPinvokeTiming.

Though that's slightly reversed when a Release build of
invocation-overhead.dll is used:

% JI_JVM_PATH=$HOME/android-toolchain/jdk-11/lib/jli/libjli.dylib dotnet tests/invocation-overhead/bin/Release/net6.0/invocation-overhead.dll
# SafeTiming timing: 00:00:03.4128431
#	Average Invocation: 0.00034128431000000003ms
# XAIntPtrTiming timing: 00:00:01.8857456
#	Average Invocation: 0.00018857455999999999ms
# JIIntPtrTiming timing: 00:00:01.9075412
#	Average Invocation: 0.00019075412ms
# JIPinvokeTiming timing: 00:00:01.6993644
#	Average Invocation: 0.00016993643999999998ms
# JIFunctionPointersTiming timing: 00:00:01.6561349
#	Average Invocation: 0.00016561349ms

With a Release build, the Average Invocation time for
JIFunctionPointersTiming takes 97% of the time as JIPinvokeTiming,
i.e. is 3% faster.

We may or may not continue investigation of C#9 Function Pointers
for JNIEnv binding purposes. We will preserve this code for
future investigation.

Context: 926e4bc
Context: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/function-pointers
Context? dotnet#666

Commit 926e4bc allowed `jnienv-gen` to emit multiple different
JNIEnv invocation strategies at the same time, allowing
`tests/invocation-overhead` to try them "all at once" for side-by-
side comparisons.

Add support for JNIEnv invocation strategy which relies on
C#9 Function Pointers, a'la:

	partial struct JNIEnv {
	    public  delegate* unmanaged <IntPtr /* env */, jobject> ExceptionOccurred;
	}
	partial class JniEnvironment {
	    partial class Exceptions {
	        public static unsafe JniObjectReference ExceptionOccurred ()
	        {
	            IntPtr __env = JniEnvironment.EnvironmentPointer;
	            var tmp = (*((JNIEnv**)__env))->ExceptionOccurred (__env);
	            return new JniObjectReference (tmp, JniObjectReferenceType.Local);
	        }
	    }
	}

This *should* allow for performance better than "JIPinvokeTiming",
as it avoids P/Invoke overheads to a set of `java_interop_*` C
functions (926e4bc), while *also* avoiding the overheads involved
with using `Marshal.GetDelegateForFunctionPointer()` as used by
"JIIntPtrs".

…but it doesn't:

	$ JI_JVM_PATH=$HOME/android-toolchain/jdk-11/lib/jli/libjli.dylib dotnet tests/invocation-overhead/bin/Debug/net6.0/invocation-overhead.dll
	# SafeTiming timing: 00:00:04.2123508
	#	Average Invocation: 0.00042123508ms
	# XAIntPtrTiming timing: 00:00:02.1625501
	#	Average Invocation: 0.00021625500999999998ms
	# JIIntPtrTiming timing: 00:00:02.3620239
	#	Average Invocation: 0.00023620239ms
	# JIPinvokeTiming timing: 00:00:01.8993587
	#	Average Invocation: 0.00018993587ms
	# JIFunctionPointersTiming timing: 00:00:02.0278083
	#	Average Invocation: 0.00020278083ms

(Compare and contrast with 926e4bc, circa 2015!)

Of particular note is that the Average Invocation time for
JIFunctionPointersTiming takes 7% longer than JIPinvokeTiming.

We may not continue investigation of C#9 Function Pointers
for `JNIEnv` binding purposes, but we can preserve this code for
future investigation.
@jonpryor jonpryor merged commit 312fbf4 into dotnet:main Jan 5, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Apr 13, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants