1

I'm writting cpuid program. I need help with getting number of each type of cache. not its size, but the number. for example i need get info such as below:

L1 data cache = 2 x 64KB.

CPUID will give me the size of each sort of cache, but not its number. On MSDN i've found that GetLogicalProcessorsInformationEx proc might be helpful to get that number. but i'm not sure do i understood it right. I guess, that member of CACHE_RELATIONSHIP structure, the GROUP_AFFINITY will be related with quantity. Could some give me some hints how to get that number or tell me were else find such infos.

Dex
  • 11
  • 1
  • 2
    Try looking at this topic [CPUID implementations in C++](http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c). The top answer has some code you may be able to utilize to solve your problem. – Doug Aug 20 '13 at 19:19
  • 1
    I have checked CPUID information here, and you can DEFINITELY get that information from there - that's how the BIOS and OS finds that information for presenting in GetLogicalProcessorInformationEx and /proc/cpuinfo etc. See section 3, particularly table 3-22 and text relating to it. http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html – Mats Petersson Aug 20 '13 at 19:32
  • No need to duplicate what the BIOS does, every major OS does it and likely does it better then we could. This type of task is why we have libraries and abstraction layers. – Sqeaky Aug 21 '13 at 02:24

1 Answers1

2

I have done a simpler version of this before. I have not worked with Cache Affinity or counts, but I have queried cache size and cache line size. I suspect that the information can be gotten by swapping out a few argument in what I have done.

Here is what I did to get the size of the largest CPU cache on common PC platforms. I have run this on windows(msvc, mingw), Linux(gcc, clang) and Mac OS X (gcc) where it compiles and runs without warning, except some seemingly spurious warnings from msvc. This code comes from https://github.com/BlackToppStudios/DAGFrameScheduler/blob/master/src/systemcalls.cpp , but feel free to use this function for your own purposes (I am author/owner and I can relicense it out of GPL).

It checks if an L4 cache exists, if so it returns it. Then it checks if an L3 cache exists, if so it returns it and then L2 and L1 likewise.

This code expects _MEZZ_THREAD_WIN32_ to be defined only on windows, _MEZZ_THREAD_APPLE_ only on Mac OS X, and presumes Linux/BSD otherwise. MinGW has issues doing this as of 6 weeks before this writing, it might be possible to use msvc/windows sdk headers and c library, but I have not attempted that, it seemed to messy.

#ifdef _MEZZ_THREAD_WIN32_
    #include <windows.h>
#else
    #ifdef _MEZZ_THREAD_APPLE_
        #include <sys/sysctl.h>
    #endif
    #include <sys/time.h>
    #include <unistd.h>
#endif

typedef unsigned int Whole

Whole GetCacheSize()
{
    #ifdef _MEZZ_THREAD_WIN32_
        #ifdef _MSC_VER
            size_t Size = 0;
            DWORD buffer_size = 0;
            DWORD i = 0;
            SYSTEM_LOGICAL_PROCESSOR_INFORMATION * buffer = 0;

            GetLogicalProcessorInformation(0, &buffer_size);
            buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)malloc(buffer_size);
            GetLogicalProcessorInformation(&buffer[0], &buffer_size);

            for (i = 0; i != buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) {
                if (buffer[i].Relationship == RelationCache && buffer[i].Cache.Level == 1) {
                    Size = buffer[i].Cache.Size;
                    break;
                }
            }

            free(buffer);
            return Size;
        #else
            //mingw can't do this, see bug http://sourceforge.net/p/mingw/bugs/1626/
            // assume 32k
            return 32768;
        #endif
    #else
        #ifdef _MEZZ_THREAD_APPLE_
            Whole CacheSize;
            Whole CSSize = sizeof(CacheSize);
            if(0==sysctlbyname("hw.l4icachesize", &CacheSize, &CSSize, NULL, 0))
            {
                return CacheSize;
            }else{
                if(0==sysctlbyname("hw.l3icachesize", &CacheSize, &CSSize, NULL, 0))
                {
                    return CacheSize;
                }else{
                    if(0==sysctlbyname("hw.l2icachesize", &CacheSize, &CSSize, NULL, 0))
                    {
                        return CacheSize;
                    }else{
                        if(0==sysctlbyname("hw.l1icachesize", &CacheSize, &CSSize, NULL, 0))
                        {
                            return CacheSize;
                        }else{
                            return 0;
                        }
                    }
                }
            }
        #else
            Whole CSSize = sysconf(_SC_LEVEL4_CACHE_SIZE);
            if(!CSSize)
            {
                CSSize = sysconf(_SC_LEVEL3_CACHE_SIZE);
                if(!CSSize)
                {
                    CSSize = sysconf(_SC_LEVEL2_CACHE_SIZE);
                    if(!CSSize)
                        { CSSize = sysconf(_SC_LEVEL1_DCACHE_SIZE); }
                }
            }
            return CSSize;
       #endif
    #endif
}
Sqeaky
  • 1,876
  • 3
  • 21
  • 40
  • Regarding OS X, the proper names for the L2 and L3 cache sizes seem to be `hw.l2cachesize` and `hw.l3cachesize` without the `i`. At least I've found more online references for these. – sjakobi Mar 03 '18 at 19:41