2014-10-15 16 views
19

Pracuję nad narzędziem, które umożliwi uczniom samodzielną ocenę wydajności przydziału programistycznego. W szczególności program, który piszą, jest wielowątkowy i nie mam bezpośredniego sposobu wpływania na liczbę tworzonych wątków. Chciałbym porównać wydajność ich programów, biorąc pod uwagę różną liczbę rdzeni (i najlepiej, że ich programy powinny przyspieszyć w przybliżeniu proporcjonalnie do liczby rdzeni, z których może korzystać).Jak określić, które rdzenie logiczne mają ten sam rdzeń fizyczny?

Możemy przekazać maskę bitową do Process.SetAffinity, aby kontrolować, których rdzeni używa program.

Jest to problematyczne na maszynach i5 i i7, które używają hiperwątkowości i dzielą każdy rdzeń fizyczny na dwa logiczne. Chcę, aby program działał na dwóch/czterech różnych rdzeniach fizycznych. Na mojej maszynie i7 proces z powinowactwem ustawionym na 3 (rdzenie 0 & 1) będzie działał mniej więcej tak szybko, jak program na pojedynczym rdzeniu (wskazując, że te logiczne rdzenie dzielą ten sam rdzeń fizyczny), ale z powinowactwem ustawionym na 5 (rdzenie 0 & 3) będzie działać znacznie szybciej (wskazując, że te rdzenie używają różnych rdzeni fizycznych). Jednak nie znalazłem wiarygodnego sposobu (poza próbą i błędem), aby to ustalić.

Jak mogę (bez eksperymentów) określić, które rdzenie logiczne mają ten sam rdzeń fizyczny?

(/ proc/cpuinfo zawiera informacje potrzebne, ale nie jest dostępna na komputerach z systemem Windows).

+1

Informacje prawdopodobnie dostępne za pośrednictwem [WMI (Windows Management Instrumentation)] (lub co najmniej liczby rdzeni fizycznych/wirtualnych, które mogą * może *) być prawidłowe do ekstrapolacji na przeplataną maskę bitową. – user2864740

+1

Wygląda na to, że zapomniałem wspomnieć, że specjalnie szukam rozwiązania C#. Dodałem tag C#, ale nigdzie go nie wspomniałem. Dodałem teraz C# do tytułu, co powinno sprawić, że będzie jaśniej tego, czego szukam. –

+0

@TomvanderZanden Nie powinieneś dodawać "C#" do tytułu. Tag powinien wystarczyć. Jeśli tak nie jest, wyjaśnij to w swoim pytaniu. – MarcinJuraszek

Odpowiedz

4

oparciu o komentarzach do Twojego pytania (dzięki dla wszystkich, zwłaszcza do @RLH) Zrobiłem tę klasę dla Ciebie :

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

Przykład zastosowania:

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

Przykład wyjścia dla 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 
Powiązane problemy