I am working on a tool to allow students to self-evaluate their programming assignment's performance. In particular, the program they're writing is multi-threaded and I have no direct way of influencing the number of threads created. I would like to compare the performance of their programs given a different number of cores (and ideally, their programs should speed up roughly proportionally to how many cores it is allowed to use).
We can pass a bitmask to Process.SetAffinity to control which cores the program uses.
This is problematic on i5 and i7 machines that use hyper-threading and split each physical core in to two logical ones. I want the program to run on two/four distinct physical cores. On my i7 machine, a process with affinity set to 3 (cores 0&1) will run roughly as fast as the program on a single core (indicating these logical cores share the same physical core), but with affinity set to 5 (cores 0&3) it will run much faster (indicating these cores are using different physical cores). However, I haven't found a reliable way (other than trial-and-error) to determine this.
How can I (without experimentation) determine which logical cores share the same physical core?
(/proc/cpuinfo has the information I need but that is not available on Windows machines.)
The number of logical processors you will have will be 8. This value is a product of the number of physical cores (8), and the number of threads they can handle (1). But what if your CPU is capable of hyperthreading? Well then each core can handle two threads, so an 8 core CPU will have 8 * 2 = 16 logical processors.
To calculate the number of logical CPUs in vSphere Client, multiply the number of sockets by the number of cores. For example, if you need to configure a VM to use 2-processor sockets, each has 2 CPU cores, then the total number of logical CPUs is 2*2=4.
Logical cores are the number of Physical cores times the number of threads that can run on each cores. This is known as HyperThreading. If I have a computer that has a 4-core processor, runs two threads per core, then I have a 8 logical processors.
When looking at core information, you may see a core value or logical processor value. A core is the physical core on the CPU. The logical processor (logical core or CPU) is how many of those cores are divided using hyperthreading to allow multiple instructions (threads) to be processed on each core simultaneously.
Based on comments to your question (thanks to all, especially to @RLH) I made this class for you:
/// <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
}
Usage example:
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);
Example outputs for 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With