From 3aa61c74692a2d240dfea7dc0929c74999e0ed36 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 22 Nov 2016 20:48:53 -0500 Subject: [PATCH] Cache result of GetCurrentProcessorNumber --- .../TlsOverPerCoreLockedStacksArrayPool.Unix.cs | 2 +- .../TlsOverPerCoreLockedStacksArrayPool.Windows.cs | 2 +- .../Buffers/TlsOverPerCoreLockedStacksArrayPool.cs | 37 ++++++++++++++++++++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Unix.cs b/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Unix.cs index aa729e8..2a0b1f7 100644 --- a/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Unix.cs +++ b/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Unix.cs @@ -19,7 +19,7 @@ namespace System.Buffers // doesn't exist on all platforms. On those it doesn't exist on, GetCurrentProcessorNumber // returns -1. As a fallback in that case and to spread the threads across the buckets // by default, we use the current managed thread ID as a proxy. - int id = Win32Native.GetCurrentProcessorNumber(); + int id = GetCurrentProcessorNumber(); if (id < 0) id = Environment.CurrentManagedThreadId; return id; } diff --git a/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Windows.cs b/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Windows.cs index 0c4c464..4ec158d 100644 --- a/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Windows.cs +++ b/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.Windows.cs @@ -14,7 +14,7 @@ namespace System.Buffers private static int ExecutionId { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return Win32Native.GetCurrentProcessorNumber(); } + get { return GetCurrentProcessorNumber(); } } } } diff --git a/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs b/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs index a4bed13..3d2b1e2 100644 --- a/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs +++ b/src/mscorlib/corefx/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs @@ -46,6 +46,11 @@ namespace System.Buffers /// A per-thread array of arrays, to cache one array per array size per thread. [ThreadStatic] private static T[][] t_tlsBuckets; + /// + /// Cached processor number used as a hint for which per-core stack to access. + /// + [ThreadStatic] + private static int? t_cachedProcessorNumber; /// Initialize the pool. public TlsOverPerCoreLockedStacksArrayPool() @@ -68,6 +73,19 @@ namespace System.Buffers /// Gets an ID for the pool to use with events. private int Id => GetHashCode(); + /// Gets the processor number associated with the current thread. + /// Uses a cached value if one exists on the current thread. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetCurrentProcessorNumber() + { + int? num = t_cachedProcessorNumber; + if (!num.HasValue) + { + t_cachedProcessorNumber = num = Win32Native.GetCurrentProcessorNumber(); + } + return num.GetValueOrDefault(); + } + public override T[] Rent(int minimumLength) { // Arrays can't be smaller than zero. We allow requesting zero-length arrays (even though @@ -265,7 +283,7 @@ namespace System.Buffers public bool TryPush(T[] array) { bool enqueued = false; - Monitor.Enter(this); + MonitorEnterWithProcNumberFlush(this); if (_count < MaxBuffersPerArraySizePerCore) { _arrays[_count++] = array; @@ -279,7 +297,7 @@ namespace System.Buffers public T[] TryPop() { T[] arr = null; - Monitor.Enter(this); + MonitorEnterWithProcNumberFlush(this); if (_count > 0) { arr = _arrays[--_count]; @@ -288,6 +306,21 @@ namespace System.Buffers Monitor.Exit(this); return arr; } + + /// + /// Enters the monitor on the object. If there is any contention while trying + /// to acquire the monitor, it flushes the cached processor number so that subsequent + /// attempts to access the per-core stacks will use an updated processor number. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void MonitorEnterWithProcNumberFlush(object obj) + { + if (!Monitor.TryEnter(obj)) + { + t_cachedProcessorNumber = null; + Monitor.Enter(obj); + } + } } } } -- 2.7.4