Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Improve thread pool performance on Unix #6955

Merged
merged 21 commits into from
Feb 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3a27429
Update LowLevelLifoSemaphore to more closely mimic CoreCLR.
filipnavara Feb 5, 2019
5e472b7
Add cache line separation
filipnavara Feb 6, 2019
938f134
Remove support for uninterruptible and/or prioritized waits in WaitSu…
filipnavara Feb 6, 2019
0dc3770
Remove obsolete comment
filipnavara Feb 7, 2019
41f83b9
Rename Wake/WaitForWake to ReleaseCore/WaitCore
filipnavara Feb 7, 2019
265f41a
Rename Counts.ExchangeSubtract to Subtract to reflect the semantics
filipnavara Feb 7, 2019
6b34732
Add missing sealed keyword and Assert
filipnavara Feb 7, 2019
9d2fad4
Make thread pool worker spin count configurable
filipnavara Feb 7, 2019
579bd96
Replicate the spinning algorithm from CLRLifoSemaphore
filipnavara Feb 7, 2019
750db85
Update Counts to use instance methods, add Assert for spinCount >= 0
filipnavara Feb 11, 2019
e7afe31
Revert "Remove support for uninterruptible and/or prioritized waits i…
filipnavara Feb 11, 2019
ddfb816
Switch LowLevelLifoSemaphore.Unix back to WaitSystem implementation
filipnavara Feb 11, 2019
81dc860
Remove obsolete internal API
filipnavara Feb 11, 2019
e60f673
Add comment
filipnavara Feb 11, 2019
2aca3bd
Fix asserts
filipnavara Feb 11, 2019
05e2183
Move more of the spinning logic to LowLevelSpinWaiter
filipnavara Feb 11, 2019
9a3678e
Remove obsolete reference to LowLevelLinq
filipnavara Feb 11, 2019
9435818
Replace SpinYieldThreshold with SpinSleep0Threshold
filipnavara Feb 14, 2019
4678e25
Update Asserts based on feedback
filipnavara Feb 14, 2019
cd0979d
Reorganize the uniprocessor spinning code paths
filipnavara Feb 14, 2019
2a109f3
Use Runtime.RuntimeImports.RhGetProcessCpuCount in LowLevelSpinWaiter…
filipnavara Feb 15, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/System.Private.CoreLib/src/System.Private.CoreLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,12 @@
<Compile Include="System\Threading\ManagedThreadId.cs" />
<Compile Include="System\Threading\Lock.cs" />
<Compile Include="System\Threading\Condition.cs" />
<Compile Include="System\Threading\FirstLevelSpinWaiter.cs" />
<Compile Include="System\Threading\Interlocked.cs" />
<Compile Include="System\Threading\LockHolder.cs" />
<Compile Include="System\Threading\LowLevelLifoSemaphore.cs" />
<Compile Include="System\Threading\LowLevelLock.cs" />
<Compile Include="System\Threading\LowLevelMonitor.cs" />
<Compile Include="System\Threading\LowLevelSpinWaiter.cs" />
<Compile Include="System\Threading\Monitor.cs" />
<Compile Include="System\Threading\ObjectHeader.cs" Condition="'$(UseSyncTable)' == 'true'" />
<Compile Include="System\Threading\Overlapped.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.

using System.Globalization;
using Internal.LowLevelLinq;
using Internal.Runtime.Augments;

namespace System.Threading
Expand All @@ -18,8 +17,16 @@ private static class WorkerThread
/// <summary>
/// Semaphore for controlling how many threads are currently working.
/// </summary>
private static LowLevelLifoSemaphore s_semaphore = new LowLevelLifoSemaphore(0, MaxPossibleThreadCount);

private static LowLevelLifoSemaphore s_semaphore = new LowLevelLifoSemaphore(0, MaxPossibleThreadCount, SemaphoreSpinCount);

/// <summary>
/// Maximum number of spins a thread pool worker thread performs before waiting for work
/// </summary>
private static int SemaphoreSpinCount
{
get => AppContextConfigHelper.GetInt16Config("ThreadPool_UnfairSemaphoreSpinLimit", 70, false);
}

private static void WorkerThreadStart()
{
ClrThreadPoolEventSource.Log.WorkerThreadStart(ThreadCounts.VolatileReadCounts(ref ThreadPoolInstance._separated.counts).numExistingThreads);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,35 @@
// 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.Collections.Generic;

namespace System.Threading
{
/// <summary>
/// A LIFO semaphore.
/// Waits on this semaphore are uninterruptible.
/// </summary>
internal sealed class LowLevelLifoSemaphore : IDisposable
internal sealed partial class LowLevelLifoSemaphore : IDisposable
{
private WaitSubsystem.WaitableObject _semaphore;

public LowLevelLifoSemaphore(int initialSignalCount, int maximumSignalCount)
private void Create(int maximumSignalCount)
{
_semaphore = WaitSubsystem.WaitableObject.NewSemaphore(initialSignalCount, maximumSignalCount);
_semaphore = WaitSubsystem.WaitableObject.NewSemaphore(0, maximumSignalCount);
}

public bool Wait(int timeoutMs)
public void Dispose()
{
return WaitSubsystem.Wait(_semaphore, timeoutMs, false, true);
}

public int Release(int count)
private bool WaitCore(int timeoutMs)
{
return WaitSubsystem.ReleaseSemaphore(_semaphore, count);
return WaitSubsystem.Wait(_semaphore, timeoutMs, false, true);
}

public void Dispose()
private void ReleaseCore(int count)
{
WaitSubsystem.ReleaseSemaphore(_semaphore, count);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@ namespace System.Threading
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365198(v=vs.85).aspx under How I/O Completion Ports Work.
/// From the docs "Threads that block their execution on an I/O completion port are released in last-in-first-out (LIFO) order."
/// </remarks>
internal sealed class LowLevelLifoSemaphore : IDisposable
internal sealed partial class LowLevelLifoSemaphore : IDisposable
{
private IntPtr _completionPort;

public LowLevelLifoSemaphore(int initialSignalCount, int maximumSignalCount)
private void Create(int maximumSignalCount)
{
Debug.Assert(initialSignalCount >= 0, "Windows LowLevelLifoSemaphore does not support a negative signal count"); // TODO: Track actual signal count to enable this
Debug.Assert(maximumSignalCount > 0);
Debug.Assert(initialSignalCount <= maximumSignalCount);

_completionPort =
Interop.Kernel32.CreateIoCompletionPort(new IntPtr(-1), IntPtr.Zero, UIntPtr.Zero, maximumSignalCount);
Expand All @@ -34,7 +32,6 @@ public LowLevelLifoSemaphore(int initialSignalCount, int maximumSignalCount)
exception.HResult = error;
throw exception;
}
Release(initialSignalCount);
}

~LowLevelLifoSemaphore()
Expand All @@ -45,7 +42,7 @@ public LowLevelLifoSemaphore(int initialSignalCount, int maximumSignalCount)
}
}

public bool Wait(int timeoutMs)
public bool WaitCore(int timeoutMs)
{
Debug.Assert(timeoutMs >= -1);

Expand All @@ -54,7 +51,7 @@ public bool Wait(int timeoutMs)
return success;
}

public int Release(int count)
public void ReleaseCore(int count)
{
Debug.Assert(count > 0);

Expand All @@ -68,7 +65,6 @@ public int Release(int count)
throw exception;
}
}
return 0; // TODO: Track actual signal count to calculate this
}

public void Dispose()
Expand Down
Loading