/// <summary> /// Gets the number of logical cores. We use this rather than Environment.ProcessorCount when possible to handle machines with > 64 cores (the single group limit available to the .NET framework). /// </summary> /// <returns>The number of logical cores.</returns> public static int GetLogicalProcessorCount() { // This function uses Windows P/Invoke calls; if we're on Mono, just return the default. if (!Utils.IsRunningOnMono) { const int ERROR_INSUFFICIENT_BUFFER = 122; // Determine the required buffer size to store the processor information uint ReturnLength = 0; if (!GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup, IntPtr.Zero, ref ReturnLength) && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { // Allocate a buffer for it IntPtr Ptr = Marshal.AllocHGlobal((int)ReturnLength); try { if (GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup, Ptr, ref ReturnLength)) { int Count = 0; for (int Pos = 0; Pos < ReturnLength;) { LOGICAL_PROCESSOR_RELATIONSHIP Type = (LOGICAL_PROCESSOR_RELATIONSHIP)Marshal.ReadInt16(Ptr, Pos); if (Type == LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup) { // Read the values from the embedded GROUP_RELATIONSHIP structure int GroupRelationshipPos = Pos + 8; int ActiveGroupCount = Marshal.ReadInt16(Ptr, GroupRelationshipPos + 2); // Read the processor counts from the embedded PROCESSOR_GROUP_INFO structures int GroupInfoPos = GroupRelationshipPos + 24; for (int GroupIdx = 0; GroupIdx < ActiveGroupCount; GroupIdx++) { Count += Marshal.ReadByte(Ptr, GroupInfoPos + 1); GroupInfoPos += 40 + IntPtr.Size; } } Pos += Marshal.ReadInt32(Ptr, Pos + 4); } return(Count); } } finally { Marshal.FreeHGlobal(Ptr); } } } return(Environment.ProcessorCount); }
/// <summary> /// Gets the number of physical cores, excluding hyper threading. /// </summary> /// <returns>The number of physical cores, or -1 if it could not be obtained</returns> public static int GetPhysicalProcessorCount() { // This function uses Windows P/Invoke calls; if we're on Mono, just fail. if (Utils.IsRunningOnMono) { return(-1); } const int ERROR_INSUFFICIENT_BUFFER = 122; // Determine the required buffer size to store the processor information uint ReturnLength = 0; if (!GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, IntPtr.Zero, ref ReturnLength) && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { // Allocate a buffer for it IntPtr Ptr = Marshal.AllocHGlobal((int)ReturnLength); try { if (GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, Ptr, ref ReturnLength)) { // As per-MSDN, this will return one structure per physical processor. Each SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX structure is of a variable size, so just skip // through the list and count the number of entries. int Count = 0; for (int Pos = 0; Pos < ReturnLength;) { LOGICAL_PROCESSOR_RELATIONSHIP Type = (LOGICAL_PROCESSOR_RELATIONSHIP)Marshal.ReadInt16(Ptr, Pos); if (Type == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore) { Count++; } Pos += Marshal.ReadInt32(Ptr, Pos + 4); } return(Count); } } finally { Marshal.FreeHGlobal(Ptr); } } return(-1); }
private static extern void GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP lpr, out IntPtr ptr, ref IntPtr ReturnLength);
extern static bool GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, IntPtr Buffer, ref uint ReturnedLength);
private static extern bool GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP relationshipType, IntPtr buffer, ref UInt32 returnedLength);
public static unsafe void Can_call_extern_function(LOGICAL_PROCESSOR_RELATIONSHIP relType) { bool successful = GetLogicalProcessorInformationEx( relType, default, out int bytesRequired);
public static extern BOOL GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, [NativeTypeName("PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX")] SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer, [NativeTypeName("PDWORD")] uint *ReturnedLength);
internal static extern bool GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, IntPtr Buffer, ref uint ReturnedLength);
private int GetProcessorInfo(LOGICAL_PROCESSOR_RELATIONSHIP coreCountType) { var buffer = new List <ISYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX>(); uint returnLength = 0; GetLogicalProcessorInformationEx(coreCountType, IntPtr.Zero, ref returnLength); if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { var ptr = Marshal.AllocHGlobal((int)returnLength); try { if (GetLogicalProcessorInformationEx(coreCountType, ptr, ref returnLength)) { var item = ptr; var readCount = 0; //int size = Marshal.SizeOf(typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX)); //int len = (int)returnLength / size; //for (int i = 0; i < len; i++) while (readCount < returnLength) { var type = (LOGICAL_PROCESSOR_RELATIONSHIP)Marshal.ReadInt32(item); var size = Marshal.ReadInt32(item, 4); var data = new byte[size]; Marshal.Copy(item, data, 0, size); switch (type) { case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorPackage: case LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore: buffer.Add((SLPI_PROCESSOR_RELATIONSHIP)Marshal.PtrToStructure(item, typeof(SLPI_PROCESSOR_RELATIONSHIP))); break; case LOGICAL_PROCESSOR_RELATIONSHIP.RelationNumaNode: buffer.Add((SLPI_NUMA_NODE_RELATIONSHIP)Marshal.PtrToStructure(item, typeof(SLPI_NUMA_NODE_RELATIONSHIP))); break; case LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache: buffer.Add((SLPI_CACHE_RELATIONSHIP)Marshal.PtrToStructure(item, typeof(SLPI_CACHE_RELATIONSHIP))); break; case LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup: buffer.Add((SLPI_GROUP_RELATIONSHIP)Marshal.PtrToStructure(item, typeof(SLPI_GROUP_RELATIONSHIP))); break; } item += size; readCount += size; } } } finally { Marshal.FreeHGlobal(ptr); } } //foreach (var proc in buffer) //{ // Console.WriteLine(proc.ProcRelationship.ToString()); //} return(buffer.Count); }
/// <summary> /// Generic method for calling GetLogicalProcessorInformationEx that returns the correct structure type. /// </summary> /// <typeparam name="T">The structure type that should be returned. Must match the relationship type.</typeparam> /// <param name="relationshipType">The relationship type to call GetLogicalProcessorInformationEx with.</param> /// <returns></returns> private static T[] GetLogicalProcessorInformationEx <T>(LOGICAL_PROCESSOR_RELATIONSHIP relationshipType) where T : struct { // validate that the lookup type and class parameter matches properly var typeClassLooukp = new Dictionary <LOGICAL_PROCESSOR_RELATIONSHIP, Type> { { LOGICAL_PROCESSOR_RELATIONSHIP.ProcessorCore, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_PROCESSOR) }, { LOGICAL_PROCESSOR_RELATIONSHIP.ProcessorPackage, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_PROCESSOR) }, { LOGICAL_PROCESSOR_RELATIONSHIP.NumaNode, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_NUMA_NODE) }, { LOGICAL_PROCESSOR_RELATIONSHIP.Cache, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_CACHE) }, { LOGICAL_PROCESSOR_RELATIONSHIP.Group, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX_GROUP) }, }; if (typeClassLooukp[relationshipType] != typeof(T)) { throw new InvalidCastException($"Generic type {typeof(T).Name} passed does not match the relationship type {relationshipType}."); } /* TODO: Rework this to fix the race condition in which the internal data changes between the first call to GetLogicalProcessorInformationEx and the second. * This is a rare or impossible case for everything but groups, which may techncially change over time. For now this code will work in 99.999999% of cases. */ // find the length required for the buffer uint requiredLength = 0; bool success = NativeMethods.GetLogicalProcessorInformationEx(relationshipType, IntPtr.Zero, ref requiredLength); if (!success && Marshal.GetLastWin32Error() != NativeMethods.ERROR_INSUFFICIENT_BUFFER) { throw new InvalidOperationException($"The call to GetLogicalProcessorInformationEx failed. Last error: {Marshal.GetLastWin32Error()}"); } // pad allocation up to the nearest 64-bit boundary requiredLength += 8 - (requiredLength % 8); if (requiredLength > int.MaxValue) { throw new InvalidOperationException($"The call to GetLogicalProcessorInformationEx returned a required data size ({requiredLength}) that exceeded the maximum signed integer value."); } IntPtr memProcInfo = Marshal.AllocHGlobal((int)requiredLength); try { uint bufferLength = requiredLength; success = NativeMethods.GetLogicalProcessorInformationEx(relationshipType, memProcInfo, ref bufferLength); if (!success) { throw new InvalidOperationException($"The call to GetLogicalProcessorInformationEx failed. Last error: {Marshal.GetLastWin32Error()}"); } #if OLD_DOT_NET_VERSION uint structLength = (uint)Marshal.SizeOf(typeof(T)); #else uint structLength = (uint)Marshal.SizeOf <T>(); #endif if (bufferLength > requiredLength || bufferLength < structLength) { throw new InvalidOperationException($"The call to GetLogicalProcessorInformationEx returned an invalid data length ({bufferLength})."); } uint arrayCount = bufferLength / structLength; var structArray = new T[arrayCount]; IntPtr pointer = memProcInfo; for (int i = 0; i < arrayCount; i++) { #if OLD_DOT_NET_VERSION structArray[i] = (T)Marshal.PtrToStructure(pointer, typeof(T)); #else structArray[i] = Marshal.PtrToStructure <T>(pointer); #endif pointer += (int)structLength; } return(structArray); } finally { Marshal.FreeHGlobal(memProcInfo); } }
public static extern unsafe bool GetLogicalProcessorInformationEx( LOGICAL_PROCESSOR_RELATIONSHIP RelationshipType, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *Buffer, ref int ReturnedLength );