diff options
author | Anton Lapounov <antonl@microsoft.com> | 2017-08-04 03:14:30 +0300 |
---|---|---|
committer | Anton Lapounov <antonl@microsoft.com> | 2017-08-04 03:14:30 +0300 |
commit | d1c4689abe76bda148cda44973d7178123265184 (patch) | |
tree | f02a194f31624156ee576d4866879eb1fe618c9a /src/System.Private.Interop | |
parent | 64fb7118f6ef5399ed5969719bf94b829e9041e4 (diff) |
Fix async call performance regression
Bugs:
• https://devdiv.visualstudio.com/DevDiv/_workitems/edit/470211
• https://devdiv.visualstudio.com/DevDiv/_workitems/edit/205405
CR: AdityaM
To schedule an asynchronous call, we perform several WinRT calls to check whether the current thread has either a CoreDispatcher or a DispatcherQueue associated with it. These calls, especially the recently added ones related to DispatcherQueue support, are expensive and make async calls around 3 times slower than on desktop CLR on a microbenchmark.
This change implements a number of optimizations based on a discussion with Windows developers:
• Skip checking for CoreDispatcher/DispatcherQueue on non-[A]STA threads.
• Skip checking for CoreDispatcher for desktop apps. (CoreDispatcher is not supported for desktop apps.)
• Cache the IDispatcherQueueStatics interface pointer instead of calling RoGetActivationFactory on each async call.
• Avoid an unnecessary closure object allocation in FactoryCache.GetActivationFactory.
I had to change WinRTCallbacks.s_resourceContextQualifierMap initialization, because it would crash for desktop apps. (The class constructor would never be called for desktop apps before I added extra static fields.)
I also deleted the orphaned Interop.WinRT.cs file.
[tfs-changeset: 1669116]
Diffstat (limited to 'src/System.Private.Interop')
-rw-r--r-- | src/System.Private.Interop/src/Shared/__ComObject.cs | 18 | ||||
-rw-r--r-- | src/System.Private.Interop/src/WinRT/Interop.WinRT.cs | 95 |
2 files changed, 4 insertions, 109 deletions
diff --git a/src/System.Private.Interop/src/Shared/__ComObject.cs b/src/System.Private.Interop/src/Shared/__ComObject.cs index ea151f4d6..e0856f8bb 100644 --- a/src/System.Private.Interop/src/Shared/__ComObject.cs +++ b/src/System.Private.Interop/src/Shared/__ComObject.cs @@ -3311,8 +3311,6 @@ namespace System.Runtime.InteropServices /// <returns>Return true if winning race. False otherwise</returns> internal bool Assign(IntPtr pComPtr, RuntimeTypeHandle handle) { - // disable warning for ref volatile -#pragma warning disable 0420 if (Interlocked.CompareExchange(ref ptr, pComPtr, default(IntPtr)) == default(IntPtr)) { Debug.Assert(!HasValue, "Entry should be empty"); @@ -3330,7 +3328,6 @@ namespace System.Runtime.InteropServices { return false; } -#pragma warning restore 0420 } /// <summary> @@ -3909,19 +3906,16 @@ namespace System.Runtime.InteropServices /// </summary> internal class FactoryCache { - private Lock m_factoryLock = new Lock(); private System.Collections.Concurrent.ConcurrentDictionary<string, FactoryCacheItem> m_cachedFactories = new System.Collections.Concurrent.ConcurrentDictionary<string, FactoryCacheItem>(); private static volatile FactoryCache s_factoryCache; internal static FactoryCache Get() { -#pragma warning disable 0420 if (s_factoryCache == null) { Interlocked.CompareExchange(ref s_factoryCache, new FactoryCache(), null); } -#pragma warning restore 0420 return s_factoryCache; } @@ -3965,12 +3959,10 @@ namespace System.Runtime.InteropServices FactoryCacheItem cacheItem; - if (!skipCache) { - - if (m_cachedFactories.TryGetValue(className, out cacheItem)) - { + if (m_cachedFactories.TryGetValue(className, out cacheItem)) + { if (cacheItem.contextEntry == currentContext) { // @@ -3978,8 +3970,7 @@ namespace System.Runtime.InteropServices // return cacheItem.factoryObject; } - } - + } } // @@ -3996,12 +3987,11 @@ namespace System.Runtime.InteropServices // // Insert into or update cache // - m_cachedFactories.AddOrUpdate(className, cacheItem, (key, oldValue) => cacheItem); + m_cachedFactories[className] = cacheItem; } return cacheItem.factoryObject; } - } #endif } diff --git a/src/System.Private.Interop/src/WinRT/Interop.WinRT.cs b/src/System.Private.Interop/src/WinRT/Interop.WinRT.cs deleted file mode 100644 index 31a7f252b..000000000 --- a/src/System.Private.Interop/src/WinRT/Interop.WinRT.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; - -partial class Interop -{ - - internal unsafe partial class WinRT - { - // Converts a ASCII (code<0x7f) string to byte array - internal static byte[] AsciiStringToByteArray(string ascii) - { - byte[] ret = new byte[ascii.Length + 1]; - int index; - - for (index = 0; index < ascii.Length; index++) - { - ret[index] = (byte)ascii[index]; - } - - ret[index] = 0; - - return ret; - } - - internal static unsafe void RoGetActivationFactory(string className, ref Guid iid, out IntPtr ppv) - { - fixed (char* unsafe_className = className) - { - void* hstring_typeName = null; - - HSTRING_HEADER hstringHeader; - int hr = - WindowsCreateStringReference( - unsafe_className, (uint)className.Length, &hstringHeader, &hstring_typeName); - - if (hr < 0) - throw Marshal.GetExceptionForHR(hr); - - fixed (Guid* unsafe_iid = &iid) - { - fixed (void* unsafe_ppv = &ppv) - { - hr = ExternalInterop.RoGetActivationFactory( - hstring_typeName, - unsafe_iid, - unsafe_ppv); - - if (hr < 0) - throw Marshal.GetExceptionForHR(hr); - } - } - } - } - - [DllImport(Interop.CORE_WINRT_STRING)] - [McgGeneratedNativeCallCodeAttribute] - [MethodImplAttribute(MethodImplOptions.NoInlining)] - internal static extern unsafe int WindowsCreateString(char* sourceString, uint length, void* hstring); - - [DllImport(Interop.CORE_WINRT_STRING)] - [McgGeneratedNativeCallCodeAttribute] - [MethodImplAttribute(MethodImplOptions.NoInlining)] - internal static extern unsafe int WindowsCreateStringReference( - char* sourceString, uint length, HSTRING_HEADER* phstringHeader, void* hstring); - - [DllImport(Interop.CORE_WINRT_ERROR, PreserveSig = true)] - [McgGeneratedNativeCallCodeAttribute] - public static extern int GetRestrictedErrorInfo(out System.IntPtr pRestrictedErrorInfo); - - [DllImport(Interop.CORE_WINRT_ERROR, PreserveSig = true)] - [McgGeneratedNativeCallCodeAttribute] - [MethodImplAttribute(MethodImplOptions.NoInlining)] - public static extern int RoOriginateError(int hr, HSTRING hstring); - - [DllImport(Interop.CORE_WINRT_ERROR, PreserveSig = true)] - [McgGeneratedNativeCallCodeAttribute] - [MethodImplAttribute(MethodImplOptions.NoInlining)] - public static extern int SetRestrictedErrorInfo(System.IntPtr pRestrictedErrorInfo); - - [DllImport(Interop.CORE_WINRT_ERROR1, PreserveSig = true)] - [McgGeneratedNativeCallCodeAttribute] - internal static extern int RoOriginateLanguageException(int hr, HSTRING message, IntPtr pLanguageException); - - [DllImport(Interop.CORE_WINRT_ERROR1, PreserveSig = true)] - [McgGeneratedNativeCallCodeAttribute] - internal static extern int RoReportUnhandledError(IntPtr pRestrictedErrorInfo); - } - -} |