Skip to content

Commit f26bc27

Browse files
jonathanpeppersjonpryor
authored andcommitted
[Java.Interop] use Dictionary<string, *>(StringComparer.Ordinal) (#550)
Context: https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#ordinal-string-operations When profiling startup for a Xamarin.Forms app, I noticed some heavy calls to `Dictionary`: Total(ms) Self(ms) Calls Method name 392 49 14826 System.Collections.Generic.Dictionary`2<TKey_REF, TValue_REF>:FindEntry (TKey_REF) 377 18 12744 System.Collections.Generic.Dictionary`2<TKey_REF, TValue_REF>:TryGetValue (TKey_REF,TValue_REF&) 129 14 3827 System.Collections.Generic.Dictionary`2<TKey_REF, TValue_REF>:TryInsert (TKey_REF,TValue_REF,System.Collections.Generic.InsertionBehavior) Quite a few of these are coming from Java.Interop itself, and I noticed we were using the default constructor for ``Dictionary`2``. This means we are using a culture-aware string comparison for every Java member we lookup. I could see a small difference in a Release build of the Xamarin.Forms integration project in xamarin-android: * Before: 01-03 09:26:24.830 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +763ms 01-03 09:26:28.865 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +754ms 01-03 09:26:32.865 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +754ms 01-03 09:26:36.898 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +759ms 01-03 09:26:40.915 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +760ms 01-03 09:26:44.863 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +752ms 01-03 09:26:48.864 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +759ms 01-03 09:26:52.881 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +753ms 01-03 09:26:56.864 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +746ms 01-03 09:27:00.864 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +760ms * Average(ms): 756 * Std Err(ms): 1.60554594383897 * Std Dev(ms): 5.07718207057594 * After: 01-03 09:48:00.954 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +745ms 01-03 09:48:04.988 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +754ms 01-03 09:48:08.987 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +761ms 01-03 09:48:12.953 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +735ms 01-03 09:48:16.987 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +752ms 01-03 09:48:20.971 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +757ms 01-03 09:48:24.938 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +760ms 01-03 09:48:28.921 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +767ms 01-03 09:48:32.888 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +745ms 01-03 09:48:36.922 1473 1503 I ActivityTaskManager: Displayed Xamarin.Forms_Performance_Integration/xamarin.forms.performance.integration.MainActivity: +757ms * Average(ms): 753.3 * Std Err(ms): 2.97040962382856 * Std Dev(ms): 9.39325999498222 I would guess this saves ~2ms during startup? I also toyed with changing the `capacity` constructor value to 0, but that seemed to make things worse. I don't think there is a way for us to "guess" the default capacity for these dictionaries, so let's let the BCL do that.
1 parent 476597b commit f26bc27

4 files changed

+4
-4
lines changed

src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceFields.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal JniInstanceFields (JniPeerMembers members)
1313

1414
readonly JniPeerMembers Members;
1515

16-
Dictionary<string, JniFieldInfo> InstanceFields = new Dictionary<string, JniFieldInfo>();
16+
Dictionary<string, JniFieldInfo> InstanceFields = new Dictionary<string, JniFieldInfo>(StringComparer.Ordinal);
1717

1818
internal void Dispose ()
1919
{

src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal JniType JniPeerType {
3535

3636
readonly Type DeclaringType;
3737

38-
Dictionary<string, JniMethodInfo> InstanceMethods = new Dictionary<string, JniMethodInfo>();
38+
Dictionary<string, JniMethodInfo> InstanceMethods = new Dictionary<string, JniMethodInfo>(StringComparer.Ordinal);
3939
Dictionary<Type, JniInstanceMethods> SubclassConstructors = new Dictionary<Type, JniInstanceMethods> ();
4040

4141
internal void Dispose ()

src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticFields.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal JniStaticFields (JniPeerMembers members)
1313

1414
readonly JniPeerMembers Members;
1515

16-
Dictionary<string, JniFieldInfo> StaticFields = new Dictionary<string, JniFieldInfo>();
16+
Dictionary<string, JniFieldInfo> StaticFields = new Dictionary<string, JniFieldInfo>(StringComparer.Ordinal);
1717

1818
public JniFieldInfo GetFieldInfo (string encodedMember)
1919
{

src/Java.Interop/Java.Interop/JniPeerMembers.JniStaticMethods.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal JniStaticMethods (JniPeerMembers members)
1313

1414
internal readonly JniPeerMembers Members;
1515

16-
Dictionary<string, JniMethodInfo> StaticMethods = new Dictionary<string, JniMethodInfo>();
16+
Dictionary<string, JniMethodInfo> StaticMethods = new Dictionary<string, JniMethodInfo>(StringComparer.Ordinal);
1717

1818
internal void Dispose ()
1919
{

0 commit comments

Comments
 (0)