【问题标题】:How to determine which logical cores share the same physical core?如何确定哪些逻辑核心共享同一个物理核心?
【发布时间】:2014-12-11 00:39:56
【问题描述】:

我正在开发一种工具,让学生能够自我评估他们的编程作业的表现。特别是,他们正在编写的程序是多线程的,我无法直接影响创建的线程数量。我想比较他们的程序在不同数量的内核下的性能(理想情况下,他们的程序的加速应该与允许使用的内核数量大致成比例)。

我们可以将位掩码传递给 Process.SetAffinity 来控制程序使用哪些内核。

这在使用超线程并将每个物理核心分成两个逻辑核心的 i5 和 i7 机器上是有问题的。我希望程序在两个/四个不同的物理内核上运行。在我的 i7 机器上,亲和性设置为 3(核心 0 和 1)的进程将与单个核心上的程序运行大致相同(表明这些逻辑核心共享相同的物理核心),但亲和性设置为 5(核心 0 和 3)它将运行得更快(表明这些内核使用不同的物理内核)。但是,我还没有找到可靠的方法(除了反复试验)来确定这一点。

我如何(无需实验)确定哪些逻辑内核共享相同的物理内核?

(/proc/cpuinfo 有我需要的信息,但在 Windows 机器上不可用。)

【问题讨论】:

  • 可能通过WMI (Windows Management Instrumentation) 获得的信息 - 或至少物理/虚拟核心的数量,它可能可以有效地推断为交错位掩码。
  • 看来我忘了提到我正在专门寻找 C# 解决方案。我确实添加了 C# 标签,但我没有在任何地方提到它。我现在在标题中添加了 C#,这应该更清楚我在寻找什么。
  • 正如@user2864740 所说,您可以使用WMI 来发现有关处理器以及物理和虚拟内核数量的信息。亲和掩码的排序方式可能是每个位都是按顺序排列的虚拟处理器。因此,如果您有 2 个物理内核和 4 个虚拟内核(每个物理内核两个虚拟内核),则位 0-1 是第一个物理内核及其虚拟内核,位 2-3 是第二个内核。
  • 另外,请注意,代码在映射到同一物理内核的 HT 内核上的运行速度很可能与在两个单独的物理内核上一样快。在一个物理上测量两个物理与两个逻辑之间的差异仍然是一个好主意,但 HT 实际上是一项非常棒的技术。当然,如果您正在执行大量同步 I/O,则这两种情况之间几乎没有区别,这也是一个有趣的信息。是的,分组的核心将在一个 ID 范围内,因此物理核心与逻辑核心的数量在单 CPU 系统上应该足够了。
  • 我想为这篇文章写一个答案,但我没有足够的时间收集足够的资源和信息。但是,如果您不害怕 C# 中的 COM 调用,请参阅此 SO 帖子:stackoverflow.com/questions/6972437/… 此帖子中的信息与此问题相关,应该可以帮助您找到解决方案。如果您自己解决此问题,请自行发布答案。

标签: c# .net multithreading processor affinity


【解决方案1】:

基于你的问题的 cmets(感谢所有人,尤其是 @RLH)我为你做了这个课程:

/// <summary>
/// Provides CPU information
/// </summary>
public static class Processor
{
    private static IHardwareCore[] cores;
    private static int[] logicalCores;

    /// <summary>
    /// Hardware core
    /// </summary>
    public interface IHardwareCore 
    {
        /// <summary>
        /// Logical core IDs
        /// </summary>
        int[] LogicalCores { get; }
    }

    /// <summary>
    /// Hardware cores
    /// </summary>
    public static IHardwareCore[] HardwareCores
    {
        get
        {
            return cores ?? (cores = GetLogicalProcessorInformation()
                .Where(x => x.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore)
                .Select(x => new HardwareCore((UInt64)x.ProcessorMask))
                .ToArray<IHardwareCore>());
        }
    }

    /// <summary>
    /// All logical core IDs
    /// </summary>
    public static int[] LogicalCores
    {
        get
        {
            return logicalCores ?? (logicalCores = HardwareCores
                .SelectMany(x => x.LogicalCores)
                .ToArray());
        }
    }

