我正在研究一种工具,让学生自我评估他们的编程作业的表现。特别是,他们编写的程序是多线程的,我没有直接的方法来影响创建的线程数。我想比较一下不同内核数量的程序性能(理想情况下,它们的程序应该大致按照允许使用的内核数量的比例加速)。
我们可以将一个位掩码传递给Process.SetAffinity来控制程序使用的核心。
这在i5和i7机器上存在问题,这些机器使用超线程并将每个物理核心拆分为两个逻辑核心。我希望程序在两个/四个不同的物理内核上运行。在我的i7机器上,亲和力设置为3(核心0和1)的进程将大致与单个核心上的程序一样快(表示这些逻辑核心共享相同的物理核心),但亲和力设置为5(核心) 0& 3)它运行得更快(表明这些内核使用不同的物理内核)。但是,我没有找到一种可靠的方法(除了反复试验)来确定这一点。
我如何(没有实验)确定哪些逻辑核心共享同一个物理核心?
(/ proc / cpuinfo有我需要的信息,但在Windows机器上不可用。)
答案 0 :(得分:5)
基于对你的问题的评论(感谢所有人,尤其是@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