简体   繁体   中英

how to determine CPU cache size in .NET?

I would like to know if there is a way to determine CPU cache size in managed code?

I am writing a Strassen's algorithm for matrix multiplication in C# and would like to know how many elements of the matrices I could fit into cache to improve computational speed.

You can use WMI to retrieve cache information.

You will first need to add a reference to System.Management.dll to your project, then you can use the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;

namespace Scratch
{
    public enum CacheLevel : ushort 
    {
        Level1 = 3,
        Level2 = 4,
        Level3 = 5,
    }

    public static class CPUInfo
    {
        public static List<uint> GetCacheSizes(CacheLevel level)
        {
            ManagementClass mc = new ManagementClass("Win32_CacheMemory");
            ManagementObjectCollection moc = mc.GetInstances();
            List<uint> cacheSizes = new List<uint>(moc.Count);

            cacheSizes.AddRange(moc
              .Cast<ManagementObject>()
              .Where(p => (ushort)(p.Properties["Level"].Value) == (ushort)level)
              .Select(p => (uint)(p.Properties["MaxCacheSize"].Value)));

            return cacheSizes;
        }
    }
}

Full details of the Win32_CacheMemory WMI class is available at:

http://msdn.microsoft.com/en-us/library/aa394080(v=vs.85).aspx

    using System;
    using System.Runtime.InteropServices;

    class Processor
    {
        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();

        //[DllImport("kernel32.dll")]
        //public static extern int GetCurrentProcessorNumber();

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        private struct GROUP_AFFINITY
        {
            public UIntPtr Mask;

            [MarshalAs(UnmanagedType.U2)]
            public ushort Group;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)]
            public ushort[] Reserved;
        }

        [DllImport("kernel32", SetLastError = true)]
        private static extern Boolean SetThreadGroupAffinity(IntPtr hThread, ref GROUP_AFFINITY GroupAffinity, ref GROUP_AFFINITY PreviousGroupAffinity);

        [StructLayout(LayoutKind.Sequential)]
        public struct PROCESSORCORE
        {
            public byte Flags;
        };

        [StructLayout(LayoutKind.Sequential)]
        public struct NUMANODE
        {
            public uint NodeNumber;
        }

        public enum PROCESSOR_CACHE_TYPE
        {
            CacheUnified,
            CacheInstruction,
            CacheData,
            CacheTrace
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CACHE_DESCRIPTOR
        {
            public byte Level;
            public byte Associativity;
            public ushort LineSize;
            public uint Size;
            public PROCESSOR_CACHE_TYPE Type;
        }

        [StructLayout(LayoutKind.Explicit)]
        public 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;
        }

        public enum LOGICAL_PROCESSOR_RELATIONSHIP
        {
            RelationProcessorCore,
            RelationNumaNode,
            RelationCache,
            RelationProcessorPackage,
            RelationGroup,
            RelationAll = 0xffff
        }

        public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
        {
#pragma warning disable 0649
            public UIntPtr ProcessorMask;
            public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
            public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
#pragma warning restore 0649
        }

        [DllImport(@"kernel32.dll", SetLastError = true)]
        public static extern bool GetLogicalProcessorInformation(IntPtr Buffer, ref uint ReturnLength);

        private const int ERROR_INSUFFICIENT_BUFFER = 122;

        private static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] _logicalProcessorInformation = null;

        public static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] LogicalProcessorInformation
        {
            get
            {
                if (_logicalProcessorInformation != null)
                    return _logicalProcessorInformation;

                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;
                            _logicalProcessorInformation = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[len];
                            IntPtr Item = Ptr;

                            for (int i = 0; i < len; i++)
                            {
                                _logicalProcessorInformation[i] = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)Marshal.PtrToStructure(Item, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
                                Item += size;
                            }

                            return _logicalProcessorInformation;
                        }
                    }
                    finally
                    {
                        Marshal.FreeHGlobal(Ptr);
                    }
                }
                return null;
            }
        }
    }

Handy helper function:

public static void GetPerCoreCacheSizes(out Int64  L1, out Int64 L2, out Int64 L3)
{
    L1 = 0;
    L2 = 0;
    L3 = 0;

    var info = Processor.LogicalProcessorInformation;
    foreach (var entry in info)
    {
        if (entry.Relationship != Processor.LOGICAL_PROCESSOR_RELATIONSHIP.RelationCache)
            continue;
        Int64 mask = (Int64)entry.ProcessorMask;
        if ((mask & (Int64)1) == 0)
            continue;
        var cache = entry.ProcessorInformation.Cache;
        switch (cache.Level)
        {
            case 1: L1 = L1 + cache.Size; break;
            case 2: L2 = L2 + cache.Size; break;
            case 3: L3 = L3 + cache.Size; break;
            default:
                break;
        }
    }

And call it:

static void Main(string[] args)
{
    long l1, l2, l3;

    GetPerCoreCacheSizes(out l1, out l2, out l3);

    String s = String.Format("Single-core memory cache: L1={0} KB, L2={1} KB, L3={2} KB", l1 / 1024, l2 / 1024, l3 / 1024);
    Console.WriteLine(s);
    Console.ReadLine();
}

Output :

Single-core memory cache: L1=64 KB, L2=256 KB, L3=6144 KB

is this what you are looking for? The Win32_Processor class features L2CacheSize and L3CacheSize members.

Try this code

using System.Management;

uint32 cachsize;
public void CPUSpeed()
{
  using(ManagementObject Mo = new ManagementObject("Win32_Processor.DeviceID='CPU0'"))
  {
    cachsize = (uint)(Mo["L2CacheSize"]);
  }
}

I get it from Here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM