Back to index

glibc  2.9
Classes | Defines | Functions | Variables
cacheinfo.c File Reference
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>

Go to the source code of this file.

Classes

struct  intel_02_cache_info

Defines

#define nintel_02_known   (sizeof (intel_02_known) / sizeof (intel_02_known [0]))

Functions

static int intel_02_known_compare (const void *p1, const void *p2)
static long int __attribute__ ((noinline))
long int attribute_hidden __cache_sysconf (int name)
static void __attribute__ ((constructor))

Variables

static struct intel_02_cache_info intel_02_known []
long int
__x86_64_data_cache_size_half 
attribute_hidden = 32 * 1024 / 2

Class Documentation

struct intel_02_cache_info

Definition at line 68 of file sysconf.c.

Class Members
long int assoc
unsigned int idx
long int linesize
int name
long int size

Define Documentation

#define nintel_02_known   (sizeof (intel_02_known) / sizeof (intel_02_known [0]))

Definition at line 85 of file cacheinfo.c.


Function Documentation

static long int __attribute__ ( (noinline)  ) [static]

Definition at line 104 of file cacheinfo.c.

{
  if ((value & 0x80000000) != 0)
    /* The register value is reserved.  */
    return 0;

  /* Fold the name.  The _SC_ constants are always in the order SIZE,
     ASSOC, LINESIZE.  */
  int folded_name = (_SC_LEVEL1_ICACHE_SIZE
                   + ((name - _SC_LEVEL1_ICACHE_SIZE) / 3) * 3);

  while (value != 0)
    {
      unsigned int byte = value & 0xff;

      if (byte == 0x40)
       {
         *no_level_2_or_3 = true;

         if (folded_name == _SC_LEVEL3_CACHE_SIZE)
           /* No need to look further.  */
           break;
       }
      else
       {
         if (byte == 0x49 && folded_name == _SC_LEVEL3_CACHE_SIZE)
           {
             /* Intel reused this value.  For family 15, model 6 it
               specifies the 3rd level cache.  Otherwise the 2nd
               level cache.  */
             unsigned int eax;
             unsigned int ebx;
             unsigned int ecx;
             unsigned int edx;
             asm volatile ("cpuid"
                         : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
                         : "0" (1));

             unsigned int family = ((eax >> 20) & 0xff) + ((eax >> 8) & 0xf);
             unsigned int model = ((((eax >>16) & 0xf) << 4)
                                + ((eax >> 4) & 0xf));
             if (family == 15 && model == 6)
              {
                /* The level 3 cache is encoded for this model like
                   the level 2 cache is for other models.  Pretend
                   the caller asked for the level 2 cache.  */
                name = (_SC_LEVEL2_CACHE_SIZE
                       + (name - _SC_LEVEL3_CACHE_SIZE));
                folded_name = _SC_LEVEL3_CACHE_SIZE;
              }
           }

         struct intel_02_cache_info *found;
         struct intel_02_cache_info search;

         search.idx = byte;
         found = bsearch (&search, intel_02_known, nintel_02_known,
                        sizeof (intel_02_known[0]), intel_02_known_compare);
         if (found != NULL)
           {
             if (found->name == folded_name)
              {
                unsigned int offset = name - folded_name;

                if (offset == 0)
                  /* Cache size.  */
                  return found->size;
                if (offset == 1)
                  return found->assoc;

                assert (offset == 2);
                return found->linesize;
              }

             if (found->name == _SC_LEVEL2_CACHE_SIZE)
              *has_level_2 = true;
           }
       }

      /* Next byte for the next round.  */
      value >>= 8;
    }

  /* Nothing found.  */
  return 0;
}

Here is the call graph for this function:

static void __attribute__ ( (constructor)  ) [static]

Definition at line 424 of file cacheinfo.c.

