public void GenericMarshalingOverhead_Int32ArrayArrayArray() { #if __ANDROID__ const int C = 100; #else // __ANDROID__ const int C = 100; #endif // __ANDROID__ var total = Stopwatch.StartNew(); var value = new int[][][] { new int[][] { new int[] { 111, 112, 113 }, new int[] { 121, 122, 123 }, }, new int[][] { new int[] { 211, 212, 213 }, new int[] { 221, 222, 223 }, }, }; using (var t = new JavaTiming()) { var n = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { t.VirtualIntMethod1Args(value); } n.Stop(); var m = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { t.Timing_VirtualIntMethod_Marshal1Args(value); } m.Stop(); var g = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { t.Timing_VirtualIntMethod_GenericMarshal1Args(value); } g.Stop(); Console.WriteLine("Generic Marshaling Overhead: ([[[I)I"); Console.WriteLine("\t Native Marshaling: {0}", n.Elapsed); Console.WriteLine("\tPartial Marshaling: {0}", m.Elapsed); Console.WriteLine("\tGeneric Marshaling: {0}", g.Elapsed); } total.Stop(); Console.WriteLine("## {0} Timing: {1}", nameof(GenericMarshalingOverhead_Int32ArrayArrayArray), total.Elapsed); }
public void GenericMarshalingOverhead_Int32() { const int C = 10000; var total = Stopwatch.StartNew(); using (var t = new JavaTiming()) { var n = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { t.VirtualIntMethod1Args(i); } n.Stop(); var m = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { t.Timing_VirtualIntMethod_Marshal1Args(i); } m.Stop(); var g = Stopwatch.StartNew(); for (int i = 0; i < C; ++i) { t.Timing_VirtualIntMethod_GenericMarshal1Args(i); } g.Stop(); Console.WriteLine("Generic Marshaling Overhead: (I)I"); Console.WriteLine("\t Native Marshaling: {0}", n.Elapsed); Console.WriteLine("\tPartial Marshaling: {0}", m.Elapsed); Console.WriteLine("\tGeneric Marshaling: {0}", g.Elapsed); } total.Stop(); Console.WriteLine("## {0} Timing: {1}", nameof(GenericMarshalingOverhead_Int32), total.Elapsed); }
public unsafe void MethodInvocationTiming() { FooMethods pinvoke_methods; foo_get_methods(out pinvoke_methods); var p_instance_void = (DV)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.instance_void, typeof(DV)); var p_instance_int = (DI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.instance_int, typeof(DI)); var p_instance_ptr = (DP)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.instance_ptr, typeof(DP)); var p_void_1a = (DV1A)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_1_args, typeof(DV1A)); var p_void_2a = (DV2A)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_2_args, typeof(DV2A)); var p_void_3a = (DV3A)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_3_args, typeof(DV3A)); var p_void_1ai = (DV1AI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_1_iargs, typeof(DV1AI)); var p_void_2ai = (DV2AI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_2_iargs, typeof(DV2AI)); var p_void_3ai = (DV3AI)Marshal.GetDelegateForFunctionPointer(pinvoke_methods.void_3_iargs, typeof(DV3AI)); var Object_class = new JniType("java/lang/Object"); var Object_init = Object_class.GetConstructor("()V"); var transfer = JniObjectReferenceOptions.CopyAndDispose; var jobj1 = CreateJavaObject(Object_class.NewObject(Object_init, null), transfer); var jobj2 = CreateJavaObject(Object_class.NewObject(Object_init, null), transfer); var jobj3 = CreateJavaObject(Object_class.NewObject(Object_init, null), transfer); var obj1 = new SomeClass(); var obj2 = new SomeClass(); var obj3 = new SomeClass(); var j = new JavaTiming(); var m = new ManagedTiming(); var comparisons = new[] { new { Name = "static void", Jni = A(() => JavaTiming.StaticVoidMethod()), Managed = A(() => ManagedTiming.StaticVoidMethod()), Pinvoke = A(() => foo_void_timing()), }, new { Name = "static int", Jni = A(() => JavaTiming.StaticIntMethod()), Managed = A(() => ManagedTiming.StaticIntMethod()), Pinvoke = A(() => foo_int_timing()), }, new { Name = "static object", Jni = A(() => JavaTiming.StaticObjectMethod()), Managed = A(() => ManagedTiming.StaticObjectMethod()), Pinvoke = A(() => foo_ptr_timing()), }, new { Name = "virtual void", Jni = A(() => j.VirtualVoidMethod()), Managed = A(() => m.VirtualVoidMethod()), Pinvoke = A(() => p_instance_void()), }, new { Name = "virtual int", Jni = A(() => j.VirtualIntMethod()), Managed = A(() => m.VirtualIntMethod()), Pinvoke = A(() => p_instance_int()), }, new { Name = "virtual object", Jni = A(() => j.VirtualObjectMethod()), Managed = A(() => m.VirtualObjectMethod()), Pinvoke = A(() => p_instance_ptr()), }, new { Name = "final void", Jni = A(() => j.FinalVoidMethod()), Managed = A(() => m.FinalVoidMethod()), Pinvoke = A(null), }, new { Name = "final int", Jni = A(() => j.FinalIntMethod()), Managed = A(() => m.FinalIntMethod()), Pinvoke = A(null), }, new { Name = "final object", Jni = A(() => j.FinalObjectMethod()), Managed = A(() => m.FinalObjectMethod()), Pinvoke = A(null), }, new { Name = "static void o1", Jni = A(() => JavaTiming.StaticVoidMethod1Args(jobj1)), Managed = A(() => ManagedTiming.StaticVoidMethod1Args(obj1)), Pinvoke = A(() => { // We include timing of the GCHandle manipulation since // a JNI invocation has to do similar work, and pinning // is usually always needed for P/Invokes. GCHandle h1 = GCHandle.Alloc(obj1, GCHandleType.Pinned); IntPtr addr1 = h1.AddrOfPinnedObject(); p_void_1a(addr1); h1.Free(); }), }, new { Name = "static void o2", Jni = A(() => JavaTiming.StaticVoidMethod2Args(jobj1, jobj2)), Managed = A(() => ManagedTiming.StaticVoidMethod2Args(obj1, obj2)), Pinvoke = A(() => { GCHandle h1 = GCHandle.Alloc(obj1, GCHandleType.Pinned), h2 = GCHandle.Alloc(obj2, GCHandleType.Pinned); IntPtr addr1 = h1.AddrOfPinnedObject(), addr2 = h2.AddrOfPinnedObject(); p_void_2a(addr1, addr2); h1.Free(); h2.Free(); }), }, new { Name = "static void o3", Jni = A(() => JavaTiming.StaticVoidMethod3Args(jobj1, jobj2, jobj3)), Managed = A(() => ManagedTiming.StaticVoidMethod3Args(obj1, obj2, obj3)), Pinvoke = A(() => { GCHandle h1 = GCHandle.Alloc(obj1, GCHandleType.Pinned), h2 = GCHandle.Alloc(obj2, GCHandleType.Pinned), h3 = GCHandle.Alloc(obj3, GCHandleType.Pinned); IntPtr addr1 = h1.AddrOfPinnedObject(), addr2 = h2.AddrOfPinnedObject(), addr3 = h3.AddrOfPinnedObject(); p_void_3a(addr1, addr2, addr3); h1.Free(); h2.Free(); h3.Free(); }), }, new { Name = "static void i1", Jni = A(() => JavaTiming.StaticVoidMethod1IArgs(42)), Managed = A(() => ManagedTiming.StaticVoidMethod1IArgs(42)), Pinvoke = A(() => p_void_1ai(42)), }, new { Name = "static void i2", Jni = A(() => JavaTiming.StaticVoidMethod2IArgs(42, 42)), Managed = A(() => ManagedTiming.StaticVoidMethod2IArgs(42, 42)), Pinvoke = A(() => p_void_2ai(42, 42)), }, new { Name = "static void i3", Jni = A(() => JavaTiming.StaticVoidMethod3IArgs(42, 42, 42)), Managed = A(() => ManagedTiming.StaticVoidMethod3IArgs(42, 42, 42)), Pinvoke = A(() => p_void_3ai(42, 42, 42)), }, }; #if __ANDROID__ const int count = 1000; #else // __ANDROID__ const int count = 100000; #endif // __ANDROID__ var total = Stopwatch.StartNew(); foo_init(JniEnvironment.EnvironmentPointer); var jniTimes = new long [comparisons.Length]; foo_get_native_jni_timings(JniEnvironment.EnvironmentPointer, count, JavaTiming.TypeRef.PeerReference.Handle, j.PeerReference.Handle, jniTimes); int jniTimeIndex = 0; foreach (var c in comparisons) { var jw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { c.Jni(); } jw.Stop(); var mw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { c.Managed(); } mw.Stop(); System.Diagnostics.Stopwatch pw = null; if (c.Pinvoke != null) { pw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { c.Pinvoke(); } pw.Stop(); } string message = string.Format("Method Invoke: {0}: JNI is {1}x managed", c.Name, System.Math.Round(jw.Elapsed.TotalMilliseconds / mw.Elapsed.TotalMilliseconds)); Console.WriteLine(message); var ct = TimeSpan.FromMilliseconds(jniTimes [jniTimeIndex++]); Console.WriteLine("\t C/JNI: {0} ms | average: {1} ms", FormatFraction(ct.TotalMilliseconds, 10, 5), FormatFraction(ct.TotalMilliseconds / count, 12, 5)); Console.WriteLine("\t JNI: {0} ms; {1,3}x C/JNI | average: {2} ms", FormatFraction(jw.Elapsed.TotalMilliseconds, 10, 5), ToString(jw.Elapsed, ct), FormatFraction(jw.Elapsed.TotalMilliseconds / count, 12, 5)); Console.WriteLine("\tManaged: {0} ms | average: {1} ms", FormatFraction(mw.Elapsed.TotalMilliseconds, 10, 5), FormatFraction(mw.Elapsed.TotalMilliseconds / count, 12, 5)); if (pw != null) { Console.WriteLine("\tPinvoke: {0} ms; {1,3}x managed | average: {2} ms", FormatFraction(pw.Elapsed.TotalMilliseconds, 10, 5), ToString(pw.Elapsed, mw.Elapsed), FormatFraction(pw.Elapsed.TotalMilliseconds / count, 12, 5)); } } total.Stop(); Console.WriteLine("## {0} Timing: {1}", nameof(MethodInvocationTiming), total.Elapsed); }
public void MethodLookupTiming() { #if __ANDROID__ const int count = 100; #else // __ANDROID__ const int count = 100; #endif // __ANDROID__ var total = Stopwatch.StartNew(); using (var o = new JavaTiming()) { var tt = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { var s = o.Timing_ToString_Traditional(); JniObjectReference.Dispose(ref s); } tt.Stop(); var ta = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { var s = o.Timing_ToString_NoCache(); JniObjectReference.Dispose(ref s); } ta.Stop(); var td = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { var s = o.Timing_ToString_DictWithLock();; JniObjectReference.Dispose(ref s); } td.Stop(); var tc = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { var s = o.Timing_ToString_DictWithNoLock(); JniObjectReference.Dispose(ref s); } tc.Stop(); var tp = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { var s = o.Timing_ToString_JniPeerMembers(); JniObjectReference.Dispose(ref s); } tp.Stop(); var vtt = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { o.VirtualIntMethod1Args(i); } vtt.Stop(); var vti = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { o.Timing_VirtualIntMethod_Marshal1Args(i); } vti.Stop(); Console.WriteLine("Method Lookup + Invoke Timing:"); Console.WriteLine("\t Traditional: {0}", tt.Elapsed); Console.WriteLine("\t No caching: {0}", ta.Elapsed); Console.WriteLine("\t Dict w/ lock: {0}", td.Elapsed); Console.WriteLine("\tConcurrentDict: {0}", tc.Elapsed); Console.WriteLine("\tJniPeerMembers: {0}", tp.Elapsed); Console.WriteLine(); Console.WriteLine("\t (I)I virtual+traditional: {0}", vtt.Elapsed); Console.WriteLine("\t (I)I virtual+JniPeerMembers: {0}", vti.Elapsed); } using (var o = new DerivedJavaTiming()) { var ntt = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { o.VirtualIntMethod1Args(i); } ntt.Stop(); var nti = Stopwatch.StartNew(); for (int i = 0; i < count; ++i) { o.Timing_VirtualIntMethod_Marshal1Args(i); } nti.Stop(); Console.WriteLine("\t (I)I nonvirtual+traditional: {0}", ntt.Elapsed); Console.WriteLine("\t(I)I nonvirtual+JniPeerMembers: {0}", nti.Elapsed); } total.Stop(); Console.WriteLine("## {0} Timing: {1}", nameof(MethodLookupTiming), total.Elapsed); }