In the realm of C# programming, understanding the underlying hardware can be crucial for optimizing performance. One fundamental aspect is knowing the number of CPU cores available. In this article, we will explore methods to retrieve the number of CPU cores in C#, delving into the System.Environment class and Windows WMI.
Let’s start.
Retrieve CPU Core Information
First of all, there are three different terms, when it comes to CPU core count. There are physical processors, CPU cores, and logical processors. They differ in the amount and therefore have different meanings.
Physical processors represent the tangible chips installed on the motherboard, each containing multiple CPU cores capable of executing instructions independently. Logical processors, on the other hand, are virtual entities generated by technologies like hyper-threading. Each core is capable of handling multiple threads concurrently. Often the amount of logical processors is double of its physical processors.
We begin with the simplest way, to retrieve the amount of logical processors:
var cpuCount = Environment.ProcessorCount;
This succinct method provides a rapid means to retrieve the count of logical processors. Notably, this method stands as the singular approach applicable across all platforms for retrieving CPU core information, ensuring uniformity and ease of access.
Retrieve WMI Cores Information
WMI (Windows Management Instrumentation) Core Information is another method we can use to retrieve the number of CPU cores in C#, but it operates exclusively on Windows machines. This limitation poses risks, especially considering many servers run on Linux. When developing open-source code or libraries, independence is crucial. Ensuring accessibility across different operating systems allows anyone to utilize and test the application. However, in specific scenarios, leveraging WMI may prove beneficial.
WMI Core information typically originates from the operating system’s management infrastructure, providing a standardized interface for retrieving data about hardware, software, and system configuration within Windows environments. With this interface, we can get advanced CPU information. If we want to retrieve the number of physical processors or the number of cores on a Windows system, we use the WMI interface.
First of all, we add the NuGet package System.Management.dll
to our project references:
Install-Package System.Management
With that, let’s look at how we retrieve the number of cores.
Retrieve the Number of Cores
Now we can retrieve the number of cores:
public int GetNumberOfCores() { if (!OperatingSystem.IsWindows()) { throw new PlatformNotSupportedException(); } var coreCount = 0; const string wmiQuery = "Select * from Win32_Processor"; foreach (var item in new System.Management.ManagementObjectSearcher(wmiQuery).Get()) { coreCount += int.Parse(item["NumberOfCores"].ToString()); } return coreCount; }
Here, we define the GetNumberOfCores()
method. If the platform is not Windows, we throw a PlatformNotSupportedException
. Otherwise, we continue to count the total number of cores.
The System.Management.ManagementObjectSearcher
class is the WMI API that we use to query for the Windows system information. We loop over the query result and retrieve the NumberOfCores
property from WMI instance.
Physical Processors
We can also get the number of physical processors:
const string wmiQuery = "Select * from Win32_ComputerSystem"; public int GetPhysicalProcessors() { if (!OperatingSystem.IsWindows()) { throw new PlatformNotSupportedException(); } foreach (var item in new System.Management.ManagementObjectSearcher(wmiQuery).Get()) { return int.Parse(item["NumberOfProcessors"].ToString()); } return 0; }
Here, we use a for loop to get all the results of executing the query Select * from Win32_ComputerSystem
in System.Management.ManagementObjectSearcher
. Then, we retrieve the NumberOfProcessors
attribute for each result, which represents the count of physical processors present in the system.
Logical Processors
Instead of using the Environment.ProcessorCount
we can also use this API to get the number of logical processors:
const string wmiQuery = "Select * from Win32_ComputerSystem"; public int GetLogicalProcessors() { if (!OperatingSystem.IsWindows()) { throw new PlatformNotSupportedException(); } foreach (var item in new System.Management.ManagementObjectSearcher(wmiQuery).Get()) { return int.Parse(item["NumberOfLogicalProcessors"].ToString()); } return 0; }
Similar to our previous method, we use a loop to get the results from the ManagementObjectSearcher()
method. This time, we retrieve the NumberOfLogicalProcessors
attribute, representing the count of logical processors in the system.
Utilizing WMI for CPU core information retrieval provides advanced insights into system hardware but is limited to Windows environments, posing challenges for cross-platform compatibility. While WMI offers a standardized interface for accessing CPU details like physical processors and cores, its reliance on Windows-specific APIs requires careful consideration in open-source projects aiming for broader platform support.
Processors Excluded from Windows
Now, we identify the excluded processors:
public int GetExcludedProcessors() { if (!OperatingSystem.IsWindows()) { throw new PlatformNotSupportedException(); } var deviceCount = 0; var deviceList = IntPtr.Zero; var processorGuid = new Guid("{50127dc3-0f36-415e-a6cc-4cb3be910b65}"); try { deviceList = SetupDiGetClassDevs(ref processorGuid, "ACPI", IntPtr.Zero, (int)DIGCF.PRESENT); for (var deviceNumber = 0; ; deviceNumber++) { var deviceInfo = new SP_DEVINFO_DATA(); deviceInfo.cbSize = Marshal.SizeOf(deviceInfo); if (!SetupDiEnumDeviceInfo(deviceList, deviceNumber, ref deviceInfo)) { deviceCount = deviceNumber; break; } } } finally { if (deviceList != IntPtr.Zero) { SetupDiDestroyDeviceInfoList(deviceList); } } return deviceCount; }
Here, we define the GetExcludedProcessors()
method, which we use to retrieve the count of excluded processors on a Windows system using SetupApi calls on Windows.
We start by initializing variables and fetching device information using the SetupDiGetClassDevs()
method. Then we enumerate through the devices and update the count. Finally, we clean up resources and return the count of processors. Note that our method provides the total number of logical processors, including those excluded from Windows.
Application and Optimization
When working with CPU information in C#, understanding how to optimize performance is crucial. Multithreading is one way to optimize the performance of a program. But to optimize a multithreaded code, we want to have at least as many threads as the number of logical processors.
By utilizing this approach, we can maximize CPU usage because every processor has assigned tasks, and we distribute the workload across CPU cores for faster execution. Remember that CPU optimization is a balance between performance and power efficiency. By leveraging core information effectively, we create more efficient applications that optimally use available resources.