2014-10-15 4 views
19

Ich arbeite an einem Tool, mit dem Schüler die Leistung ihrer Programmieraufgabe selbst bewerten können. Insbesondere ist das Programm, das sie schreiben, Multi-Threading und ich habe keine direkte Möglichkeit, die Anzahl der erstellten Threads zu beeinflussen. Ich würde gerne die Leistung ihrer Programme bei einer anderen Anzahl von Kernen vergleichen (und idealerweise sollten ihre Programme ungefähr proportional dazu ansteigen, wie viele Kerne es benutzen darf).Wie ermittelt man, welche logischen Kerne den gleichen physischen Kern teilen?

Wir können eine Bitmaske an Process.SetAffinity übergeben, um zu steuern, welche Cores das Programm verwendet.

Dies ist problematisch auf i5 und i7-Maschinen, die Hyper-Threading verwenden und jeden physischen Kern in zwei logische aufteilen. Ich möchte, dass das Programm auf zwei oder vier verschiedenen physikalischen Kernen läuft. Auf meiner i7-Maschine läuft ein Prozess mit einer Affinität von 3 (Kerne 0 & 1) ungefähr so ​​schnell wie das Programm auf einem einzelnen Kern (zeigt an, dass diese logischen Kerne den gleichen physischen Kern haben), aber mit einer Affinität von 5 (Kernen) 0 & 3) es wird viel schneller laufen (zeigt an, dass diese Kerne verschiedene physische Kerne verwenden). Ich habe jedoch keinen zuverlässigen Weg gefunden (außer Versuch und Irrtum), um dies zu bestimmen.

Wie kann ich (ohne Experimente) feststellen, welche logischen Kerne den gleichen physischen Kern haben?

(/ proc/cpuinfo hat die Informationen, die ich brauche, aber das ist auf Windows-Rechnern nicht verfügbar.)

+1

Die Informationen sind wahrscheinlich verfügbar über [WMI (Windows Management Instrumentation)] (http://en.wikipedia.org/wiki/Windows_Management_Instrumentation) - oder zumindest die Anzahl der physischen/virtuellen Kerne, die es * könnte * gültig sein, um in eine verschachtelte Bitmaske zu extrapolieren. – user2864740

+1

Es sieht so aus, als hätte ich vergessen zu erwähnen, dass ich speziell nach einer C# Lösung suche. Ich habe das C# -Tag hinzugefügt, aber ich habe es nirgends erwähnt. Ich habe jetzt C# im Titel hinzugefügt, was es ein bisschen klarer machen sollte, wonach ich suche. –

+0

@TomvanderZanden Sie sollten 'C#' nicht zum Titel hinzufügen. Tag sollte genug sein. Wenn es nicht ist, machen Sie es in Ihrer Frage deutlich. – MarcinJuraszek

Antwort

4

Basierend auf Kommentare auf Ihre Frage (Dank an alle, vor allem zu @RLH) habe ich diese Klasse für Sie :

/// <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 
} 

Anwendungsbeispiel:

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); 

Beispiel Ausgänge für Intel Core i5:

Verwandte Themen