2014-10-15 19 views
19

Sto lavorando a uno strumento per consentire agli studenti di autovalutare le prestazioni del loro incarico di programmazione. In particolare, il programma che stanno scrivendo è multi-thread e non ho modo diretto di influenzare il numero di thread creati. Vorrei confrontare le prestazioni dei loro programmi con un numero diverso di core (e idealmente i loro programmi dovrebbero accelerare in modo approssimativo rispetto al numero di core che è consentito utilizzare).Come determinare quali core logici condividono lo stesso core fisico?

Possiamo passare una maschera di bit a Process.SetAffinity per controllare quali core il programma utilizza.

Ciò è problematico sulle macchine i5 e i7 che utilizzano hyper-threading e suddividono ciascun core fisico in due logici. Voglio che il programma funzioni su due/quattro core fisici distinti. Sulla mia macchina i7, un processo con affinità impostata su 3 (core 0 & 1) funzionerà grosso modo quanto il programma su un singolo core (indicando che questi core logici condividono lo stesso core fisico), ma con affinità impostata su 5 (core 0 & 3) funzionerà molto più velocemente (indicando che questi core utilizzano core fisici diversi). Tuttavia, non ho trovato un modo affidabile (diverso da trial-and-error) per determinare questo.

Come è possibile (senza sperimentazione) determinare quali core logici condividono lo stesso nucleo fisico?

(/ proc/cpuinfo ha le informazioni che ho bisogno, ma che non è disponibile su macchine Windows.)

+1

Le informazioni probabilmente disponibili tramite [WMI (Strumentazione gestione Windows)] (http://en.wikipedia.org/wiki/Windows_Management_Instrumentation) - o almeno il conteggio di core fisici/virtuali, che * potrebbe * essere valido per estrapolare in una maschera di bit interleaved. – user2864740

+1

Sembra che abbia dimenticato di menzionare che sto cercando specificamente una soluzione C#. Ho aggiunto il tag C# ma non l'ho menzionato da nessuna parte. Ho aggiunto C# nel titolo, il che dovrebbe rendere un po 'più chiaro quello che sto cercando. –

+0

@TomvanderZanden Non si deve aggiungere 'C#' al titolo. Tag dovrebbe essere sufficiente. Se non lo è, chiariscilo nella tua domanda. – MarcinJuraszek

risposta

4

Sulla base di commenti alla tua domanda (grazie a tutti, specialmente a @RLH) Ho fatto questa classe per voi :

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

esempio di utilizzo:

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

uscite esempio per 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