{
  /* Find out what brand of processor.  */
  unsigned int eax;
  unsigned int ebx;
  unsigned int ecx;
  unsigned int edx;
  int max_cpuid;
  int max_cpuid_ex;
  long int data = -1;
  long int shared = -1;
  unsigned int level;
  unsigned int threads = 0;

  asm volatile ("cpuid"
              : "=a" (max_cpuid), "=b" (ebx), "=c" (ecx), "=d" (edx)
              : "0" (0));

  /* This spells out "GenuineIntel".  */
  if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69)
    {
      data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, max_cpuid);

      /* Try L3 first.  */
      level  = 3;
      shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, max_cpuid);

      if (shared <= 0)
        {
         /* Try L2 otherwise.  */
          level  = 2;
          shared = handle_intel (_SC_LEVEL2_CACHE_SIZE, max_cpuid);
       }

      asm volatile ("cpuid"
                  : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
                  : "0" (1));

      /* Intel prefers SSSE3 instructions for memory/string routines
        if they are avaiable.  */
      if ((ecx & 0x200))
       __x86_64_preferred_memory_instruction = 3;
      else
       __x86_64_preferred_memory_instruction = 2;

      /* Figure out the number of logical threads that share the
        highest cache level.  */
      if (max_cpuid >= 4)
        {
         int i = 0;

         /* Query until desired cache level is enumerated.  */
         do
           {
              asm volatile ("cpuid"
                          : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
                          : "0" (4), "2" (i++));

             /* There seems to be a bug in at least some Pentium Ds
               which sometimes fail to iterate all cache parameters.
               Do not loop indefinitely here, stop in this case and
               assume there is no such information.  */
             if ((eax & 0x1f) == 0)
              goto intel_bug_no_cache_info;
           }
          while (((eax >> 5) & 0x7) != level);

         threads = ((eax >> 14) & 0x3ff) + 1;
       }
      else
        {
       intel_bug_no_cache_info:
         /* Assume that all logical threads share the highest cache level.  */

         threads = (ebx >> 16) & 0xff;
       }

      /* Cap usage of highest cache level to the number of supported
        threads.  */
      if (shared > 0 && threads > 0)
        shared /= threads;
    }
  /* This spells out "AuthenticAMD".  */
  else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
    {
      data   = handle_amd (_SC_LEVEL1_DCACHE_SIZE);
      long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE);
      shared = handle_amd (_SC_LEVEL3_CACHE_SIZE);

      /* Get maximum extended function. */
      asm volatile ("cpuid"
                  : "=a" (max_cpuid_ex), "=b" (ebx), "=c" (ecx), "=d" (edx)
                  : "0" (0x80000000));

      if (shared <= 0)
       /* No shared L3 cache.  All we have is the L2 cache.  */
       shared = core;
      else
       {
         /* Figure out the number of logical threads that share L3.  */
         if (max_cpuid_ex >= 0x80000008)
           {
             /* Get width of APIC ID.  */
             asm volatile ("cpuid"
                         : "=a" (max_cpuid_ex), "=b" (ebx), "=c" (ecx),
                           "=d" (edx)
                         : "0" (0x80000008));
             threads = 1 << ((ecx >> 12) & 0x0f);
           }

         if (threads == 0)
           {
             /* If APIC ID width is not available, use logical
               processor count.  */
             asm volatile ("cpuid"
                         : "=a" (max_cpuid_ex), "=b" (ebx), "=c" (ecx),
                           "=d" (edx)
                         : "0" (0x00000001));

             if ((edx & (1 << 28)) != 0)
              threads = (ebx >> 16) & 0xff;
           }

         /* Cap usage of highest cache level to the number of
            supported threads.  */
         if (threads > 0)
           shared /= threads;

         /* Account for exclusive L2 and L3 caches.  */
         shared += core;
       }

      if (max_cpuid_ex >= 0x80000001)
       {
         asm volatile ("cpuid"
                     : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
                     : "0" (0x80000001));
         /*  PREFETCHW     || 3DNow!  */
         if ((ecx & 0x100) || (edx & 0x80000000))
           __x86_64_prefetchw = -1;
       }
    }

  if (data > 0)
    __x86_64_data_cache_size_half = data / 2;

  if (shared > 0)
    {
      __x86_64_shared_cache_size_half = shared / 2;
      __x86_64_shared_cache_size = shared;
    }
}

Definition at line 376 of file cacheinfo.c.

{
  /* Find out what brand of processor.  */
  unsigned int eax;
  unsigned int ebx;
  unsigned int ecx;
  unsigned int edx;
  asm volatile ("cpuid"
              : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
              : "0" (0));

  /* This spells out "GenuineIntel".  */
  if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69)
    return handle_intel (name, eax);

  /* This spells out "AuthenticAMD".  */
  if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
    return handle_amd (name);

  // XXX Fill in more vendors.

  /* CPU not known, we have no information.  */
  return 0;
}
static int intel_02_known_compare ( const void *  p1,
const void *  p2 
) [static]

Definition at line 88 of file cacheinfo.c.

{
  const struct intel_02_cache_info *i1;
  const struct intel_02_cache_info *i2;

  i1 = (const struct intel_02_cache_info *) p1;
  i2 = (const struct intel_02_cache_info *) p2;

  if (i1->idx == i2->idx)
    return 0;

  return i1->idx < i2->idx ? -1 : 1;
}

Here is the caller graph for this function:


Variable Documentation

int __x86_64_preferred_memory_instruction attribute_hidden = 32 * 1024 / 2

Definition at line 404 of file cacheinfo.c.