检测是否存在多个CPU kGroups或NUMA节点

时间:2017-05-01 23:12:28

标签: c# wmi pinvoke cpu numa

我想在C#中编写一个工具,它可以检测Windows中是否存在多个CPU组。我已经看到这被称为kGroups,也被称为NUMA节点。

这种需求源于多个与性能相关的问题,我们发现客户正在运行HP服务器,这些服务器通常将BIOS中的NUMA组大小优化设置为" Clustered"而不是" Flat"这可能导致Windows中的多个CPU组。除非另有设计为跨kGroup运行,否则任何一个进程只能使用kGroup中设置进程关联的逻辑处理器。

我找到了许多可以检测有关物理/逻辑处理器数量的信息的资源,但是我无法找到有关这些CPU是否/如何进行逻辑分组的信息。我可以通过p / invoke或WMI等方法获取此信息。

编辑:通过p / invoke找到以下帖子,其中包含GetLogicalProcessorInformationEx调用的完整示例。当我可以确认如何测试numa节点配置时会更新。

https://stackoverflow.com/a/6972620/3736007

参考:http://h17007.www1.hpe.com/docs/iss/proliant_uefi/UEFI_Gen9_060216/s_set_NUMA_group.html

解决了(我想)。我能够使用David Heffernan的c#实现,将它包装在一个类中,并添加了一些属性来返回我之后的一些信息。不安全的代码对我来说仍然是一个黑魔法所以我知道它可以做得更好,但它到目前为止工作。

public static class LogicalProcessorInformation
{
    public static int CpuPackages
    {
        get
        {
            if (_buffer == null)
                _buffer = MyGetLogicalProcessorInformation();
            return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage);
        }
    }

    public static int CpuCores
    {
        get
        {
            if (_buffer == null)
                _buffer = MyGetLogicalProcessorInformation();
            return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore);
        }
    }

    public static int LogicalProcessors
    {
        get
        {
            if (_buffer == null)
                _buffer = MyGetLogicalProcessorInformation();
            var count = 0;
            foreach (var obj in _buffer.Where(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore))
            {
                count += CountSetBits(obj.ProcessorMask);
            }
            return count;
        }
    }

    public static int CpuGroups
    {
        get
        {
            if (_buffer == null)
                _buffer = MyGetLogicalProcessorInformation();
            return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup);
        }
    }

    public static int NumaNodes
    {
        get
        {
            if (_buffer == null)
                _buffer = MyGetLogicalProcessorInformation();
            return _buffer.Count(b => b.Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode);
        }
    }

    private static int CountSetBits(UIntPtr bitMask)
    {
        // todo: get rid of tostring and figure out the right way.
        var bitMaskuint = uint.Parse(bitMask.ToString());
        uint count = 0;
        while (bitMaskuint != 0)
        {
            count += bitMaskuint & 1;
            bitMaskuint >>= 1;
        }

        return (int)count;
    }

    private static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] _buffer;

    [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[] MyGetLogicalProcessorInformation()
    {
        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;
    }
}

0 个答案:

没有答案