Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
da29c61
Add dependencies
Mar 4, 2020
423d830
Add config var
Mar 4, 2020
ad228ef
Move portable RegisteredWaitHandle implementation to shared ThreadPoo…
Mar 9, 2020
1155fb0
Merge RegisteredWaitHandle implementations
Mar 4, 2020
6f9b3dc
Separate portable-only portion of RegisteredWaitHandle
May 24, 2020
d792cd7
Fix timers, tiered compilation, introduced time-sensitive work item q…
Mar 15, 2020
a911883
Implement ResetThreadPoolThread, set thread names for diagnostics
Mar 15, 2020
40ce9d0
Cache-line-separate PortableThreadPool._numRequestedWorkers similarly…
Mar 16, 2020
a5d3c2b
Post wait completions to the IO completion port on Windows for corecl…
Mar 17, 2020
ad632be
Reroute managed gate thread into unmanaged side to perform gate activ…
Mar 18, 2020
f942773
Flow config values from CoreCLR to the portable thread pool for compat
Mar 22, 2020
0ef2079
Port - 44970522045f0c323f5735c4fe4b54bd8f71e800 - Fix hill climbing f…
Mar 23, 2020
3151057
Port - aa5ce2b1bc9ac553ddd493e269a53c999d61e965 - Limit min threads i…
Mar 23, 2020
5d8d4ae
Port - 8cc2aa35933677339b9e9ec5485754aa750907df - Optimize AdjustMaxW…
Mar 24, 2020
3916619
Fix ETW events
Mar 25, 2020
88ea9c4
Fix perf of counts structs
Mar 27, 2020
8ef63f9
Fix perf of dispatch loop
Mar 28, 2020
e01df4f
Fix perf of ThreadInt64PersistentCounter
Mar 29, 2020
7c89f81
Miscellaneous perf fixes
Apr 1, 2020
13c2d62
Fix starvation heuristic
Jun 1, 2020
dd23472
Implement worker tracking
May 23, 2020
6cd2b2d
Use smaller stack size for threads that don't run user code
May 27, 2020
c8bdfad
Note some SOS dependencies, small fixes in hill climbing to make equi…
Jun 1, 2020
38c00d5
Port some tests from CoreRT
Jun 7, 2020
0ff3b03
Fail-fast in thread pool native entry points specific to thread pool …
Jun 7, 2020
cc35f92
Fix SetMinThreads() and SetMaxThreads() to return true only when both…
Jun 8, 2020
79eb3b9
Fix registered wait removals for fairness since there can be duplicat…
Jun 9, 2020
8b309cc
Allow multiple DotNETRuntime event providers/sources in EventPipe
Jun 12, 2020
ac1917d
Fix registered wait handle timeout logic in the wait thread
Jun 16, 2020
73f911c
Fix Browser build
Jun 22, 2020
1b99da7
Remove unnecessary methods from Browser thread pool, address some fee…
Jun 24, 2020
17b3d2d
Fix build warning after merge
Jun 30, 2020
e8043ff
Address feedback for events, undo EventPipe change in mono, change ev…
Jun 30, 2020
8d9cc2d
Disable new timer test for browser
Jul 1, 2020
f03709b
Fix EventSource tests to expect the new provider name used in mono
Jul 1, 2020
ff48985
Revert event source name in mono to match coreclr
Jul 3, 2020
93563e6
Add issue link for prerequisites of enabling the portable thread pool…
Jul 3, 2020
100dad7
Address feedback
Jul 6, 2020
4c7f778
Fix race condition in registered wait unregister
Jul 11, 2020
d55c5fc
Fix a new issue in WaitThread after shifting items in arrays
Jul 12, 2020
996597f
Fix usage of LowLevelMonitor after rebase
Sep 10, 2020
82f7cda
Fix tests that use RemoteExecutor to include a test for whether it is…
Sep 11, 2020
b53a5b9
Fix build
Sep 11, 2020
7dcb267
Slight fix to starvation heuristic to be closer to what it was before
Sep 25, 2020
65840d8
Fix license headers in new files
Oct 9, 2020
fb28ad2
Address feedback
Oct 9, 2020
04326b6
Change pattern for accessing the event source for better ILLinker com…
Oct 16, 2020
ec038cf
Move hill climbing config reads into constructor instead of passing t…
Oct 16, 2020
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
Prev Previous commit
Next Next commit
Fix timers, tiered compilation, introduced time-sensitive work item q…
…ueue to simulate coreclr behavior
  • Loading branch information
