Don't needlessly refresh proc count (dotnet/coreclr#27543)
authorBen Adams <thundercat@illyriad.co.uk>
Thu, 31 Oct 2019 09:47:57 +0000 (09:47 +0000)
committerKoundinya Veluri <kouvel@users.noreply.github.com>
Thu, 31 Oct 2019 09:47:57 +0000 (02:47 -0700)
Commit migrated from https://github.com/dotnet/coreclr/commit/946e57b61a4db9ccb574fc3a754f783208080947

src/coreclr/src/System.Private.CoreLib/src/System/Environment.CoreCLR.cs
src/coreclr/tests/src/JIT/Directed/pinvoke/pinvoke-examples.cs
src/libraries/System.Private.CoreLib/src/System/Environment.cs
src/libraries/System.Private.CoreLib/src/System/Threading/CancellationTokenSource.cs
src/libraries/System.Private.CoreLib/src/System/Threading/LowLevelLifoSemaphore.cs
src/libraries/System.Private.CoreLib/src/System/Threading/ManualResetEventSlim.cs
src/libraries/System.Private.CoreLib/src/System/Threading/PortableThreadPool.cs
src/libraries/System.Private.CoreLib/src/System/Threading/ReaderWriterLockSlim.cs
src/libraries/System.Private.CoreLib/src/System/Threading/SpinLock.cs
src/libraries/System.Private.CoreLib/src/System/Threading/SpinWait.cs
src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPool.cs

index 5ff86e0..7dc2f38 100644 (file)
@@ -80,11 +80,6 @@ namespace System
                 GetCommandLineArgsNative();
         }
 
-        // Unconditionally return false since .NET Core does not support object finalization during shutdown.
-        public static bool HasShutdownStarted => false;
-
-        public static int ProcessorCount => GetProcessorCount();
-
         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
         private static extern int GetProcessorCount();
 
index 26080d8..d25a24e 100644 (file)
@@ -6,6 +6,7 @@
 // along with the impact of EH.
 
 using System;
+using System.Threading;
 using System.Runtime.CompilerServices;
 
 
