📄 schedulerproxy.h
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// SchedulerProxy.h
//
// RM proxy for a scheduler instance
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
namespace Concurrency
{
namespace details
{
class SchedulerProxy : public ::Concurrency::ISchedulerProxy
{
public:
/// <summary>
/// Constructs a scheduler proxy.
/// </summary>
SchedulerProxy(IScheduler * pScheduler, ResourceManager * pResourceManager, const SchedulerPolicy &policy);
/// <summary>
/// Called in order to notify the resource manager that the given scheduler is shutting down. This
/// will cause the resource manager to immediately reclaim all resources granted to the scheduler.
/// </summary>
virtual void Shutdown();
/// <summary>
/// Called by a scheduler in order make an initial request for an allocation of virtual processors. The request
/// is driven by policies within the scheduler queried via the IScheduler::GetPolicy method. If the request
/// can be satisfied via the rules of allocation, it is communicated to the scheduler as a call to
/// IScheduler::AddVirtualProcessors.
/// </summary>
/// <param name="doSubscribeCurrentThread">
/// Whether to subscribe the current thread and account for it during resource allocation.
/// </param>
/// <returns>
/// The IExecutionResource instance representing current thread if doSubscribeCurrentThread was true; NULL otherwise.
/// </returns>
virtual IExecutionResource * RequestInitialVirtualProcessors(bool doSubscribeCurrentThread);
/// <summary>
/// Ensures that a context is bound to a thread proxy. This API should *NOT* be called in the vast majority of circumstances.
/// The IThreadProxy::SwitchTo will perform late binding to thread proxies as necessary. There are, however, circumstances
/// where it is necessary to pre-bind a context to ensure that the SwitchTo operation switches to an already bound context. This
/// is the case on a UMS scheduling context as it cannot call allocation APIs.
/// </summary>
/// <param name="pContext">
/// The context to bind.
/// </param>
virtual void BindContext(IExecutionContext * pContext);
/// <summary>
/// Returns an **unstarted** thread proxy attached to pContext, to the thread proxy factory.
/// Such a thread proxy **must** be unstarted.
/// This API should *NOT* be called in the vast majority of circumstances.
/// </summary>
/// <param name="pContext">
/// The context to unbind.
/// </param>
virtual void UnbindContext(IExecutionContext * pContext);
/// <summary>
/// This API registers the current thread with the resource manager associating it with this scheduler,
/// and returns an instance of IExecutionResource back to the scheduler, for bookkeeping and maintenance.
/// </summary>
/// <returns>
/// The IExecutionResource instance representing current thread in the runtime.
/// </returns>
virtual IExecutionResource * SubscribeCurrentThread();
/// <summary>
/// The unique identifier of the scheduler this proxy represents.
/// </summary>
unsigned int GetId() const
{
return m_id;
}
/// <summary>
/// Causes the resource manager to create a new virtual processor root running atop the same hardware thread as this
/// execution resource. Typically, this is used when a scheduler wishes to oversubscribe a particular hardware thread
/// for a limited amount of time.
/// </summary>
/// <param name="pExecutionResource">
/// The execution resource abstraction on which to oversubscribe.
/// </param>
/// <returns>
/// A new virtual processor root running atop the same hardware thread as this execution resource.
/// </returns>
virtual IVirtualProcessorRoot * CreateOversubscriber(IExecutionResource * pExecutionResource);
/// <summary>
/// Getters for the various policy elements.
/// </summary>
unsigned int MaxConcurrency() const
{
return m_maxConcurrency;
}
unsigned int MinConcurrency() const
{
return m_minConcurrency;
}
unsigned int TargetOversubscriptionFactor() const
{
return m_targetOversubscriptionFactor;
}
int ContextStackSize () const
{
return m_contextStackSize;
}
int ContextPriority () const
{
return m_contextPriority;
}
unsigned int MinVprocHWThreads() const
{
// Compute number of cores used for virtual processors that are fixed
ASSERT(m_numFixedCores >= m_numExternalThreadCores);
unsigned int fixedVprocCores = m_numFixedCores - m_numExternalThreadCores;
// Compute maximum(t1, minimum set by policy) which is minimum of virtual processor cores
return max(fixedVprocCores, m_minimumHardwareThreads);
}
unsigned int MinHWThreads() const
{
// The minimum needed number of hardware threads (cores) is equal to:
// - minimum needed vproc cores + minimum needed external thread cores
unsigned int minimumCores = MinVprocHWThreads() + m_numExternalThreadCores;
ASSERT(minimumCores <= m_physicalResourceCount);
return minimumCores;
}
unsigned int DesiredHWThreads() const
{
unsigned int desiredCores = min(m_physicalResourceCount, m_desiredHardwareThreads + m_numExternalThreadCores);
ASSERT(m_numExternalThreads != 0 || desiredCores == m_desiredHardwareThreads);
return desiredCores;
}
unsigned int ComputeMinHWThreadsWithExternalThread() const
{
unsigned int newMin = min(m_physicalResourceCount, MinHWThreads() + 1);
return newMin;
}
unsigned int ComputeDesiredHWThreadsWithExternalThread() const
{
unsigned int newDesired = min(m_physicalResourceCount, DesiredHWThreads() + 1);
return newDesired;
}
/// <summary>
/// Returns the number of external thread subscriptions
/// </summary>
unsigned int GetNumNestedThreadSubscriptions()
{
return m_threadSubscriptions.Count();
}
/// <summary>
/// Called to adjust the suggested allocation such that we do not exceed maxConcurrency.
/// This routine takes into account vprocs that are marked for removal but haven't yet been
/// retired by the scheduler. The suggested allocation would be decreased to account for such
/// vprocs.
/// </summary>
unsigned int AdjustAllocationIncrease(unsigned int suggestedAllocation) const;
/// <summary>
/// Returns the number of cores allocated to the proxy at any time.
/// </summary>
unsigned int GetNumAllocatedCores() const
{
return m_numAllocatedCores;
}
/// <summary>
/// Returns the number of borrowed cores. These are cores that were oversubscribed and temporarily
/// assigned to this scheduler during dynamic core migration as they were found to be unused
/// by the other scheduler(s) they were assigned to. The reason these cores were oversubscribed
/// instead of migrated was that they contributed to the minimum number of cores on the other
/// scheduler(s) and hence couldn't be taken away.
/// </summary>
unsigned int GetNumBorrowedCores() const
{
return m_numBorrowedCores;
}
/// <summary>
/// Returns the number of owned cores. This is the total allocated cores minus the borrowed cores.
/// </summary>
unsigned int GetNumOwnedCores() const
{
return m_numAllocatedCores - m_numBorrowedCores;
}
/// <summary>
/// Returns the number of fixed cores - cores that have a subscribed thread on them.
/// </summary>
unsigned int GetNumFixedCores() const
{
return m_numFixedCores;
}
/// <summary>
/// Tells if cores were stolen from this proxy during the course of a new allocation.
/// </summary>
bool GetCoresStolen() const
{
return m_fCoresStolen;
}
/// <summary>
/// Sets or clears a flag indicating the RM is stealing cores from this proxy to satsify a new scheduler's
/// allocation.
/// </summary>
void SetCoresStolen(bool stolen)
{
m_fCoresStolen = stolen;
}
/// <summary>
/// Toggles the state on a core from borrowed to owned (and vice versa), and updates necessary counts.
/// </summary>
void ToggleBorrowedState(SchedulerNode * pNode, unsigned int coreIndex);
/// <summary>
/// Creates a new execution resource for the external thread and registers it with the scheduler proxy.
/// </summary>
ExecutionResource * CreateExternalThreadResource(SchedulerNode * pNode, unsigned int coreIndex);
/// <summary>
/// Called by the RM when it is done allocating cores for the scheduler proxy. Gives the proxy
/// an array of nodes and cores.
/// </summary>
ExecutionResource * GrantAllocation(SchedulerNode * pAllocatedNodes, unsigned int nodeCount, unsigned int numberAllocated, bool doExternalThreadAllocation);
/// <summary>
/// Finds the core allocated by the RM on which a single subscribed external thread should run.
/// </summary>
ExecutionResource * GrantExternalThreadAllocation(bool doOversubscribeCore);
/// <summary>
/// Returns a pointer to the copy of allocated nodes that were assigned to the proxy at
/// creation time.
/// </summary>
SchedulerNode * GetAllocatedNodes() const
{
return m_pAllocatedNodes;
}
/// <summary>
/// Returns a pointer to the array that holds the sorted order for nodes. This is used by the
/// RM to sort nodes by whatever criteria it chooses.
/// </summary>
unsigned int * GetSortedNodeOrder() const
{
return m_pSortedNodeOrder;
}
/// <summary>
/// Returns a pointer to the scheduler associated with the sheduler proxy.
/// </summary>
IScheduler * Scheduler() const
{
return m_pScheduler;
}
/// <summary>
/// Returns a pointer to the resource manager associated with the scheduler proxy.
/// </summary>
ResourceManager * GetResourceManager() const
{
return m_pResourceManager;
}
/// <summary>
/// Returns a pointer to a data buffer that is used to store static allocation data. The data
/// is populated and manipulated by the RM, but stored in the scheduler proxy for convenience.
/// </summary>
StaticAllocationData * GetStaticAllocationData()
{
return &m_staticData;
}
/// <summary>
/// Returns a pointer to a data buffer that is used to store dynamic allocation data. The data
/// is populated and manipulated by the RM, but stored in the scheduler proxy for convenience.
/// </summary>
DynamicAllocationData * GetDynamicAllocationData()
{
return &m_dynamicData;
}
/// <summary>
/// Creates a virtual processor root and adds it to the scheduler proxys list of roots.
/// </summary>
virtual VirtualProcessorRoot * CreateVirtualProcessorRoot(SchedulerNode * pNode, unsigned int coreIndex);
/// <summary>
/// Notifies the scheduler associated with this proxy to add the virtual processor roots provided.
/// Called by the RM during initial allocation and dynamic core migration.
/// </summary>
void AddVirtualProcessorRoots(IVirtualProcessorRoot ** vprocRoots, unsigned int count);
/// <summary>
/// Adds an appropriate number of virtual processor roots to the scheduler associated with this proxy.
/// Called by the RM during core migration when the RM decides to give this scheduler an additional
/// core.
/// </summary>
void AddCore(SchedulerNode * pNode, unsigned int coreIndex, bool fBorrowed);
/// <summary>
/// Notifies the scheduler associated with this proxy to remove the virtual processor roots associated
/// with the core provided. Called by the RM during core migration.
/// </summary>
void RemoveCore(SchedulerNode * pNode, unsigned int coreIndex);
/// <summary>
/// Called by the RM to instruct this scheduler proxy to notify its scheduler that this core is now
/// externally busy or externally idle.
/// </summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -