Skip to content

Commit

Permalink
Don't needlessly refresh proc count (dotnet/coreclr#27543)
Browse files Browse the repository at this point in the history
Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
  • Loading branch information
benaadams authored and dotnet-bot committed Oct 31, 2019
1 parent 18e82ca commit 3607af2
Show file tree
Hide file tree
Showing 9 changed files with 21 additions and 53 deletions.
10 changes: 10 additions & 0 deletions src/Common/src/CoreLib/System/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ private void ExecuteCallbackHandlers(bool throwOnFirstException)
/// <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 :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public bool Wait(int timeoutMs)
counts = countsBeforeUpdate;
}

int processorCount = PlatformHelper.ProcessorCount;
int processorCount = Environment.ProcessorCount;
int spinIndex = processorCount > 1 ? 0 : SpinSleep0Threshold;
while (spinIndex < _spinCount)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ private void Initialize(bool initialState, int spinCount)
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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private struct CacheLineSeparated

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ internal class ReaderWriterCount
/// </summary>
public class ReaderWriterLockSlim : IDisposable
{
private static readonly int ProcessorCount = Environment.ProcessorCount;

// Specifying if the lock can be reacquired recursively.
private readonly bool _fIsReentrant;

Expand Down Expand Up @@ -1233,7 +1231,7 @@ private static void SpinWait(int spinCount)
const int LockSpinCycles = 20;

// Exponential back-off
if ((spinCount < 5) && (ProcessorCount > 1))
if ((spinCount < 5) && (Environment.ProcessorCount > 1))
{
Thread.SpinWait(LockSpinCycles * spinCount);
}
Expand Down Expand Up @@ -1563,7 +1561,7 @@ private void EnterSpin(EnterSpinLockReason reason)
Interlocked.Add(ref _enterDeprioritizationState, deprioritizationStateChange);
}

int processorCount = ProcessorCount;
int processorCount = Environment.ProcessorCount;
for (int spinIndex = 0; ; spinIndex++)
{
if (spinIndex < LockSpinCount && processorCount > 1)
Expand Down
2 changes: 1 addition & 1 deletion src/Common/src/CoreLib/System/Threading/SpinLock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ private void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)

// *** Step 2, Spinning and Yielding
var spinner = new SpinWait();
if (turn > PlatformHelper.ProcessorCount)
if (turn > Environment.ProcessorCount)
{
spinner.Count = SpinWait.YieldThreshold;
}
Expand Down
44 changes: 3 additions & 41 deletions src/Common/src/CoreLib/System/Threading/SpinWait.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public struct SpinWait
/// 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;
Expand Down Expand Up @@ -114,7 +114,7 @@ internal set
/// 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.
Expand Down Expand Up @@ -175,7 +175,7 @@ private void SpinOnceCore(int sleep1Threshold)
_count >= YieldThreshold &&
((_count >= sleep1Threshold && sleep1Threshold >= 0) || (_count - YieldThreshold) % 2 == 0)
) ||
PlatformHelper.IsSingleProcessor)
Environment.IsSingleProcessor)
{
//
// We must yield.
Expand Down Expand Up @@ -346,42 +346,4 @@ public static bool SpinUntil(Func<bool> condition, int millisecondsTimeout)
}
#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;
}
}
4 changes: 1 addition & 3 deletions src/Common/src/CoreLib/System/Threading/ThreadPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -436,7 +434,7 @@ internal void EnsureThreadRequested()
// 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)
Expand Down

0 comments on commit 3607af2

Please sign in to comment.