Koundinya Veluri committed Oct 20, 2020
commit d792cd74a5d217c64eb98c1cdb5bef273177506d
Original file line number Diff line number Diff line change
Expand Up @@ -134,27 +134,30 @@ public bool Unregister(WaitHandle waitObject)
private static extern bool UnregisterWaitNative(IntPtr handle, SafeHandle? waitObject);
}

public static partial class ThreadPool
internal sealed class UnmanagedThreadPoolWorkItem : IThreadPoolWorkItem
{
// Time in ms for which ThreadPoolWorkQueue.Dispatch keeps executing work items before returning to the OS
private const uint DispatchQuantum = 30;
private readonly IntPtr _callback;
private readonly IntPtr _state;

public UnmanagedThreadPoolWorkItem(IntPtr callback, IntPtr state)
{
_callback = callback;
_state = state;
}

void IThreadPoolWorkItem.Execute() => ExecuteUnmanagedThreadPoolWorkItem(_callback, _state);

[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void ExecuteUnmanagedThreadPoolWorkItem(IntPtr callback, IntPtr state);
}

public static partial class ThreadPool
{
internal static readonly bool UsePortableThreadPool = InitializeConfigAndDetermineUsePortableThreadPool();
internal static bool SupportsTimeSensitiveWorkItems => UsePortableThreadPool;

internal static readonly bool EnableWorkerTracking = GetEnableWorkerTracking();

internal static bool KeepDispatching(int startTickCount)
{
if (UsePortableThreadPool)
{
return true;
}

// Note: this function may incorrectly return false due to TickCount overflow
// if work item execution took around a multiple of 2^32 milliseconds (~49.7 days),
// which is improbable.
return (uint)(Environment.TickCount - startTickCount) < DispatchQuantum;
}

private static unsafe bool InitializeConfigAndDetermineUsePortableThreadPool()
{
Expand Down Expand Up @@ -346,6 +349,13 @@ internal static void RequestWorkerThread()
public static unsafe bool UnsafeQueueNativeOverlapped(NativeOverlapped* overlapped) =>
PostQueuedCompletionStatus(overlapped);

// Entry point from unmanaged code
private static void UnsafeQueueUnmanagedWorkItem(IntPtr callback, IntPtr state)
{
Debug.Assert(SupportsTimeSensitiveWorkItems);
UnsafeQueueTimeSensitiveWorkItemInternal(new UnmanagedThreadPoolWorkItem(callback, state));
}

// Native methods:

[MethodImpl(MethodImplOptions.InternalCall)]
Expand Down Expand Up @@ -394,7 +404,7 @@ internal static void NotifyWorkItemProgress()
{
if (UsePortableThreadPool)
{
PortableThreadPool.ThreadPoolInstance.NotifyWorkItemComplete();
PortableThreadPool.ThreadPoolInstance.NotifyWorkItemProgress();
return;
}

Expand Down Expand Up @@ -446,4 +456,5 @@ public static bool BindHandle(SafeHandle osHandle)
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool BindIOCompletionCallbackNative(IntPtr fileHandle);
}

}
12 changes: 12 additions & 0 deletions src/coreclr/src/vm/comthreadpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,18 @@ FCIMPLEND

/********************************************************************************************************************/

void QCALLTYPE ThreadPoolNative::ExecuteUnmanagedThreadPoolWorkItem(LPTHREAD_START_ROUTINE callback, LPVOID state)
{
QCALL_CONTRACT;

BEGIN_QCALL;

_ASSERTE(ThreadpoolMgr::UsePortableThreadPool());
callback(state);

END_QCALL;
}

/********************************************************************************************************************/

struct BindIoCompletion_Args
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/src/vm/comthreadpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class ThreadPoolNative
static FCDECL2(FC_BOOL_RET, CorUnregisterWait, LPVOID WaitHandle, Object * objectToNotify);
static FCDECL1(void, CorWaitHandleCleanupNative, LPVOID WaitHandle);
static FCDECL1(FC_BOOL_RET, CorBindIoCompletionCallback, HANDLE fileHandle);

static void QCALLTYPE ExecuteUnmanagedThreadPoolWorkItem(LPTHREAD_START_ROUTINE callback, LPVOID state);
};

class AppDomainTimerNative
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/src/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,9 @@ DEFINE_METHOD(TP_WAIT_CALLBACK, PERFORM_WAIT_CALLBACK, Perf
DEFINE_CLASS(TIMER_QUEUE, Threading, TimerQueue)
DEFINE_METHOD(TIMER_QUEUE, APPDOMAIN_TIMER_CALLBACK, AppDomainTimerCallback, SM_Int_RetVoid)

DEFINE_CLASS(THREAD_POOL, Threading, ThreadPool)
DEFINE_METHOD(THREAD_POOL, UNSAFE_QUEUE_UNMANAGED_WORK_ITEM, UnsafeQueueUnmanagedWorkItem, SM_IntPtr_IntPtr_RetVoid)

DEFINE_CLASS(TIMESPAN, System, TimeSpan)


Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/src/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,12 +656,15 @@ FCFuncStart(gTimerFuncs)
QCFuncElement("DeleteAppDomainTimer", AppDomainTimerNative::DeleteAppDomainTimer)
FCFuncEnd()


FCFuncStart(gRegisteredWaitHandleFuncs)
FCFuncElement("UnregisterWaitNative", ThreadPoolNative::CorUnregisterWait)
FCFuncElement("WaitHandleCleanupNative", ThreadPoolNative::CorWaitHandleCleanupNative)
FCFuncEnd()

FCFuncStart(gUnmanagedThreadPoolWorkItemFuncs)
QCFuncElement("ExecuteUnmanagedThreadPoolWorkItem", ThreadPoolNative::ExecuteUnmanagedThreadPoolWorkItem)
FCFuncEnd()

FCFuncStart(gWaitHandleFuncs)
FCFuncElement("WaitOneCore", WaitHandleNative::CorWaitOneNative)
FCFuncElement("WaitMultipleIgnoringSyncContext", WaitHandleNative::CorWaitMultipleNative)
Expand Down Expand Up @@ -1214,6 +1217,7 @@ FCClassElement("TypeBuilder", "System.Reflection.Emit", gCOMClassWriter)
FCClassElement("TypeLoadException", "System", gTypeLoadExceptionFuncs)
FCClassElement("TypeNameParser", "System", gTypeNameParser)
FCClassElement("TypedReference", "System", gTypedReferenceFuncs)
FCClassElement("UnmanagedThreadPoolWorkItem", "System.Threading", gUnmanagedThreadPoolWorkItemFuncs)
#ifdef FEATURE_UTF8STRING
FCClassElement("Utf8String", "System", gUtf8StringFuncs)
#endif // FEATURE_UTF8STRING
Expand Down
50 changes: 50 additions & 0 deletions src/coreclr/src/vm/tieredcompilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ TieredCompilationManager::TieredCompilationManager() :
m_countOfNewMethodsCalledDuringDelay(0),
m_methodsPendingCountingForTier1(nullptr),
m_tieringDelayTimerHandle(nullptr),
m_doBackgroundWorkTimerHandle(nullptr),
m_isBackgroundWorkScheduled(false),
m_tier1CallCountingCandidateMethodRecentlyRecorded(false),
m_isPendingCallCountingCompletion(false),
Expand Down Expand Up @@ -566,17 +567,65 @@ void TieredCompilationManager::RequestBackgroundWork()
WRAPPER_NO_CONTRACT;
_ASSERTE(m_isBackgroundWorkScheduled);

if (ThreadpoolMgr::UsePortableThreadPool())
{
// QueueUserWorkItem is not intended to be supported in this mode, and there are call sites of this function where
// managed code cannot be called instead to queue a work item. Use a timer with zero due time instead, which would on
// the timer thread call into managed code to queue a work item.

NewHolder<ThreadpoolMgr::TimerInfoContext> timerContextHolder = new ThreadpoolMgr::TimerInfoContext();
timerContextHolder->TimerId = 0;

_ASSERTE(m_doBackgroundWorkTimerHandle == nullptr);
if (!ThreadpoolMgr::CreateTimerQueueTimer(
&m_doBackgroundWorkTimerHandle,
DoBackgroundWorkTimerCallback,
timerContextHolder,
0 /* DueTime */,
(DWORD)-1 /* Period, non-repeating */,
0 /* Flags */))
{
_ASSERTE(m_doBackgroundWorkTimerHandle == nullptr);
ThrowOutOfMemory();
}

timerContextHolder.SuppressRelease(); // the timer context is automatically deleted by the timer infrastructure
return;
}

if (!ThreadpoolMgr::QueueUserWorkItem(StaticBackgroundWorkCallback, this, QUEUE_ONLY, TRUE))
{
ThrowOutOfMemory();
}
}

void WINAPI TieredCompilationManager::DoBackgroundWorkTimerCallback(PVOID parameter, BOOLEAN timerFired)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_PREEMPTIVE;
}
CONTRACTL_END;

