Is there a way via .NET/C# to find out the number of CPU cores?
PS This is a straight code question, not a \"Should I use multi-threading?\" question! :-)
Is there a way via .NET/C# to find out the number of CPU cores?
PS This is a straight code question, not a \"Should I use multi-threading?\" question! :-)
There are several different pieces of information relating to processors that you could get:
These can all be different; in the case of a machine with 2 dual-core hyper-threading-enabled processors, there are 2 physical processors, 4 cores, and 8 logical processors.
The number of logical processors is available through the Environment class, but the other information is only available through WMI (and you may have to install some hotfixes or service packs to get it on some systems):
Make sure to add a reference in your project to System.Management.dll
Physical Processors:
foreach (var item in new System.Management.ManagementObjectSearcher(\"Select * from Win32_ComputerSystem\").Get())
{
Console.WriteLine(\"Number Of Physical Processors: {0} \", item[\"NumberOfProcessors\"]);
}
Cores:
int coreCount = 0;
foreach (var item in new System.Management.ManagementObjectSearcher(\"Select * from Win32_Processor\").Get())
{
coreCount += int.Parse(item[\"NumberOfCores\"].ToString());
}
Console.WriteLine(\"Number Of Cores: {0}\", coreCount);
Logical Processors:
Console.WriteLine(\"Number Of Logical Processors: {0}\", Environment.ProcessorCount);
OR
foreach (var item in new System.Management.ManagementObjectSearcher(\"Select * from Win32_ComputerSystem\").Get())
{
Console.WriteLine(\"Number Of Logical Processors: {0}\", item[\"NumberOfLogicalProcessors\"]);
}
Processors excluded from Windows:
You can also use Windows API calls in setupapi.dll to discover processors that have been excluded from Windows (e.g. through boot settings) and aren\'t detectable using the above means. The code below gives the total number of logical processors (I haven\'t been able to figure out how to differentiate physical from logical processors) that exist, including those that have been excluded from Windows:
static void Main(string[] args)
{
int deviceCount = 0;
IntPtr deviceList = IntPtr.Zero;
// GUID for processor classid
Guid processorGuid = new Guid(\"{50127dc3-0f36-415e-a6cc-4cb3be910b65}\");
try
{
// get a list of all processor devices
deviceList = SetupDiGetClassDevs(ref processorGuid, \"ACPI\", IntPtr.Zero, (int)DIGCF.PRESENT);
// attempt to process each item in the list
for (int deviceNumber = 0; ; deviceNumber++)
{
SP_DEVINFO_DATA deviceInfo = new SP_DEVINFO_DATA();
deviceInfo.cbSize = Marshal.SizeOf(deviceInfo);
// attempt to read the device info from the list, if this fails, we\'re at the end of the list
if (!SetupDiEnumDeviceInfo(deviceList, deviceNumber, ref deviceInfo))
{
deviceCount = deviceNumber - 1;
break;
}
}
}
finally
{
if (deviceList != IntPtr.Zero) { SetupDiDestroyDeviceInfoList(deviceList); }
}
Console.WriteLine(\"Number of cores: {0}\", deviceCount);
}
[DllImport(\"setupapi.dll\", SetLastError = true)]
private static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid,
[MarshalAs(UnmanagedType.LPStr)]String enumerator,
IntPtr hwndParent,
Int32 Flags);
[DllImport(\"setupapi.dll\", SetLastError = true)]
private static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
[DllImport(\"setupapi.dll\", SetLastError = true)]
private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet,
Int32 MemberIndex,
ref SP_DEVINFO_DATA DeviceInterfaceData);
[StructLayout(LayoutKind.Sequential)]
private struct SP_DEVINFO_DATA
{
public int cbSize;
public Guid ClassGuid;
public uint DevInst;
public IntPtr Reserved;
}
private enum DIGCF
{
DEFAULT = 0x1,
PRESENT = 0x2,
ALLCLASSES = 0x4,
PROFILE = 0x8,
DEVICEINTERFACE = 0x10,
}
Environment.ProcessorCount
[Documentation]
WMI queries are slow, so try to Select only the desired members instead of using Select *.
The following query takes 3.4s:
foreach (var item in new System.Management.ManagementObjectSearcher(\"Select * from Win32_Processor\").Get())
While this one takes 0.122s:
foreach (var item in new System.Management.ManagementObjectSearcher(\"Select NumberOfCores from Win32_Processor\").Get())
Environment.ProcessorCount should give you the number of cores on the local machine.
It\'s rather interesting to see how .NET get this internally to say the least... It\'s as \"simple\" as below:
namespace System.Threading
{
using System;
using System.Runtime.CompilerServices;
internal static class PlatformHelper
{
private const int PROCESSOR_COUNT_REFRESH_INTERVAL_MS = 0x7530;
private static volatile int s_lastProcessorCountRefreshTicks;
private static volatile int s_processorCount;
internal static bool IsSingleProcessor
{
get
{
return (ProcessorCount == 1);
}
}
internal static int ProcessorCount
{
get
{
int tickCount = Environment.TickCount;
int num2 = s_processorCount;
if ((num2 == 0) || ((tickCount - s_lastProcessorCountRefreshTicks) >= 0x7530))
{
s_processorCount = num2 = Environment.ProcessorCount;
s_lastProcessorCountRefreshTicks = tickCount;
}
return num2;
}
}
}
}
You can also get it with PInvoke on Kernel32.dll
The following code is coming more or less from SystemInfo.cs
from System.Web source located here:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct SYSTEM_INFO
{
public ushort wProcessorArchitecture;
public ushort wReserved;
public uint dwPageSize;
public IntPtr lpMinimumApplicationAddress;
public IntPtr lpMaximumApplicationAddress;
public IntPtr dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public ushort wProcessorLevel;
public ushort wProcessorRevision;
}
internal static class SystemInfo
{
internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
[DllImport(\"kernel32.dll\", CharSet = CharSet.Unicode)]
internal static extern void GetSystemInfo(out SYSTEM_INFO si);
[DllImport(\"kernel32.dll\")]
internal static extern int GetProcessAffinityMask(IntPtr handle, out IntPtr processAffinityMask, out IntPtr systemAffinityMask);
internal static int GetNumProcessCPUs()
{
if (SystemInfo._trueNumberOfProcessors == 0)
{
SYSTEM_INFO si;
GetSystemInfo(out si);
if ((int) si.dwNumberOfProcessors == 1)
{
SystemInfo._trueNumberOfProcessors = 1;
}
else
{
IntPtr processAffinityMask;
IntPtr systemAffinityMask;
if (GetProcessAffinityMask(INVALID_HANDLE_VALUE, out processAffinityMask, out systemAffinityMask) == 0)
{
SystemInfo._trueNumberOfProcessors = 1;
}
else
{
int num1 = 0;
if (IntPtr.Size == 4)
{
uint num2 = (uint) (int) processAffinityMask;
while ((int) num2 != 0)
{
if (((int) num2 & 1) == 1)
++num1;
num2 >>= 1;
}
}
else
{
ulong num2 = (ulong) (long) processAffinityMask;
while ((long) num2 != 0L)
{
if (((long) num2 & 1L) == 1L)
++num1;
num2 >>= 1;
}
}
SystemInfo._trueNumberOfProcessors = num1;
}
}
}
return SystemInfo._trueNumberOfProcessors;
}
}
The the easyest way = Environment.ProcessorCount
Exemple from Environment.ProcessorCount Property
using System;
class Sample
{
public static void Main()
{
Console.WriteLine(\"The number of processors \" +
\"on this computer is {0}.\",
Environment.ProcessorCount);
}
}
One option would be to read the data from the registry. MSDN Article On The Topic: http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.localmachine(v=vs.71).aspx)
The processors, I believe can be located here, HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor
private void determineNumberOfProcessCores()
{
RegistryKey rk = Registry.LocalMachine;
String[] subKeys = rk.OpenSubKey(\"HARDWARE\").OpenSubKey(\"DESCRIPTION\").OpenSubKey(\"System\").OpenSubKey(\"CentralProcessor\").GetSubKeyNames();
textBox1.Text = \"Total number of cores:\" + subKeys.Length.ToString();
}
I am reasonably sure the registry entry will be there on most systems.
Though I would throw my $0.02 in.
The following program prints the logical and physical cores of a windows machine.
#define STRICT
#include \"stdafx.h\"
#include <windows.h>
#include <stdio.h>
#include <omp.h>
template<typename T>
T *AdvanceBytes(T *p, SIZE_T cb)
{
return reinterpret_cast<T*>(reinterpret_cast<BYTE *>(p) + cb);
}
class EnumLogicalProcessorInformation
{
public:
EnumLogicalProcessorInformation(LOGICAL_PROCESSOR_RELATIONSHIP Relationship)
: m_pinfoBase(nullptr), m_pinfoCurrent(nullptr), m_cbRemaining(0)
{
DWORD cb = 0;
if (GetLogicalProcessorInformationEx(Relationship,
nullptr, &cb)) return;
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return;
m_pinfoBase =
reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *>
(LocalAlloc(LMEM_FIXED, cb));
if (!m_pinfoBase) return;
if (!GetLogicalProcessorInformationEx(Relationship,
m_pinfoBase, &cb)) return;
m_pinfoCurrent = m_pinfoBase;
m_cbRemaining = cb;
}
~EnumLogicalProcessorInformation() { LocalFree(m_pinfoBase); }
void MoveNext()
{
if (m_pinfoCurrent) {
m_cbRemaining -= m_pinfoCurrent->Size;
if (m_cbRemaining) {
m_pinfoCurrent = AdvanceBytes(m_pinfoCurrent,
m_pinfoCurrent->Size);
} else {
m_pinfoCurrent = nullptr;
}
}
}
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Current()
{ return m_pinfoCurrent; }
private:
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *m_pinfoBase;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *m_pinfoCurrent;
DWORD m_cbRemaining;
};
int __cdecl main(int argc, char **argv)
{
int numLogicalCore = 0;
int numPhysicalCore = 0;
for (EnumLogicalProcessorInformation enumInfo(RelationProcessorCore);
auto pinfo = enumInfo.Current(); enumInfo.MoveNext())
{
int numThreadPerCore = (pinfo->Processor.Flags == LTP_PC_SMT) ? 2 : 1;
// std::cout << \"thread per core: \"<< numThreadPerCore << std::endl;
numLogicalCore += numThreadPerCore;
numPhysicalCore += 1;
}
printf (\"Number of physical core = %d , Number of Logical core = %d \\n\", numPhysicalCore, numLogicalCore );
char c = getchar(); /* just to wait on to see the results in the command prompt */
return 0;
}
/*
I tested with Intel Xeon four cores with hyper threading and here is the result
Number of physical core = 4 , Number of Logical core = 8
*/
I was looking for the same thing but I don\'t want to install any nuget or servicepack, so I found this solution, it is pretty simple and straight forward, using this discussion, I thought it would be so easy to run that WMIC command and get that value, here is the C# code. You only need to use System.Management namespace (and couple more standard namespaces for process and so on).
string fileName = Path.Combine(Environment.SystemDirectory, \"wbem\", \"wmic.exe\");
string arguments = @\"cpu get NumberOfCores\";
Process process = new Process
{
StartInfo =
{
FileName = fileName,
Arguments = arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
}
};
process.Start();
StreamReader output = process.StandardOutput;
Console.WriteLine(output.ReadToEnd());
process.WaitForExit();
int exitCode = process.ExitCode;
process.Close();