Skip to content

Commit 9b7feaa

Browse files
Therzokrolfbjarne
authored andcommitted
Performance improvements (dotnet#938)
* [Perf] Use Runtime.IntPtrEqualityComparer everywhere This avoid boxing the key for Dictionaries which take IntPtr as keys. * [Perf] Avoid Tuple allocations and boxing of tuple items The default implementation of Tuple IEquatable uses EqualityComparer<Object>.Default, which causes boxing for IntPtr. Implement a hand-made IntPtr-Type tuple that also uses custom comparers defined Runtime, for IntPtr and Type equality. This should improve allocations done by GetDelegateForBlock
1 parent 462a3c7 commit 9b7feaa

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

src/AudioToolbox/MusicSequence.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ internal MusicSequence (IntPtr handle) {
4545
this.handle = handle;
4646
}
4747

48-
static Dictionary <IntPtr, MusicSequenceUserCallback> userCallbackHandles = new Dictionary <IntPtr, MusicSequenceUserCallback> ();
48+
static Dictionary <IntPtr, MusicSequenceUserCallback> userCallbackHandles = new Dictionary <IntPtr, MusicSequenceUserCallback> (Runtime.IntPtrEqualityComparer);
4949

5050
static MusicSequenceUserCallbackProxy userCallbackProxy = new MusicSequenceUserCallbackProxy (UserCallbackProxy);
5151

src/CoreFoundation/CFMessagePort.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ struct ContextProxy {
5555

5656
delegate void CFMessagePortInvalidationCallBackProxy (/* CFMessagePortRef */ IntPtr messagePort, /* void * */ IntPtr info);
5757

58-
static Dictionary <IntPtr, CFMessagePortCallBack> outputHandles = new Dictionary <IntPtr, CFMessagePortCallBack> ();
58+
static Dictionary <IntPtr, CFMessagePortCallBack> outputHandles = new Dictionary <IntPtr, CFMessagePortCallBack> (Runtime.IntPtrEqualityComparer);
5959

60-
static Dictionary <IntPtr, Action> invalidationHandles = new Dictionary <IntPtr, Action> ();
60+
static Dictionary <IntPtr, Action> invalidationHandles = new Dictionary <IntPtr, Action> (Runtime.IntPtrEqualityComparer);
6161

62-
static Dictionary <IntPtr, CFMessagePortContext> messagePortContexts = new Dictionary <IntPtr, CFMessagePortContext> ();
62+
static Dictionary <IntPtr, CFMessagePortContext> messagePortContexts = new Dictionary <IntPtr, CFMessagePortContext> (Runtime.IntPtrEqualityComparer);
6363

6464
static CFMessagePortCallBackProxy messageOutputCallback = new CFMessagePortCallBackProxy (MessagePortCallback);
6565

src/CoreMedia/CMBufferQueue.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ protected virtual void Dispose (bool disposing)
113113

114114
internal CMBufferQueue (int count)
115115
{
116-
queueObjects = new Dictionary<IntPtr,INativeObject> (count);
116+
queueObjects = new Dictionary<IntPtr,INativeObject> (count, Runtime.IntPtrEqualityComparer);
117117
gch = GCHandle.Alloc (this);
118118
}
119119

src/ObjCRuntime/DynamicRegistrar.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public Dictionary<IntPtr, MethodDescription> GetMethods (Type type)
119119
RegisterType (type);
120120

121121
if (!method_map.TryGetValue (type, out methods)) {
122-
methods = new Dictionary <IntPtr, MethodDescription> ();
122+
methods = new Dictionary <IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer);
123123
method_map [type] = methods;
124124
}
125125

@@ -804,7 +804,7 @@ monotouch.dll since we don't link all frameworks most of the time. */
804804
if (type.IsFakeProtocol)
805805
return;
806806

807-
var methods = new Dictionary <IntPtr, MethodDescription> ();
807+
var methods = new Dictionary <IntPtr, MethodDescription> (Runtime.IntPtrEqualityComparer);
808808

809809
var super = type.SuperType;
810810

src/ObjCRuntime/Runtime.cs

+47-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public partial class Runtime {
3636
internal const bool IsUnifiedBuild = false;
3737
#endif
3838

39-
static Dictionary<Tuple<IntPtr,Type>,Delegate> block_to_delegate_cache;
39+
static Dictionary<IntPtrTypeValueTuple,Delegate> block_to_delegate_cache;
4040

4141
static List <object> delegates;
4242
static List <Assembly> assemblies;
@@ -753,13 +753,13 @@ static Delegate CreateBlockProxy (MethodInfo method, IntPtr block)
753753
static Delegate GetDelegateForBlock (IntPtr methodPtr, Type type)
754754
{
755755
if (block_to_delegate_cache == null)
756-
block_to_delegate_cache = new Dictionary<Tuple<IntPtr, Type>, Delegate> ();
756+
block_to_delegate_cache = new Dictionary<IntPtrTypeValueTuple, Delegate> ();
757757

758758
// We do not care if there is a race condition and we initialize two caches
759759
// since the worst that can happen is that we end up with an extra
760760
// delegate->function pointer.
761761
Delegate val;
762-
var pair = new Tuple<IntPtr, Type> (methodPtr, type);
762+
var pair = new IntPtrTypeValueTuple (methodPtr, type);
763763
lock (block_to_delegate_cache) {
764764
if (block_to_delegate_cache.TryGetValue (pair, out val))
765765
return val;
@@ -1356,4 +1356,48 @@ public int GetHashCode (Type obj)
13561356
return obj.GetHashCode ();
13571357
}
13581358
}
1359+
1360+
internal struct IntPtrTypeValueTuple : IEquatable<IntPtrTypeValueTuple>
1361+
{
1362+
static readonly IEqualityComparer<IntPtr> item1Comparer = Runtime.IntPtrEqualityComparer;
1363+
static readonly IEqualityComparer<Type> item2Comparer = Runtime.TypeEqualityComparer;
1364+
1365+
public readonly IntPtr Item1;
1366+
public readonly Type Item2;
1367+
1368+
public IntPtrTypeValueTuple (IntPtr item1, Type item2)
1369+
{
1370+
Item1 = item1;
1371+
Item2 = item2;
1372+
}
1373+
1374+
public bool Equals (IntPtrTypeValueTuple other)
1375+
{
1376+
return item1Comparer.Equals (Item1, other.Item1) &&
1377+
item2Comparer.Equals (Item2, other.Item2);
1378+
}
1379+
1380+
public override bool Equals (object obj)
1381+
{
1382+
if (obj is IntPtrTypeValueTuple)
1383+
return Equals ((IntPtrTypeValueTuple)obj);
1384+
1385+
return false;
1386+
}
1387+
1388+
public override int GetHashCode ()
1389+
{
1390+
return item1Comparer.GetHashCode (Item1) ^ item2Comparer.GetHashCode (Item2);
1391+
}
1392+
1393+
public static bool operator == (IntPtrTypeValueTuple left, IntPtrTypeValueTuple right)
1394+
{
1395+
return left.Equals(right);
1396+
}
1397+
1398+
public static bool operator != (IntPtrTypeValueTuple left, IntPtrTypeValueTuple right)
1399+
{
1400+
return !left.Equals(right);
1401+
}
1402+
}
13591403
}

0 commit comments

Comments
 (0)