Skip to content

Commit

Permalink
Improve non agile object performance (#1106)
Browse files Browse the repository at this point in the history
* CompareExchange

* Add benchark for non agile objects

* Add another benchmark and cleanup code

* Minor changes

* Agile reference optimizations

* Variable rename

* Add back fallback

Co-authored-by: Joshua Larkin <70237359+j0shuams@users.noreply.github.com>
  • Loading branch information
manodasanW and j0shuams authored Feb 16, 2022
1 parent 0bf67c1 commit 25d83dd
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 139 deletions.
66 changes: 66 additions & 0 deletions src/Benchmarks/NonAgileObjectPerf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using BenchmarkDotNet.Attributes;
using System.Threading;

namespace Benchmarks
{
[MemoryDiagnoser]
public class NonAgileObjectPerf
{
AutoResetEvent createObject;
AutoResetEvent exitThread;
AutoResetEvent objectCreated;
Thread staThread;
private volatile Windows.UI.Popups.PopupMenu nonAgileObject;

[GlobalSetup]
public void Setup()
{
createObject = new AutoResetEvent(false);
exitThread = new AutoResetEvent(false);
objectCreated = new AutoResetEvent(false);
staThread = new Thread(new ThreadStart(ObjectAllocationLoop));
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
}

[GlobalCleanup]
public void Cleanup()
{
exitThread.Set();
createObject.Set();
}

private void ObjectAllocationLoop()
{
while (createObject.WaitOne() && !exitThread.WaitOne(1))
{
createObject.Reset();
nonAgileObject = new Windows.UI.Popups.PopupMenu();
CallObject();
objectCreated.Set();
}
}

private int CallObject()
{
return nonAgileObject.Commands.Count;
}

[Benchmark]
public void ConstructAndQueryNonAgileObject()
{
createObject.Set();
objectCreated.WaitOne();
CallObject();
objectCreated.Reset();
}

[Benchmark]
public void ConstructNonAgileObject()
{
createObject.Set();
objectCreated.WaitOne();
objectCreated.Reset();
}
}
}
15 changes: 7 additions & 8 deletions src/WinRT.Runtime/AgileReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AgileReference : IDisposable
{
private readonly static Guid CLSID_StdGlobalInterfaceTable = new(0x00000323, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
private readonly static Lazy<IGlobalInterfaceTable> Git = new Lazy<IGlobalInterfaceTable>(() => GetGitTable());
private readonly IAgileReference _agileReference;
private readonly IObjectReference _agileReference;
private readonly IntPtr _cookie;
private bool disposed;

Expand All @@ -35,12 +35,8 @@ public unsafe AgileReference(IObjectReference instance)
0 /*AGILEREFERENCE_DEFAULT*/,
ref iid,
instance.ThisPtr,
&agileReference));
#if NET
_agileReference = (IAgileReference)new SingleInterfaceOptimizedObject(typeof(IAgileReference), ObjectReference<ABI.WinRT.Interop.IAgileReference.Vftbl>.Attach(ref agileReference));
#else
_agileReference = ABI.WinRT.Interop.IAgileReference.FromAbi(agileReference).AsType<ABI.WinRT.Interop.IAgileReference>();
#endif
&agileReference));
_agileReference = ObjectReference<IUnknownVftbl>.Attach(ref agileReference);
}
catch(TypeLoadException)
{
Expand All @@ -51,7 +47,10 @@ public unsafe AgileReference(IObjectReference instance)
MarshalInterface<IAgileReference>.DisposeAbi(agileReference);
}
}
public IObjectReference Get() => _cookie == IntPtr.Zero ? _agileReference?.Resolve(IUnknownVftbl.IID) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID);

public IObjectReference Get() => _cookie == IntPtr.Zero ? ABI.WinRT.Interop.IAgileReferenceMethods.Resolve(_agileReference, IUnknownVftbl.IID) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID);

internal ObjectReference<T> Get<T>(Guid iid) => _cookie == IntPtr.Zero ? ABI.WinRT.Interop.IAgileReferenceMethods.Resolve<T>(_agileReference, iid) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID)?.As<T>(iid);