_ASSERTE(ThreadpoolMgr::UsePortableThreadPool());
_ASSERTE(timerFired);

TieredCompilationManager *pTieredCompilationManager = GetAppDomain()->GetTieredCompilationManager();
_ASSERTE(pTieredCompilationManager->m_doBackgroundWorkTimerHandle != nullptr);
ThreadpoolMgr::DeleteTimerQueueTimer(pTieredCompilationManager->m_doBackgroundWorkTimerHandle, nullptr);
pTieredCompilationManager->m_doBackgroundWorkTimerHandle = nullptr;

pTieredCompilationManager->DoBackgroundWork();
}

// This is the initial entrypoint for the background thread, called by
// the threadpool.
DWORD WINAPI TieredCompilationManager::StaticBackgroundWorkCallback(void *args)
{
STANDARD_VM_CONTRACT;
_ASSERTE(!ThreadpoolMgr::UsePortableThreadPool());

TieredCompilationManager * pTieredCompilationManager = (TieredCompilationManager *)args;
pTieredCompilationManager->DoBackgroundWork();
Expand All @@ -590,6 +639,7 @@ DWORD WINAPI TieredCompilationManager::StaticBackgroundWorkCallback(void *args)
void TieredCompilationManager::DoBackgroundWork()
{
WRAPPER_NO_CONTRACT;
_ASSERTE(m_doBackgroundWorkTimerHandle == nullptr);

AutoResetIsBackgroundWorkScheduled autoResetIsBackgroundWorkScheduled(this);

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/src/vm/tieredcompilation.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class TieredCompilationManager
void ScheduleBackgroundWork();
private:
void RequestBackgroundWork();
static void WINAPI DoBackgroundWorkTimerCallback(PVOID parameter, BOOLEAN timerFired);
static DWORD StaticBackgroundWorkCallback(void* args);
void DoBackgroundWork();

Expand Down Expand Up @@ -109,13 +110,12 @@ class TieredCompilationManager
UINT32 m_countOfNewMethodsCalledDuringDelay;
SArray<MethodDesc*>* m_methodsPendingCountingForTier1;
HANDLE m_tieringDelayTimerHandle;
HANDLE m_doBackgroundWorkTimerHandle;
bool m_isBackgroundWorkScheduled;
bool m_tier1CallCountingCandidateMethodRecentlyRecorded;
bool m_isPendingCallCountingCompletion;
bool m_recentlyRequestedCallCountingCompletionAgain;

CLREvent m_asyncWorkDoneEvent;

#endif // FEATURE_TIERED_COMPILATION
};

Expand Down
22 changes: 17 additions & 5 deletions src/coreclr/src/vm/win32threadpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4492,6 +4492,7 @@ BOOL ThreadpoolMgr::CreateTimerQueueTimer(PHANDLE phNewTimer,
if (!params.setupSucceeded)
{
CloseHandle(TimerThreadHandle);
*phNewTimer = NULL;
return FALSE;
}

Expand All @@ -4503,8 +4504,6 @@ BOOL ThreadpoolMgr::CreateTimerQueueTimer(PHANDLE phNewTimer,

NewHolder<TimerInfo> timerInfoHolder;
TimerInfo * timerInfo = new (nothrow) TimerInfo;
*phNewTimer = (HANDLE) timerInfo;

if (NULL == timerInfo)
ThrowOutOfMemory();

Expand All @@ -4519,9 +4518,12 @@ BOOL ThreadpoolMgr::CreateTimerQueueTimer(PHANDLE phNewTimer,
timerInfo->ExternalCompletionEvent = INVALID_HANDLE;
timerInfo->ExternalEventSafeHandle = NULL;

*phNewTimer = (HANDLE)timerInfo;

BOOL status = QueueUserAPC((PAPCFUNC)InsertNewTimer,TimerThread,(size_t)timerInfo);
if (FALSE == status)
{
*phNewTimer = NULL;
return FALSE;
}

Expand Down Expand Up @@ -4706,9 +4708,19 @@ DWORD ThreadpoolMgr::FireTimers()

InterlockedIncrement(&timerInfo->refCount);

QueueUserWorkItem(AsyncTimerCallbackCompletion,
timerInfo,
QUEUE_ONLY /* TimerInfo take care of deleting*/);
if (UsePortableThreadPool())
{
GCX_COOP();

ARG_SLOT args[] = { PtrToArgSlot(AsyncTimerCallbackCompletion), PtrToArgSlot(timerInfo) };
MethodDescCallSite(METHOD__THREAD_POOL__UNSAFE_QUEUE_UNMANAGED_WORK_ITEM).Call(args);
}
else
{
QueueUserWorkItem(AsyncTimerCallbackCompletion,
timerInfo,
QUEUE_ONLY /* TimerInfo take care of deleting*/);
}

if (timerInfo->Period != 0 && timerInfo->Period != (ULONG)-1)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public int GetAvailableThreads()
public int ThreadCount => ThreadCounts.VolatileReadCounts(ref _separated.counts).numExistingThreads;
public long CompletedWorkItemCount => _completionCounter.Count;

internal bool NotifyWorkItemComplete()
internal void NotifyWorkItemProgress()
{
_completionCounter.Increment();
Volatile.Write(ref _separated.lastDequeueTime, Environment.TickCount);
Expand All @@ -211,7 +211,11 @@ internal bool NotifyWorkItemComplete()
_hillClimbingThreadAdjustmentLock.Release();
}
}
}

internal bool NotifyWorkItemComplete()
{
NotifyWorkItemProgress();
return !WorkerThread.ShouldStopProcessingWorkNow();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ public sealed partial class RegisteredWaitHandle : MarshalByRefObject

public static partial class ThreadPool
{
internal const bool SupportsTimeSensitiveWorkItems = true;
internal const bool EnableWorkerTracking = false;


public static bool SetMaxThreads(int workerThreads, int completionPortThreads)
{
if (workerThreads < 0 || completionPortThreads < 0)
Expand Down Expand Up @@ -90,14 +90,9 @@ internal static void RequestWorkerThread()
PortableThreadPool.ThreadPoolInstance.RequestWorker();
}

internal static bool KeepDispatching(int startTickCount)
{
return true;
}

internal static void NotifyWorkItemProgress()
{
PortableThreadPool.ThreadPoolInstance.NotifyWorkItemComplete();
PortableThreadPool.ThreadPoolInstance.NotifyWorkItemProgress();
}

internal static bool NotifyWorkItemComplete()
Expand Down
Loading