@@ -14,20 +15,20 @@ namespace PInvokeTest
     internal class Test
     {
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        static int AsForceInline()
+        static bool AsForceInline()
         {
-            return Environment.ProcessorCount;
+            return Thread.Yield();
         }
 
-        static int AsNormalInline()
+        static bool AsNormalInline()
         {
-            return Environment.ProcessorCount;
+            return Thread.Yield();
         }
 
         [MethodImpl(MethodImplOptions.NoInlining)]
-        static int AsNoInline()
+        static bool AsNoInline()
         {
-            return Environment.ProcessorCount;
+            return Thread.Yield();
         }
 
         static bool FromTryCatch()
@@ -36,7 +37,7 @@ namespace PInvokeTest
             try 
             {
                 // All pinvokes should be inline, except on x64
-                result = (Environment.ProcessorCount == AsNormalInline());
+                result = (Thread.Yield() == AsNormalInline());
             }
             catch (Exception)
             {
@@ -53,8 +54,8 @@ namespace PInvokeTest
             try 
             {
                 // All pinvokes should be inline, except on x64
-                result1 = (Environment.ProcessorCount == AsNormalInline());
-                result2 = (Environment.ProcessorCount == AsNormalInline());
+                result1 = (Thread.Yield() == AsNormalInline());
+                result2 = (Thread.Yield() == AsNormalInline());
             }
             finally
             {
@@ -72,12 +73,12 @@ namespace PInvokeTest
             try 
             {
                 // These two pinvokes should be inline, except on x64
-                result1 = (Environment.ProcessorCount == AsNormalInline());
+                result1 = (Thread.Yield() == AsNormalInline());
             }
             finally
             {
                 // These two pinvokes should *not* be inline (finally)
-                result2 = (Environment.ProcessorCount == AsNormalInline());
+                result2 = (Thread.Yield() == AsNormalInline());
                 result = result1 && result2;
             }
 
@@ -93,14 +94,14 @@ namespace PInvokeTest
             try 
             {
                 // These two pinvokes should be inline, except on x64
-                result1 = (Environment.ProcessorCount == AsNormalInline());
+                result1 = (Thread.Yield() == AsNormalInline());
             }
             finally
             {
                 try 
                 {
                     // These two pinvokes should *not* be inline (finally)
-                    result2 = (Environment.ProcessorCount == AsNormalInline());
+                    result2 = (Thread.Yield() == AsNormalInline());
                 }
                 catch (Exception)
                 {
@@ -117,7 +118,7 @@ namespace PInvokeTest
         static bool FromInline()
         {
             // These two pinvokes should be inline
-            bool result = (Environment.ProcessorCount == AsForceInline());
+            bool result = (Thread.Yield() == AsForceInline());
             return result;
         }
 
@@ -125,8 +126,8 @@ namespace PInvokeTest
         static bool FromInline2()
         {
             // These four pinvokes should be inline
-            bool result1 = (Environment.ProcessorCount == AsNormalInline());
-            bool result2 = (Environment.ProcessorCount == AsForceInline());
+            bool result1 = (Thread.Yield() == AsNormalInline());
+            bool result2 = (Thread.Yield() == AsForceInline());
             return result1 && result2;
         }
 
@@ -134,7 +135,7 @@ namespace PInvokeTest
         static bool FromNoInline()
         {
             // The only pinvoke should be inline
-            bool result = (Environment.ProcessorCount == AsNoInline());
+            bool result = (Thread.Yield() == AsNoInline());
             return result;
         }
 
@@ -142,8 +143,8 @@ namespace PInvokeTest
         static bool FromNoInline2()
         {
             // Three pinvokes should be inline
-            bool result1 = (Environment.ProcessorCount == AsNormalInline());
-            bool result2 = (Environment.ProcessorCount == AsNoInline());
+            bool result1 = (Thread.Yield() == AsNormalInline());
+            bool result2 = (Thread.Yield() == AsNoInline());
             return result1 && result2;
         }
 
@@ -161,10 +162,10 @@ namespace PInvokeTest
             // it just calls get_ProcessorCount.
             //
             // For the second call, the force inline works, and the
-            // subsequent inline of get_ProcessorCount exposes a call
-            // to the pinvoke GetProcessorCount.  This pinvoke will
+            // subsequent inline of Thread.Yield exposes a call
+            // to the pinvoke YieldInternal.  This pinvoke will
             // not be inline.
-            catch (Exception) when (Environment.ProcessorCount == AsForceInline())
+            catch (Exception) when (Thread.Yield() == AsForceInline())
             {
                 result = true;
             }
@@ -174,14 +175,14 @@ namespace PInvokeTest
 
         static bool FromColdCode()
         {
-            int pc = 0;
+            bool yield = false;
             bool result1 = false;
             bool result2 = false;
 
             try
             {
                 // This pinvoke should not be inline (cold)
-                pc = Environment.ProcessorCount;
+                yield = Thread.Yield();
                 throw new Exception("expected");
             }
             catch (Exception)
@@ -189,14 +190,14 @@ namespace PInvokeTest
                 // These two pinvokes should not be inline (catch)
                 //
                 // For the first call the jit won't inline the
-                // wrapper, so it just calls get_ProcessorCount.
+                // wrapper, so it just calls Thread.Yield.
                 //
                 // For the second call, the force inline works, and
-                // the subsequent inline of get_ProcessorCount exposes
-                // a call to the pinvoke GetProcessorCount.  This
+                // the subsequent inline of Thread.Yield exposes
+                // a call to the pinvoke YieldInternal.  This
                 // pinvoke will not be inline.
-                result1 = (pc == Environment.ProcessorCount);
-                result2 = (pc == AsForceInline());
+                result1 = (yield == Thread.Yield());
+                result2 = (yield == AsForceInline());
             }
 
             return result1 && result2;
index ea04f10..1454f1d 100644 (file)
@@ -11,6 +11,16 @@ namespace System
 {
     public static partial class Environment
     {
+        public static int ProcessorCount { get; } = GetProcessorCount();
+
+        /// <summary>
+        /// Gets whether the current machine has only a single processor.
+        /// </summary>
+        internal static bool IsSingleProcessor => ProcessorCount == 1;
+
+        // Unconditionally return false since .NET Core does not support object finalization during shutdown.
+        public static bool HasShutdownStarted => false;
+
         public static string? GetEnvironmentVariable(string variable)
         {
             if (variable == null)
index 1ed5c02..e90d775 100644 (file)
@@ -726,7 +726,7 @@ namespace System.Threading
         /// <returns>A power of 2 representing the number of partitions to use.</returns>
         private static int GetPartitionCount()
         {
-            int procs = PlatformHelper.ProcessorCount;
+            int procs = Environment.ProcessorCount;
             int count =
                 procs > 8 ? 16 : // capped at 16 to limit memory usage on larger machines
                 procs > 4 ? 8 :
index a02dbd8..4e81254 100644 (file)
@@ -88,7 +88,7 @@ namespace System.Threading
                 counts = countsBeforeUpdate;
             }
 
-            int processorCount = PlatformHelper.ProcessorCount;
+            int processorCount = Environment.ProcessorCount;
             int spinIndex = processorCount > 1 ? 0 : SpinSleep0Threshold;
             while (spinIndex < _spinCount)
             {
index e804d38..f15e4ef 100644 (file)
@@ -202,7 +202,7 @@ namespace System.Threading
             Debug.Assert(DEFAULT_SPIN_SP >= 0, "Internal error - DEFAULT_SPIN_SP is outside the legal range.");
             Debug.Assert(DEFAULT_SPIN_SP <= SpinCountState_MaxValue, "Internal error - DEFAULT_SPIN_SP is outside the legal range.");
 
-            SpinCount = PlatformHelper.IsSingleProcessor ? DEFAULT_SPIN_SP : spinCount;
+            SpinCount = Environment.IsSingleProcessor ? DEFAULT_SPIN_SP : spinCount;
         }
 
         /// <summary>
index 3ea1c15..bad6e1f 100644 (file)
@@ -68,7 +68,7 @@ namespace System.Threading
 
         private PortableThreadPool()
         {
-            _minThreads = s_forcedMinWorkerThreads > 0 ? s_forcedMinWorkerThreads : (short)ThreadPoolGlobals.processorCount;
+            _minThreads = s_forcedMinWorkerThreads > 0 ? s_forcedMinWorkerThreads : (short)Environment.ProcessorCount;
             if (_minThreads > MaxPossibleThreadCount)
             {
                 _minThreads = MaxPossibleThreadCount;
index 6267c67..928f4c6 100644 (file)
@@ -53,8 +53,6 @@ namespace System.Threading
     /// </summary>
     public class ReaderWriterLockSlim : IDisposable
     {
-        private static readonly int ProcessorCount = Environment.ProcessorCount;
-
         // Specifying if the lock can be reacquired recursively.
         private readonly bool _fIsReentrant;
 
@@ -1233,7 +1231,7 @@ namespace System.Threading
             const int LockSpinCycles = 20;
 
             // Exponential back-off
-            if ((spinCount < 5) && (ProcessorCount > 1))
+            if ((spinCount < 5) && (Environment.ProcessorCount > 1))
             {
                 Thread.SpinWait(LockSpinCycles * spinCount);
             }
@@ -1563,7 +1561,7 @@ namespace System.Threading
                     Interlocked.Add(ref _enterDeprioritizationState, deprioritizationStateChange);
                 }
 
-                int processorCount = ProcessorCount;
+                int processorCount = Environment.ProcessorCount;
                 for (int spinIndex = 0; ; spinIndex++)
                 {
                     if (spinIndex < LockSpinCount && processorCount > 1)
index d2717e7..0a222dc 100644 (file)
@@ -349,7 +349,7 @@ namespace System.Threading
 
             // *** Step 2, Spinning and Yielding
             var spinner = new SpinWait();
-            if (turn > PlatformHelper.ProcessorCount)
+            if (turn > Environment.ProcessorCount)
             {
                 spinner.Count = SpinWait.YieldThreshold;
             }
index 56ee7c4..1d1b68d 100644 (file)
@@ -86,7 +86,7 @@ namespace System.Threading
         /// depends on the likelihood of the spin being successful and how long the wait would be but those are not accounted
         /// for here.
         /// </remarks>
-        internal static readonly int SpinCountforSpinBeforeWait = PlatformHelper.IsSingleProcessor ? 1 : 35;
+        internal static readonly int SpinCountforSpinBeforeWait = Environment.IsSingleProcessor ? 1 : 35;
 
         // The number of times we've spun already.
         private int _count;
@@ -114,7 +114,7 @@ namespace System.Threading
         /// On a single-CPU machine, <see cref="SpinOnce()"/> always yields the processor. On machines with
         /// multiple CPUs, <see cref="SpinOnce()"/> may yield after an unspecified number of calls.
         /// </remarks>
-        public bool NextSpinWillYield => _count >= YieldThreshold || PlatformHelper.IsSingleProcessor;
+        public bool NextSpinWillYield => _count >= YieldThreshold || Environment.IsSingleProcessor;
 
         /// <summary>
         /// Performs a single spin.
@@ -175,7 +175,7 @@ namespace System.Threading
                     _count >= YieldThreshold &&
                     ((_count >= sleep1Threshold && sleep1Threshold >= 0) || (_count - YieldThreshold) % 2 == 0)
                 ) ||
-                PlatformHelper.IsSingleProcessor)
+                Environment.IsSingleProcessor)
             {
                 //
                 // We must yield.
@@ -346,42 +346,4 @@ namespace System.Threading
         }
         #endregion
     }
-
-    /// <summary>
-    /// A helper class to get the number of processors, it updates the numbers of processors every sampling interval.
-    /// </summary>
-    internal static class PlatformHelper
-    {
-        private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 30000; // How often to refresh the count, in milliseconds.
-        private static volatile int s_processorCount; // The last count seen.
-        private static volatile int s_lastProcessorCountRefreshTicks; // The last time we refreshed.
-
-        /// <summary>
-        /// Gets the number of available processors
-        /// </summary>
-        internal static int ProcessorCount
-        {
-            get
-            {
-                int now = Environment.TickCount;
-                int procCount = s_processorCount;
-                if (procCount == 0 || (now - s_lastProcessorCountRefreshTicks) >= PROCESSOR_COUNT_REFRESH_INTERVAL_MS)
-                {
-                    s_processorCount = procCount = Environment.ProcessorCount;
-                    s_lastProcessorCountRefreshTicks = now;
-                }
-
-                Debug.Assert(procCount > 0,
-                    "Processor count should be greater than 0.");
-
-                return procCount;
-            }
-        }
-
-        /// <summary>
-        /// Gets whether the current machine has only a single processor.
-        /// </summary>
-        /// <remarks>This typically does not change on a machine, so it's checked only once.</remarks>
-        internal static readonly bool IsSingleProcessor = ProcessorCount == 1;
-    }
 }
index f59785a..68cdc6c 100644 (file)
@@ -25,8 +25,6 @@ namespace System.Threading
 {
     internal static class ThreadPoolGlobals
     {
-        public static readonly int processorCount = Environment.ProcessorCount;
-
         public static volatile bool threadPoolInitialized;
         public static bool enableWorkerTracking;
 
@@ -436,7 +434,7 @@ namespace System.Threading
             // by the VM by the time we reach this point.
             //
             int count = numOutstandingThreadRequests;
-            while (count < ThreadPoolGlobals.processorCount)
+            while (count < Environment.ProcessorCount)
             {
                 int prev = Interlocked.CompareExchange(ref numOutstandingThreadRequests, count + 1, count);
                 if (prev == count)