Skip to content

Commit 8cdb16d

Browse files
committed
[PerformanceTests] Add timing for virtual vs. nonvirtual invocation.
This is why we want JniPeerMembers in Xamarin.Android: CACHEING! ## MethodInvocationTiming Timing: 00:00:03.6698748 Method Lookup + Invoke Timing: Traditional: 00:00:00.0018948 No caching: 00:00:00.0255321 Dict w/ lock: 00:00:00.0018600 ConcurrentDict: 00:00:00.0032975 JniPeerMembers: 00:00:00.0022527 (I)I virtual+traditional: 00:00:00.0000809 (I)I virtual+JniPeerMembers: 00:00:00.0000873 (I)I nonvirtual+traditional: 00:00:00.0069499 (I)I nonvirtual+JniPeerMembers: 00:00:00.0001617 Xamarin.Android is close (-ish) to the `(I)I nonvirtual+traditional` timing -- 0.0069s vs. 0.00008s for virtual dispatch (virtual dispatch is ~86x faster! Though the bug [0] says ~4x on Android...?). That's what we want to improve. How's Java.Interop+JniPeerMembers do? Virtual dispatch is 0.0000873s (slightly slower than Xamarin.Android-style virtual dispatch [1]), but *nonvirtual* dispatch is only 0.001617s, or 1.8x longer. Still not entirely great -- we need to test this scenario on Android -- but still nearly 2 orders of magnitude faster for nonvirtual dispatch, which is a fairly common scenario. [0]: https://bugzilla.xamarin.com/show_bug.cgi?id=32126 [1]: :-(
1 parent 1a8d2a8 commit 8cdb16d

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

tests/PerformanceTests/JavaTiming.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ namespace Java.Interop.PerformanceTests
1010
[JniTypeSignature (JniTypeName)]
1111
public class JavaTiming : JavaObject
1212
{
13-
const string JniTypeName = "com/xamarin/interop/performance/JavaTiming";
13+
protected const string JniTypeName = "com/xamarin/interop/performance/JavaTiming";
1414
static readonly JniPeerMembers _members = new JniPeerMembers (JniTypeName, typeof (JavaTiming));
1515

16+
public override JniPeerMembers JniPeerMembers {
17+
get {return _members;}
18+
}
19+
1620
static JniType _TypeRef;
1721
internal static JniType TypeRef {
1822
get {return JniType.GetCachedJniType (ref _TypeRef, JniTypeName);}
@@ -267,6 +271,16 @@ public JniObjectReference Timing_ToString_DictWithNoLock ()
267271
(s, c) => c ?? TypeRef.GetInstanceMethod (toString_name, toString_sig));
268272
return m.InvokeVirtualObjectMethod (PeerReference);
269273
}
274+
275+
public unsafe JniObjectReference Timing_ToString_JniPeerMembers ()
276+
{
277+
const string id = toString_name + "\u0000" + toString_sig;
278+
return _members.InstanceMethods.InvokeVirtualObjectMethod (id, this, null);
279+
}
280+
}
281+
282+
[JniTypeSignature (JniTypeName)]
283+
class DerivedJavaTiming : JavaTiming {
270284
}
271285
}
272286

tests/PerformanceTests/TimingTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,51 @@ public void MethodLookupTiming ()
350350
}
351351
tc.Stop ();
352352

353+
var tp = Stopwatch.StartNew ();
354+
for (int i = 0; i < count; ++i) {
355+
var s = o.Timing_ToString_JniPeerMembers ();
356+
JniEnvironment.References.Dispose (ref s);
357+
}
358+
tp.Stop ();
359+
360+
361+
var vtt = Stopwatch.StartNew ();
362+
for (int i = 0; i < count; ++i) {
363+
o.VirtualIntMethod1Args (i);
364+
}
365+
vtt.Stop ();
366+
367+
var vti = Stopwatch.StartNew ();
368+
for (int i = 0; i < count; ++i) {
369+
o.Timing_VirtualIntMethod_Marshal1Args (i);
370+
}
371+
vti.Stop ();
372+
373+
353374
Console.WriteLine ("Method Lookup + Invoke Timing:");
354375
Console.WriteLine ("\t Traditional: {0}", tt.Elapsed);
355376
Console.WriteLine ("\t No caching: {0}", ta.Elapsed);
356377
Console.WriteLine ("\t Dict w/ lock: {0}", td.Elapsed);
357378
Console.WriteLine ("\tConcurrentDict: {0}", tc.Elapsed);
379+
Console.WriteLine ("\tJniPeerMembers: {0}", tp.Elapsed);
380+
Console.WriteLine ();
381+
Console.WriteLine ("\t (I)I virtual+traditional: {0}", vtt.Elapsed);
382+
Console.WriteLine ("\t (I)I virtual+JniPeerMembers: {0}", vti.Elapsed);
383+
}
384+
using (var o = new DerivedJavaTiming ()) {
385+
var ntt = Stopwatch.StartNew ();
386+
for (int i = 0; i < count; ++i) {
387+
o.VirtualIntMethod1Args (i);
388+
}
389+
ntt.Stop ();
390+
391+
var nti = Stopwatch.StartNew ();
392+
for (int i = 0; i < count; ++i) {
393+
o.Timing_VirtualIntMethod_Marshal1Args (i);
394+
}
395+
nti.Stop ();
396+
Console.WriteLine ("\t (I)I nonvirtual+traditional: {0}", ntt.Elapsed);
397+
Console.WriteLine ("\t(I)I nonvirtual+JniPeerMembers: {0}", nti.Elapsed);
358398
}
359399

360400
total.Stop ();

0 commit comments

Comments
 (0)