📄 rminternal.h
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// rminternal.h
//
// Main internal header file for ConcRT's Resource Manager.
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#pragma once
namespace Concurrency
{
namespace details
{
// The lowest two bits are used to determine the type of the pointer stored in the
// execution resource TLS slot (created in the RM).
static const size_t TlsResourceBitMask = 0x3;
static const size_t TlsResourceInResource = 0x0;
static const size_t TlsResourceInProxy = 0x1;
static const size_t TlsResourceInUMSProxy = 0x2;
// The RM has an array of processor nodes and cores representing the hardware topology on the machine.
// Every scheduler that asks for an allocation, gets it's own copy of this array of nodes/cores once they
// have been granted an allocation of cores by the RM, that is stored in the corresponding scheduler proxy.
/// <summary>
/// An abstraction of a hardware affinity that understands how to deal with affinity on both Win7 and pre-Win7
/// platforms.
/// </summary>
struct HardwareAffinity
{
public:
/// <summary>
/// Construct an empty affinity.
/// </summary>
HardwareAffinity()
{
memset(&m_affinity, 0, sizeof(m_affinity));
m_affinity.Group = 0;
m_affinity.Mask = 0;
}
/// <summary>
/// Construct a hardware affinity from a given thread.
/// </summary>
HardwareAffinity(HANDLE hThread);
/// <summary>
/// Construct a Win7 understood affinity.
/// </summary>
HardwareAffinity(USHORT processorGroup, ULONG_PTR affinityMask)
{
memset(&m_affinity, 0, sizeof(m_affinity));
m_affinity.Group = processorGroup;
m_affinity.Mask = affinityMask;
}
/// <summary>
/// Construct a pre-Win7 understood affinity.
/// </summary>
HardwareAffinity(DWORD_PTR affinityMask)
{
memset(&m_affinity, 0, sizeof(m_affinity));
m_affinity.Group = 0;
m_affinity.Mask = affinityMask;
}
/// <summary>
/// Copy construct an affinity.
/// </summary>
HardwareAffinity(const HardwareAffinity &src)
{
memcpy(&m_affinity, &src.m_affinity, sizeof(m_affinity));
}
/// <summary>
/// Compare two affinities
/// </summary>
bool operator==(const HardwareAffinity &rhs)
{
return (rhs.m_affinity.Group == m_affinity.Group && rhs.m_affinity.Mask == m_affinity.Mask);
}
/// <summary>
/// Compare two affinities
/// </summary>
bool operator!=(const HardwareAffinity &rhs)
{
return !operator==(rhs);
}
/// <summary>
/// Copy an affinity.
/// </summary>
HardwareAffinity& operator=(const HardwareAffinity &rhs)
{
m_affinity.Group = rhs.m_affinity.Group;
m_affinity.Mask = rhs.m_affinity.Mask;
return *this;
}
/// <summary>
/// Applies this hardware affinity to a thread.
/// </summary>
/// <param name="hThread">
/// The thread handle to which to apply this affinity.
/// </param>
void ApplyTo(HANDLE hThread);
/// <summary>
/// Initializes the SetThreadGroupAffinity function for Win 7 and higher.
/// </summary>
static void InitializeSetThreadGroupAffinityFn();
private:
// A pointer to a kernel32 function that exists only on Win7 and higher
typedef BOOL (WINAPI *PFnSetThreadGroupAffinity)(HANDLE, PGROUP_AFFINITY, PGROUP_AFFINITY);
static PFnSetThreadGroupAffinity s_pfnSetThreadGroupAffinity;
// A pointer to a kernel32 function that exists only on Win7 and higher
typedef BOOL (WINAPI *PFnGetThreadGroupAffinity)(HANDLE, PGROUP_AFFINITY);
static PFnGetThreadGroupAffinity s_pfnGetThreadGroupAffinity;
GROUP_AFFINITY m_affinity;
};
/// <summary>
/// Base class for description of a core or hardware thread.
/// </summary>
struct ProcessorCore
{
enum CoreState
{
// The core available for allocation
Available = 0,
// The core is allocated to a scheduler
Allocated,
// When cores are freed up from other schedulers, this will be the state they set their copy of the
// core to, while setting the global copy to Available. This will enable them to track the cores they
// have relinquished. If the new scheduler is not allocated this core, it will revert back to Allocated
// for the scheduler proxy it came from.
Stolen,
// The core is reserved for a possible allocation
Reserved,
// A core is considered idle during dynamic core migration if the scheduler(s) that core is assigned
// to, have all vprocs de-activated.
Idle
};
// 'Available' means available for assignment to a scheduler during the allocation calculation.
CoreState m_coreState;
// The processor number in Win7 {group, processor number} id scheme.
BYTE m_processorNumber;
};
/// <summary>
/// Representation of a processor core within the RM's global map of execution resources. Information in this struct
/// represents a systemwide view of the underlying hardware thread.
/// </summary>
struct GlobalCore : public ProcessorCore
{
// The number of schedulers that this core is assigned to.
unsigned int m_useCount;
// Used to send notifications to qualifying schedulers regarding external subscription level changes.
LONG m_currentSubscriptionLevel;
LONG m_previousSubscriptionLevel;
// This field is used during core migration to represent the number of schedulers that this core has been allocated
// to, that have also deactivated all virtual processors on the core, i.e. the number of schedulers that are 'idle'
// with respect to this core. When this is equal to the use count, the core is considered 'idle'.
unsigned int m_idleSchedulers;
};
/// <summary>
/// Representation of a processor core within a scheduler proxy's local map of execution resources. Information in this struct
/// represents the schedulers utilization of the underlying hardware thread.
/// </summary>
struct SchedulerCore : public ProcessorCore
{
// When virtual processor roots are created for a scheduler proxy, or external threads are subscribed, the corresponding
// execution resources are inserted into this list.
List<ExecutionResource, CollectionTypes::Count> m_resources;
// This field represents the number of activated virtual processors and subscribed threads that a scheduler has
// on this core at any time. When a virtual processor root is deactivated, or when a thread subscription is released
// the count is decremented. The core is considered to be 'idle' in the scheduler it belongs to, if this value is 0.
volatile LONG m_subscriptionLevel;
// Used to send notifications to qualifying schedulers regarding external subscription level changes.
LONG m_currentSubscriptionLevel;
LONG m_previousSubscriptionLevel;
// The number of threads that were assigned to this core through initial allocation or core migration.
// Note that this is not necessarily equal to the number of roots in the m_resources list, since the list
// includes oversubscribed vproc roots as well.
unsigned int m_numAssignedThreads;
// The total number of threads (running on vprocs and external) that require this core to be fixed.
unsigned int m_numFixedThreads;
// The number of external threads that run on this core.
unsigned int m_numExternalThreads;
// This is set to true for a scheduler proxy's core during static allocation or core migration if the subscription
// level on the core is found to be 0 when the Dynamic RM worker is executing. The subscription value can change
// as soon as it is captured, but the captured value is what is used for successive computation.
bool m_fIdleDuringDRM;
// This is set to true for a scheduler proxy's core during core migration, if this is an borrowed core.
// An borrowed core is a core that is assigned to one or more different schedulers, but was found to be idle.
// The RM temporarily assigns idle resources to schedulers that need them.
bool m_fBorrowed;
// This variable is set to true when a borrowed core is converted to a fixed core. When the core is unfixed,
// it is marked borrowed again.
bool m_fPreviouslyBorrowed;
/// <summary>
/// Returns whether this core is fixed, i.e., cannot be removed by the RM.
/// </summary>
bool IsFixed()
{
return m_numFixedThreads > 0;
}
/// <summary>
/// Returns whether this core is idle, i.e., its subscription level was 0 at the time it was retreived by the RM.
/// Note that this state could change, but once we capture it, we consider it idle until the next time it is captured.
/// </summary>
bool IsIdle()
{
return m_fIdleDuringDRM;
}
/// <summary>
/// Returns whether this core is borrowed, i.e., it was temporarily lent to this scheduler due to the owning
/// scheduler being idle on this core.
/// </summary>
bool IsBorrowed()
{
return m_fBorrowed;
}
};
/// <summary>
/// Base class for the description of a processor package or NUMA node.
/// </summary>
struct ProcessorNode
{
// affinity mask of node
ULONG_PTR m_nodeAffinity;
// total number of cores in the node
unsigned int m_coreCount;
// number of cores allocated to the scheduler proxy (this field is only applicable to a scheduler proxy's nodes)
unsigned int m_allocatedCores;
// A scratch field used during allocation. The allocation routine works by looking at cores with m_useCount=0,
// grabs all it can, then looks at m_useCount=1, then m_useCount=2, etc... During an allocation attempt at a particular
// use count, cores that are allocated at previous use counts are stored in m_allocatedCores, and cores available at the
// current use count are stored in m_availableForAllocation. A subset of those may be allocated to the scheduler proxy,
// and that number is added to m_allocatedCores before moving on.
unsigned int m_availableForAllocation;
// The group number in Win7 {group, mask} id scheme
unsigned int m_processorGroup;
// The node id which maps to a scheduler node id.
unsigned int m_id;
};
/// <summary>
/// Representation of a processor node within a scheduler proxy's local map of execution resources. Information in this struct
/// represents the schedulers utilization of the underlying node.
/// </summary>
struct SchedulerNode : public ProcessorNode
{
// The number of allocated cores that are borrowed. An borrowed core is a core that is assigned to
// one or more different schedulers, but was found to be idle. The RM temporarily assigns idle resources to
// schedulers that need them.
unsigned int m_numBorrowedCores;
// The number of cores on this node that are considered fixed. Fixed cores cannot be removed by the RM during static/dynamic allocation.
unsigned int m_numFixedCores;
// The number of cores in this node for the scheduler in question that were found to be idle during the dynamic RM phase. This is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -