2014-10-15 4 views
19

Я работаю над инструментом, позволяющим студентам самостоятельно оценивать производительность их программирования. В частности, программа, которую они пишут, имеет многопоточность, и у меня нет прямого способа повлиять на количество созданных потоков. Я бы хотел сравнить производительность своих программ с различным количеством ядер (и в идеале их программы должны ускоряться примерно пропорционально количеству ядер, которые разрешено использовать).Как определить, какие логические ядра имеют одно и то же физическое ядро?

Мы можем передать битмаску Process.SetAffinity, чтобы контролировать, какие ядра использует программа.

Это проблема на машинах i5 и i7, которые используют гиперпоточность и разделяют каждое физическое ядро ​​на два логических. Я хочу, чтобы программа работала на двух/четырех различных физических ядрах. На моей машине i7 процесс с аффинностью, установленный в 3 (ядра 0 & 1), будет работать примерно так же быстро, как программа на одном ядре (указав, что эти логические ядра имеют одно и то же физическое ядро), но с аффинностью, установленной на 5 (ядра 0 & 3) он будет работать намного быстрее (указав, что эти ядра используют разные физические ядра). Тем не менее, я не нашел надежного способа (кроме проб и ошибок), чтобы определить это.

Как я могу (без экспериментов) определить, какие логические ядра имеют одно и то же физическое ядро?

(/ Proc/CPUInfo имеет информацию, мне нужно, но это не доступно на компьютерах Windows.)

+1

Информация, доступная через [WMI (Windows Management Instrumentation)] (http://en.wikipedia.org/wiki/Windows_Management_Instrumentation) - или, по крайней мере, счет физических/виртуальных ядер, которые он * может * действительны для экстраполяции в перемешанную битовую маску. – user2864740

+1

Похоже, я забыл упомянуть, что я специально ищу решение для C#. Я добавил тег C#, но я нигде не упоминал об этом. Я добавил C# в заголовок, который должен сделать его немного яснее, что я ищу. –

+0

@TomvanderZanden Вы не должны добавлять 'C#' в заголовок. Тег должен быть достаточно. Если это не так, сделайте это ясно в своем вопросе. – MarcinJuraszek

ответ

4

Основываясь на комментариях к вашему вопросу (спасибо всем, особенно @RLH) Я сделал этот класс для вас :

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

пример использования:

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

пример выходы для 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 

 Смежные вопросы

  • Нет связанных вопросов^_^