protected virtual void Dispose(bool disposing)
{
Expand Down
148 changes: 68 additions & 80 deletions src/WinRT.Runtime/Interop/IAgileReference.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace WinRT.Interop
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal interface IAgileReference
{
IObjectReference Resolve(Guid riid);
IObjectReference Resolve(Guid riid);
}

[WindowsRuntimeType]
Expand All @@ -37,107 +37,95 @@ internal interface IGlobalInterfaceTable

namespace ABI.WinRT.Interop
{
using global::WinRT;

[DynamicInterfaceCastableImplementation]
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal unsafe interface IAgileReference : global::WinRT.Interop.IAgileReference
{
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
public struct Vftbl
using global::WinRT;

internal static class IAgileReferenceMethods
{
public static unsafe IObjectReference Resolve(IObjectReference _obj, Guid riid)
{
public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
private void* _Resolve;
public delegate* unmanaged[Stdcall]<IntPtr, ref Guid, out IntPtr, int> Resolve { get => (delegate* unmanaged[Stdcall]<IntPtr, ref Guid, out IntPtr, int>)_Resolve; set => _Resolve = value; }

public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
if (_obj == null) return null;

#if !NET
public delegate int ResolveDelegate(IntPtr thisPtr, Guid* riid, IntPtr* objectReference);
private static readonly Delegate[] DelegateCache = new Delegate[1];
#endif
static Vftbl()
var ThisPtr = _obj.ThisPtr;
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
#if !NET
_Resolve = Marshal.GetFunctionPointerForDelegate(DelegateCache[0] = new ResolveDelegate(Do_Abi_Resolve)).ToPointer(),
#else
_Resolve = (delegate* unmanaged<IntPtr, Guid*, IntPtr*, int>)&Do_Abi_Resolve
#endif
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
}

#if NET
[UnmanagedCallersOnly]
#endif
private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference)
finally
{
IObjectReference _objectReference = default;

*objectReference = default;

try
{
_objectReference = global::WinRT.ComWrappersSupport.FindObject<global::WinRT.Interop.IAgileReference>(thisPtr).Resolve(*riid);
*objectReference = _objectReference?.GetRef() ?? IntPtr.Zero;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
MarshalInspectable<object>.DisposeAbi(ptr);
}
}

public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
}

public static unsafe ObjectReference<T> Resolve<T>(IObjectReference _obj, Guid riid)
{
if (_obj == null) return null;

IObjectReference global::WinRT.Interop.IAgileReference.Resolve(Guid riid)
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IAgileReference).TypeHandle));
var ThisPtr = _obj.ThisPtr;

ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.Resolve(ThisPtr, ref riid, out IntPtr ptr));
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
return ComWrappersSupport.GetObjectReferenceForInterface<T>(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}
}

[DynamicInterfaceCastableImplementation]
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal unsafe interface IAgileReference : global::WinRT.Interop.IAgileReference
{
public static IntPtr AbiToProjectionVftablePtr;
static unsafe IAgileReference()
{
AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(IAgileReference), sizeof(global::WinRT.Interop.IUnknownVftbl) + sizeof(IntPtr) * 1);
*(global::WinRT.Interop.IUnknownVftbl*)AbiToProjectionVftablePtr = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl;
((delegate* unmanaged<IntPtr, Guid*, IntPtr*, int>*)AbiToProjectionVftablePtr)[3] = &Do_Abi_Resolve;
}

[UnmanagedCallersOnly]
private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference)
{
IObjectReference _objectReference = default;

*objectReference = default;

try
{
_objectReference = global::WinRT.ComWrappersSupport.FindObject<global::WinRT.Interop.IAgileReference>(thisPtr).Resolve(*riid);
*objectReference = _objectReference?.GetRef() ?? IntPtr.Zero;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
}

IObjectReference global::WinRT.Interop.IAgileReference.Resolve(Guid riid)
{
var _obj = ((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IAgileReference).TypeHandle);
return IAgileReferenceMethods.Resolve(_obj, riid);
}
}

[DynamicInterfaceCastableImplementation]
[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
interface IAgileObject : global::WinRT.Interop.IAgileObject
{
[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public struct Vftbl
{
public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;

public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;

static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}
{
public static IntPtr AbiToProjectionVftablePtr;
static unsafe IAgileObject()
{
AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(IAgileObject), sizeof(global::WinRT.Interop.IUnknownVftbl));
*(global::WinRT.Interop.IUnknownVftbl*)AbiToProjectionVftablePtr = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl;
}

public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);

}

[Guid("00000146-0000-0000-C000-000000000046")]
Expand Down
55 changes: 43 additions & 12 deletions src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace WinRT.Interop
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal interface IAgileReference
{
IObjectReference Resolve(Guid riid);
IObjectReference Resolve(Guid riid);
}

[WindowsRuntimeType]
Expand All @@ -36,7 +36,46 @@ internal interface IGlobalInterfaceTable

namespace ABI.WinRT.Interop
{
using global::WinRT;
using global::WinRT;

internal static class IAgileReferenceMethods
{
public static unsafe IObjectReference Resolve(IObjectReference _obj, Guid riid)
{
if (_obj == null) return null;

var ThisPtr = _obj.ThisPtr;
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}

public static unsafe ObjectReference<T> Resolve<T>(IObjectReference _obj, Guid riid)
{
if (_obj == null) return null;

var ThisPtr = _obj.ThisPtr;
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface<T>(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}
}

[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal sealed unsafe class IAgileReference : global::WinRT.Interop.IAgileReference
Expand Down Expand Up @@ -104,16 +143,8 @@ public IAgileReference(ObjectReference<Vftbl> obj)

public IObjectReference Resolve(Guid riid)
{
ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.Resolve(ThisPtr, ref riid, out IntPtr ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}
return IAgileReferenceMethods.Resolve(_obj, riid);
}
}

[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
Expand Down
Loading

0 comments on commit 25d83dd

Please sign in to comment.