    /// <summary>
    /// Current logical core ID
    /// </summary>
    public static int CurrentLogicalCore
    {
        get { return GetCurrentProcessorNumber(); }
    }

    private class HardwareCore : IHardwareCore
    {
        public HardwareCore(UInt64 logicalCoresMask)
        {
            var logicalCores = new List<int>();

            for (var i = 0; i < 64; ++i)
            {
                if (((logicalCoresMask >> i) & 0x1) == 0) continue;
                logicalCores.Add(i);
            }

            LogicalCores = logicalCores.ToArray();
        }

        public int[] LogicalCores { get; private set; }
    }

    #region Exports

    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESSORCORE
    {
        public byte Flags;
    };

    [StructLayout(LayoutKind.Sequential)]
    private struct NUMANODE
    {
        public uint NodeNumber;
    }

    private enum PROCESSOR_CACHE_TYPE
    {
        CacheUnified,
        CacheInstruction,
        CacheData,
        CacheTrace
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct CACHE_DESCRIPTOR
    {
        public byte Level;
        public byte Associativity;
        public ushort LineSize;
        public uint Size;
        public PROCESSOR_CACHE_TYPE Type;
    }

    [StructLayout(LayoutKind.Explicit)]
    private struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
    {
        [FieldOffset(0)]
        public PROCESSORCORE ProcessorCore;
        [FieldOffset(0)]
        public NUMANODE NumaNode;
        [FieldOffset(0)]
        public CACHE_DESCRIPTOR Cache;
        [FieldOffset(0)]
        private UInt64 Reserved1;
        [FieldOffset(8)]
        private UInt64 Reserved2;
    }

    private enum LOGICAL_PROCESSOR_RELATIONSHIP
    {
        RelationProcessorCore,
        RelationNumaNode,
        RelationCache,
        RelationProcessorPackage,
        RelationGroup,
        RelationAll = 0xffff
    }

    private struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
    {
        public UIntPtr ProcessorMask;
        public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
        public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
    }

    [DllImport(@"kernel32.dll", SetLastError = true)]
    private static extern bool GetLogicalProcessorInformation(
        IntPtr Buffer,
        ref uint ReturnLength
    );

    private const int ERROR_INSUFFICIENT_BUFFER = 122;

    private static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] GetLogicalProcessorInformation()
    {
        uint ReturnLength = 0;
        GetLogicalProcessorInformation(IntPtr.Zero, ref ReturnLength);
        if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
        {
            IntPtr Ptr = Marshal.AllocHGlobal((int)ReturnLength);
            try
            {
                if (GetLogicalProcessorInformation(Ptr, ref ReturnLength))
                {
                    int size = Marshal.SizeOf(typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
                    int len = (int)ReturnLength / size;
                    SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] Buffer = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[len];
                    IntPtr Item = Ptr;
                    for (int i = 0; i < len; i++)
                    {
                        Buffer[i] = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)Marshal.PtrToStructure(Item, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
                        Item += size;
                    }
                    return Buffer;
                }
            }
            finally
            {
                Marshal.FreeHGlobal(Ptr);
            }
        }
        return null;
    }

    [DllImport(@"kernel32.dll", SetLastError = true)]
    private static extern int GetCurrentProcessorNumber();

    #endregion
}

使用示例:

for (var i = 0; i < Processor.HardwareCores.Length; ++i)
{
    Console.WriteLine("Hardware Core {0} has logical cores {1}", i,
        string.Join(", ", Processor.HardwareCores[i].LogicalCores));
}
Console.WriteLine("All logical cores: " + string.Join(", ", Processor.LogicalCores));
Console.WriteLine("Current Logical Core is " + Processor.CurrentLogicalCore);

Intel Core i5 的示例输出:

Hardware Core 0 has logical cores 0, 1
Hardware Core 1 has logical cores 2, 3
All logical cores: 0, 1, 2, 3
Current Logical Core is 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-08
    • 1970-01-01
    • 2014-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多