Blame sysdeps/x86/cacheinfo.c

Packit Service 562438
/* x86_64 cache info.
Packit Service 562438
   Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#if IS_IN (libc)
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit Service 562438
#include <stdbool.h>
Packit Service 562438
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <cpuid.h>
Packit Service 562438
#include <init-arch.h>
Packit Service 562438
Packit Service 562438
static const struct intel_02_cache_info
Packit Service 562438
{
Packit Service 562438
  unsigned char idx;
Packit Service 562438
  unsigned char assoc;
Packit Service 562438
  unsigned char linesize;
Packit Service 562438
  unsigned char rel_name;
Packit Service 562438
  unsigned int size;
Packit Service 562438
} intel_02_known [] =
Packit Service 562438
  {
Packit Service 562438
#define M(sc) ((sc) - _SC_LEVEL1_ICACHE_SIZE)
Packit Service 562438
    { 0x06,  4, 32, M(_SC_LEVEL1_ICACHE_SIZE),    8192 },
Packit Service 562438
    { 0x08,  4, 32, M(_SC_LEVEL1_ICACHE_SIZE),   16384 },
Packit Service 562438
    { 0x09,  4, 32, M(_SC_LEVEL1_ICACHE_SIZE),   32768 },
Packit Service 562438
    { 0x0a,  2, 32, M(_SC_LEVEL1_DCACHE_SIZE),    8192 },
Packit Service 562438
    { 0x0c,  4, 32, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 562438
    { 0x0d,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 562438
    { 0x0e,  6, 64, M(_SC_LEVEL1_DCACHE_SIZE),   24576 },
Packit Service 562438
    { 0x21,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 562438
    { 0x22,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x23,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0x25,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0x29,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 562438
    { 0x2c,  8, 64, M(_SC_LEVEL1_DCACHE_SIZE),   32768 },
Packit Service 562438
    { 0x30,  8, 64, M(_SC_LEVEL1_ICACHE_SIZE),   32768 },
Packit Service 562438
    { 0x39,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 562438
    { 0x3a,  6, 64, M(_SC_LEVEL2_CACHE_SIZE),   196608 },
Packit Service 562438
    { 0x3b,  2, 64, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 562438
    { 0x3c,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 562438
    { 0x3d,  6, 64, M(_SC_LEVEL2_CACHE_SIZE),   393216 },
Packit Service 562438
    { 0x3e,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x3f,  2, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 562438
    { 0x41,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 562438
    { 0x42,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 562438
    { 0x43,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x44,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0x45,  4, 32, M(_SC_LEVEL2_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0x46,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 562438
    { 0x47,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 562438
    { 0x48, 12, 64, M(_SC_LEVEL2_CACHE_SIZE),  3145728 },
Packit Service 562438
    { 0x49, 16, 64, M(_SC_LEVEL2_CACHE_SIZE),  4194304 },
Packit Service 562438
    { 0x4a, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  6291456 },
Packit Service 562438
    { 0x4b, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 562438
    { 0x4c, 12, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 },
Packit Service 562438
    { 0x4d, 16, 64, M(_SC_LEVEL3_CACHE_SIZE), 16777216 },
Packit Service 562438
    { 0x4e, 24, 64, M(_SC_LEVEL2_CACHE_SIZE),  6291456 },
Packit Service 562438
    { 0x60,  8, 64, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 562438
    { 0x66,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),    8192 },
Packit Service 562438
    { 0x67,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),   16384 },
Packit Service 562438
    { 0x68,  4, 64, M(_SC_LEVEL1_DCACHE_SIZE),   32768 },
Packit Service 562438
    { 0x78,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0x79,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   131072 },
Packit Service 562438
    { 0x7a,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 562438
    { 0x7b,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x7c,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0x7d,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0x7f,  2, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x80,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x82,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),   262144 },
Packit Service 562438
    { 0x83,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x84,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0x85,  8, 32, M(_SC_LEVEL2_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0x86,  4, 64, M(_SC_LEVEL2_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0x87,  8, 64, M(_SC_LEVEL2_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0xd0,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),   524288 },
Packit Service 562438
    { 0xd1,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0xd2,  4, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0xd6,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  1048576 },
Packit Service 562438
    { 0xd7,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0xd8,  8, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 562438
    { 0xdc, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0xdd, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 562438
    { 0xde, 12, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 562438
    { 0xe2, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  2097152 },
Packit Service 562438
    { 0xe3, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  4194304 },
Packit Service 562438
    { 0xe4, 16, 64, M(_SC_LEVEL3_CACHE_SIZE),  8388608 },
Packit Service 562438
    { 0xea, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 12582912 },
Packit Service 562438
    { 0xeb, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 18874368 },
Packit Service 562438
    { 0xec, 24, 64, M(_SC_LEVEL3_CACHE_SIZE), 25165824 },
Packit Service 562438
  };
Packit Service 562438
Packit Service 562438
#define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known [0]))
Packit Service 562438
Packit Service 562438
static int
Packit Service 562438
intel_02_known_compare (const void *p1, const void *p2)
Packit Service 562438
{
Packit Service 562438
  const struct intel_02_cache_info *i1;
Packit Service 562438
  const struct intel_02_cache_info *i2;
Packit Service 562438
Packit Service 562438
  i1 = (const struct intel_02_cache_info *) p1;
Packit Service 562438
  i2 = (const struct intel_02_cache_info *) p2;
Packit Service 562438
Packit Service 562438
  if (i1->idx == i2->idx)
Packit Service 562438
    return 0;
Packit Service 562438
Packit Service 562438
  return i1->idx < i2->idx ? -1 : 1;
Packit Service 562438
}
Packit Service 562438
Packit Service 562438
Packit Service 562438
static long int
Packit Service 562438
__attribute__ ((noinline))
Packit Service 562438
intel_check_word (int name, unsigned int value, bool *has_level_2,
Packit Service 562438
		  bool *no_level_2_or_3,
Packit Service 562438
		  const struct cpu_features *cpu_features)
Packit Service 562438
{
Packit Service 562438
  if ((value & 0x80000000) != 0)
Packit Service 562438
    /* The register value is reserved.  */
Packit Service 562438
    return 0;
Packit Service 562438
Packit Service 562438
  /* Fold the name.  The _SC_ constants are always in the order SIZE,
Packit Service 562438
     ASSOC, LINESIZE.  */
Packit Service 562438
  int folded_rel_name = (M(name) / 3) * 3;
Packit Service 562438
Packit Service 562438
  while (value != 0)
Packit Service 562438
    {
Packit Service 562438
      unsigned int byte = value & 0xff;
Packit Service 562438
Packit Service 562438
      if (byte == 0x40)
Packit Service 562438
	{
Packit Service 562438
	  *no_level_2_or_3 = true;
Packit Service 562438
Packit Service 562438
	  if (folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
Packit Service 562438
	    /* No need to look further.  */
Packit Service 562438
	    break;
Packit Service 562438
	}
Packit Service 562438
      else if (byte == 0xff)
Packit Service 562438
	{
Packit Service 562438
	  /* CPUID leaf 0x4 contains all the information.  We need to
Packit Service 562438
	     iterate over it.  */
Packit Service 562438
	  unsigned int eax;
Packit Service 562438
	  unsigned int ebx;
Packit Service 562438
	  unsigned int ecx;
Packit Service 562438
	  unsigned int edx;
Packit Service 562438
Packit Service 562438
	  unsigned int round = 0;
Packit Service 562438
	  while (1)
Packit Service 562438
	    {
Packit Service 562438
	      __cpuid_count (4, round, eax, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
	      enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
Packit Service 562438
	      if (type == null)
Packit Service 562438
		/* That was the end.  */
Packit Service 562438
		break;
Packit Service 562438
Packit Service 562438
	      unsigned int level = (eax >> 5) & 0x7;
Packit Service 562438
Packit Service 562438
	      if ((level == 1 && type == data
Packit Service 562438
		   && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
Packit Service 562438
		  || (level == 1 && type == inst
Packit Service 562438
		      && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
Packit Service 562438
		  || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
Packit Service 562438
		  || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
Packit Service 562438
		  || (level == 4 && folded_rel_name == M(_SC_LEVEL4_CACHE_SIZE)))
Packit Service 562438
		{
Packit Service 562438
		  unsigned int offset = M(name) - folded_rel_name;
Packit Service 562438
Packit Service 562438
		  if (offset == 0)
Packit Service 562438
		    /* Cache size.  */
Packit Service 562438
		    return (((ebx >> 22) + 1)
Packit Service 562438
			    * (((ebx >> 12) & 0x3ff) + 1)
Packit Service 562438
			    * ((ebx & 0xfff) + 1)
Packit Service 562438
			    * (ecx + 1));
Packit Service 562438
		  if (offset == 1)
Packit Service 562438
		    return (ebx >> 22) + 1;
Packit Service 562438
Packit Service 562438
		  assert (offset == 2);
Packit Service 562438
		  return (ebx & 0xfff) + 1;
Packit Service 562438
		}
Packit Service 562438
Packit Service 562438
	      ++round;
Packit Service 562438
	    }
Packit Service 562438
	  /* There is no other cache information anywhere else.  */
Packit Service 562438
	  break;
Packit Service 562438
	}
Packit Service 562438
      else
Packit Service 562438
	{
Packit Service 562438
	  if (byte == 0x49 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE))
Packit Service 562438
	    {
Packit Service 562438
	      /* Intel reused this value.  For family 15, model 6 it
Packit Service 562438
		 specifies the 3rd level cache.  Otherwise the 2nd
Packit Service 562438
		 level cache.  */
Packit Service 6e118c
	      unsigned int family = cpu_features->basic.family;
Packit Service 6e118c
	      unsigned int model = cpu_features->basic.model;
Packit Service 562438
Packit Service 562438
	      if (family == 15 && model == 6)
Packit Service 562438
		{
Packit Service 562438
		  /* The level 3 cache is encoded for this model like
Packit Service 562438
		     the level 2 cache is for other models.  Pretend
Packit Service 562438
		     the caller asked for the level 2 cache.  */
Packit Service 562438
		  name = (_SC_LEVEL2_CACHE_SIZE
Packit Service 562438
			  + (name - _SC_LEVEL3_CACHE_SIZE));
Packit Service 562438
		  folded_rel_name = M(_SC_LEVEL2_CACHE_SIZE);
Packit Service 562438
		}
Packit Service 562438
	    }
Packit Service 562438
Packit Service 562438
	  struct intel_02_cache_info *found;
Packit Service 562438
	  struct intel_02_cache_info search;
Packit Service 562438
Packit Service 562438
	  search.idx = byte;
Packit Service 562438
	  found = bsearch (&search, intel_02_known, nintel_02_known,
Packit Service 562438
			   sizeof (intel_02_known[0]), intel_02_known_compare);
Packit Service 562438
	  if (found != NULL)
Packit Service 562438
	    {
Packit Service 562438
	      if (found->rel_name == folded_rel_name)
Packit Service 562438
		{
Packit Service 562438
		  unsigned int offset = M(name) - folded_rel_name;
Packit Service 562438
Packit Service 562438
		  if (offset == 0)
Packit Service 562438
		    /* Cache size.  */
Packit Service 562438
		    return found->size;
Packit Service 562438
		  if (offset == 1)
Packit Service 562438
		    return found->assoc;
Packit Service 562438
Packit Service 562438
		  assert (offset == 2);
Packit Service 562438
		  return found->linesize;
Packit Service 562438
		}
Packit Service 562438
Packit Service 562438
	      if (found->rel_name == M(_SC_LEVEL2_CACHE_SIZE))
Packit Service 562438
		*has_level_2 = true;
Packit Service 562438
	    }
Packit Service 562438
	}
Packit Service 562438
Packit Service 562438
      /* Next byte for the next round.  */
Packit Service 562438
      value >>= 8;
Packit Service 562438
    }
Packit Service 562438
Packit Service 562438
  /* Nothing found.  */
Packit Service 562438
  return 0;
Packit Service 562438
}
Packit Service 562438
Packit Service 562438
Packit Service 562438
static long int __attribute__ ((noinline))
Packit Service 562438
handle_intel (int name, const struct cpu_features *cpu_features)
Packit Service 562438
{
Packit Service 6e118c
  unsigned int maxidx = cpu_features->basic.max_cpuid;
Packit Service 562438
Packit Service 562438
  /* Return -1 for older CPUs.  */
Packit Service 562438
  if (maxidx < 2)
Packit Service 562438
    return -1;
Packit Service 562438
Packit Service 562438
  /* OK, we can use the CPUID instruction to get all info about the
Packit Service 562438
     caches.  */
Packit Service 562438
  unsigned int cnt = 0;
Packit Service 562438
  unsigned int max = 1;
Packit Service 562438
  long int result = 0;
Packit Service 562438
  bool no_level_2_or_3 = false;
Packit Service 562438
  bool has_level_2 = false;
Packit Service 562438
Packit Service 562438
  while (cnt++ < max)
Packit Service 562438
    {
Packit Service 562438
      unsigned int eax;
Packit Service 562438
      unsigned int ebx;
Packit Service 562438
      unsigned int ecx;
Packit Service 562438
      unsigned int edx;
Packit Service 562438
      __cpuid (2, eax, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
      /* The low byte of EAX in the first round contain the number of
Packit Service 562438
	 rounds we have to make.  At least one, the one we are already
Packit Service 562438
	 doing.  */
Packit Service 562438
      if (cnt == 1)
Packit Service 562438
	{
Packit Service 562438
	  max = eax & 0xff;
Packit Service 562438
	  eax &= 0xffffff00;
Packit Service 562438
	}
Packit Service 562438
Packit Service 562438
      /* Process the individual registers' value.  */
Packit Service 562438
      result = intel_check_word (name, eax, &has_level_2,
Packit Service 562438
				 &no_level_2_or_3, cpu_features);
Packit Service 562438
      if (result != 0)
Packit Service 562438
	return result;
Packit Service 562438
Packit Service 562438
      result = intel_check_word (name, ebx, &has_level_2,
Packit Service 562438
				 &no_level_2_or_3, cpu_features);
Packit Service 562438
      if (result != 0)
Packit Service 562438
	return result;
Packit Service 562438
Packit Service 562438
      result = intel_check_word (name, ecx, &has_level_2,
Packit Service 562438
				 &no_level_2_or_3, cpu_features);
Packit Service 562438
      if (result != 0)
Packit Service 562438
	return result;
Packit Service 562438
Packit Service 562438
      result = intel_check_word (name, edx, &has_level_2,
Packit Service 562438
				 &no_level_2_or_3, cpu_features);
Packit Service 562438
      if (result != 0)
Packit Service 562438
	return result;
Packit Service 562438
    }
Packit Service 562438
Packit Service 562438
  if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE
Packit Service 562438
      && no_level_2_or_3)
Packit Service 562438
    return -1;
Packit Service 562438
Packit Service 562438
  return 0;
Packit Service 562438
}
Packit Service 562438
Packit Service 562438
Packit Service 562438
static long int __attribute__ ((noinline))
Packit Service 562438
handle_amd (int name)
Packit Service 562438
{
Packit Service 562438
  unsigned int eax;
Packit Service 562438
  unsigned int ebx;
Packit Service 562438
  unsigned int ecx;
Packit Service 562438
  unsigned int edx;
Packit Service 562438
  __cpuid (0x80000000, eax, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
  /* No level 4 cache (yet).  */
Packit Service 562438
  if (name > _SC_LEVEL3_CACHE_LINESIZE)
Packit Service 562438
    return 0;
Packit Service 562438
Packit Service 562438
  unsigned int fn = 0x80000005 + (name >= _SC_LEVEL2_CACHE_SIZE);
Packit Service 562438
  if (eax < fn)
Packit Service 562438
    return 0;
Packit Service 562438
Packit Service 562438
  __cpuid (fn, eax, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
  if (name < _SC_LEVEL1_DCACHE_SIZE)
Packit Service 562438
    {
Packit Service 562438
      name += _SC_LEVEL1_DCACHE_SIZE - _SC_LEVEL1_ICACHE_SIZE;
Packit Service 562438
      ecx = edx;
Packit Service 562438
    }
Packit Service 562438
Packit Service 562438
  switch (name)
Packit Service 562438
    {
Packit Service 562438
    case _SC_LEVEL1_DCACHE_SIZE:
Packit Service 562438
      return (ecx >> 14) & 0x3fc00;
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL1_DCACHE_ASSOC:
Packit Service 562438
      ecx >>= 16;
Packit Service 562438
      if ((ecx & 0xff) == 0xff)
Packit Service 562438
	/* Fully associative.  */
Packit Service 562438
	return (ecx << 2) & 0x3fc00;
Packit Service 562438
      return ecx & 0xff;
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL1_DCACHE_LINESIZE:
Packit Service 562438
      return ecx & 0xff;
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL2_CACHE_SIZE:
Packit Service 562438
      return (ecx & 0xf000) == 0 ? 0 : (ecx >> 6) & 0x3fffc00;
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL2_CACHE_ASSOC:
Packit Service 562438
      switch ((ecx >> 12) & 0xf)
Packit Service 562438
	{
Packit Service 562438
	case 0:
Packit Service 562438
	case 1:
Packit Service 562438
	case 2:
Packit Service 562438
	case 4:
Packit Service 562438
	  return (ecx >> 12) & 0xf;
Packit Service 562438
	case 6:
Packit Service 562438
	  return 8;
Packit Service 562438
	case 8:
Packit Service 562438
	  return 16;
Packit Service 562438
	case 10:
Packit Service 562438
	  return 32;
Packit Service 562438
	case 11:
Packit Service 562438
	  return 48;
Packit Service 562438
	case 12:
Packit Service 562438
	  return 64;
Packit Service 562438
	case 13:
Packit Service 562438
	  return 96;
Packit Service 562438
	case 14:
Packit Service 562438
	  return 128;
Packit Service 562438
	case 15:
Packit Service 562438
	  return ((ecx >> 6) & 0x3fffc00) / (ecx & 0xff);
Packit Service 562438
	default:
Packit Service 562438
	  return 0;
Packit Service 562438
	}
Packit Service 562438
      /* NOTREACHED */
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL2_CACHE_LINESIZE:
Packit Service 562438
      return (ecx & 0xf000) == 0 ? 0 : ecx & 0xff;
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL3_CACHE_SIZE:
Packit Service 562438
      return (edx & 0xf000) == 0 ? 0 : (edx & 0x3ffc0000) << 1;
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL3_CACHE_ASSOC:
Packit Service 562438
      switch ((edx >> 12) & 0xf)
Packit Service 562438
	{
Packit Service 562438
	case 0:
Packit Service 562438
	case 1:
Packit Service 562438
	case 2:
Packit Service 562438
	case 4:
Packit Service 562438
	  return (edx >> 12) & 0xf;
Packit Service 562438
	case 6:
Packit Service 562438
	  return 8;
Packit Service 562438
	case 8:
Packit Service 562438
	  return 16;
Packit Service 562438
	case 10:
Packit Service 562438
	  return 32;
Packit Service 562438
	case 11:
Packit Service 562438
	  return 48;
Packit Service 562438
	case 12:
Packit Service 562438
	  return 64;
Packit Service 562438
	case 13:
Packit Service 562438
	  return 96;
Packit Service 562438
	case 14:
Packit Service 562438
	  return 128;
Packit Service 562438
	case 15:
Packit Service 562438
	  return ((edx & 0x3ffc0000) << 1) / (edx & 0xff);
Packit Service 562438
	default:
Packit Service 562438
	  return 0;
Packit Service 562438
	}
Packit Service 562438
      /* NOTREACHED */
Packit Service 562438
Packit Service 562438
    case _SC_LEVEL3_CACHE_LINESIZE:
Packit Service 562438
      return (edx & 0xf000) == 0 ? 0 : edx & 0xff;
Packit Service 562438
Packit Service 562438
    default:
Packit Service 562438
      assert (! "cannot happen");
Packit Service 562438
    }
Packit Service 562438
  return -1;
Packit Service 562438
}
Packit Service 562438
Packit Service 007ef8
Packit 6c4009
/* Get the value of the system variable NAME.  */
Packit 6c4009
long int
Packit 6c4009
attribute_hidden
Packit 6c4009
__cache_sysconf (int name)
Packit 6c4009
{
Packit 6c4009
  const struct cpu_features *cpu_features = __get_cpu_features ();
Packit 6c4009
Packit Service 6e118c
  if (cpu_features->basic.kind == arch_kind_intel)
Packit 6c4009
    return handle_intel (name, cpu_features);
Packit 6c4009
Packit Service 6e118c
  if (cpu_features->basic.kind == arch_kind_amd)
Packit 6c4009
    return handle_amd (name);
Packit 6c4009
Packit 6c4009
  // XXX Fill in more vendors.
Packit 6c4009
Packit 6c4009
  /* CPU not known, we have no information.  */
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit Service 562438
/* Data cache size for use in memory and string routines, typically
Packit Service 562438
   L1 size, rounded to multiple of 256 bytes.  */
Packit Service 562438
long int __x86_data_cache_size_half attribute_hidden = 32 * 1024 / 2;
Packit Service 562438
long int __x86_data_cache_size attribute_hidden = 32 * 1024;
Packit Service 562438
/* Similar to __x86_data_cache_size_half, but not rounded.  */
Packit Service 562438
long int __x86_raw_data_cache_size_half attribute_hidden = 32 * 1024 / 2;
Packit Service 562438
/* Similar to __x86_data_cache_size, but not rounded.  */
Packit Service 562438
long int __x86_raw_data_cache_size attribute_hidden = 32 * 1024;
Packit Service 562438
/* Shared cache size for use in memory and string routines, typically
Packit Service 562438
   L2 or L3 size, rounded to multiple of 256 bytes.  */
Packit Service 562438
long int __x86_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2;
Packit Service 562438
long int __x86_shared_cache_size attribute_hidden = 1024 * 1024;
Packit Service 562438
/* Similar to __x86_shared_cache_size_half, but not rounded.  */
Packit Service 562438
long int __x86_raw_shared_cache_size_half attribute_hidden = 1024 * 1024 / 2;
Packit Service 562438
/* Similar to __x86_shared_cache_size, but not rounded.  */
Packit Service 562438
long int __x86_raw_shared_cache_size attribute_hidden = 1024 * 1024;
Packit Service 562438
Packit Service 562438
/* Threshold to use non temporal store.  */
Packit Service 562438
long int __x86_shared_non_temporal_threshold attribute_hidden;
Packit Service 562438
Packit Service 562438
#ifndef DISABLE_PREFETCHW
Packit Service 562438
/* PREFETCHW support flag for use in memory and string routines.  */
Packit Service 562438
int __x86_prefetchw attribute_hidden;
Packit Service 562438
#endif
Packit Service 562438
Packit Service 562438
Packit Service 562438
static void
Packit Service 562438
__attribute__((constructor))
Packit Service 562438
init_cacheinfo (void)
Packit Service 562438
{
Packit Service 562438
  /* Find out what brand of processor.  */
Packit Service 562438
  unsigned int eax;
Packit Service 562438
  unsigned int ebx;
Packit Service 562438
  unsigned int ecx;
Packit Service 562438
  unsigned int edx;
Packit Service 562438
  int max_cpuid_ex;
Packit Service 562438
  long int data = -1;
Packit Service 562438
  long int shared = -1;
Packit Service 562438
  unsigned int level;
Packit Service 562438
  unsigned int threads = 0;
Packit Service 562438
  const struct cpu_features *cpu_features = __get_cpu_features ();
Packit Service 6e118c
  int max_cpuid = cpu_features->basic.max_cpuid;
Packit Service 562438
Packit Service 6e118c
  if (cpu_features->basic.kind == arch_kind_intel)
Packit Service 562438
    {
Packit Service 562438
      data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features);
Packit Service 562438
Packit Service 562438
      long int core = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
Packit Service 562438
      bool inclusive_cache = true;
Packit Service 562438
Packit Service 562438
      /* Try L3 first.  */
Packit Service 562438
      level  = 3;
Packit Service 562438
      shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features);
Packit Service 562438
Packit Service 562438
      /* Number of logical processors sharing L2 cache.  */
Packit Service 562438
      int threads_l2;
Packit Service 562438
Packit Service 562438
      /* Number of logical processors sharing L3 cache.  */
Packit Service 562438
      int threads_l3;
Packit Service 562438
Packit Service 562438
      if (shared <= 0)
Packit Service 562438
	{
Packit Service 562438
	  /* Try L2 otherwise.  */
Packit Service 562438
	  level  = 2;
Packit Service 562438
	  shared = core;
Packit Service 562438
	  threads_l2 = 0;
Packit Service 562438
	  threads_l3 = -1;
Packit Service 562438
	}
Packit Service 562438
      else
Packit Service 562438
	{
Packit Service 562438
	  threads_l2 = 0;
Packit Service 562438
	  threads_l3 = 0;
Packit Service 562438
	}
Packit Service 562438
Packit Service 562438
      /* A value of 0 for the HTT bit indicates there is only a single
Packit Service 562438
	 logical processor.  */
Packit Service 562438
      if (HAS_CPU_FEATURE (HTT))
Packit Service 562438
	{
Packit Service 562438
	  /* Figure out the number of logical threads that share the
Packit Service 562438
	     highest cache level.  */
Packit Service 562438
	  if (max_cpuid >= 4)
Packit Service 562438
	    {
Packit Service 6e118c
	      unsigned int family = cpu_features->basic.family;
Packit Service 6e118c
	      unsigned int model = cpu_features->basic.model;
Packit Service 562438
Packit Service 562438
	      int i = 0;
Packit Service 562438
Packit Service 562438
	      /* Query until cache level 2 and 3 are enumerated.  */
Packit Service 562438
	      int check = 0x1 | (threads_l3 == 0) << 1;
Packit Service 562438
	      do
Packit Service 562438
		{
Packit Service 562438
		  __cpuid_count (4, i++, eax, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
		  /* There seems to be a bug in at least some Pentium Ds
Packit Service 562438
		     which sometimes fail to iterate all cache parameters.
Packit Service 562438
		     Do not loop indefinitely here, stop in this case and
Packit Service 562438
		     assume there is no such information.  */
Packit Service 562438
		  if ((eax & 0x1f) == 0)
Packit Service 562438
		    goto intel_bug_no_cache_info;
Packit Service 562438
Packit Service 562438
		  switch ((eax >> 5) & 0x7)
Packit Service 562438
		    {
Packit Service 562438
		    default:
Packit Service 562438
		      break;
Packit Service 562438
		    case 2:
Packit Service 562438
		      if ((check & 0x1))
Packit Service 562438
			{
Packit Service 562438
			  /* Get maximum number of logical processors
Packit Service 562438
			     sharing L2 cache.  */
Packit Service 562438
			  threads_l2 = (eax >> 14) & 0x3ff;
Packit Service 562438
			  check &= ~0x1;
Packit Service 562438
			}
Packit Service 562438
		      break;
Packit Service 562438
		    case 3:
Packit Service 562438
		      if ((check & (0x1 << 1)))
Packit Service 562438
			{
Packit Service 562438
			  /* Get maximum number of logical processors
Packit Service 562438
			     sharing L3 cache.  */
Packit Service 562438
			  threads_l3 = (eax >> 14) & 0x3ff;
Packit Service 562438
Packit Service 562438
			  /* Check if L2 and L3 caches are inclusive.  */
Packit Service 562438
			  inclusive_cache = (edx & 0x2) != 0;
Packit Service 562438
			  check &= ~(0x1 << 1);
Packit Service 562438
			}
Packit Service 562438
		      break;
Packit Service 562438
		    }
Packit Service 562438
		}
Packit Service 562438
	      while (check);
Packit Service 562438
Packit Service 562438
	      /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum
Packit Service 562438
		 numbers of addressable IDs for logical processors sharing
Packit Service 562438
		 the cache, instead of the maximum number of threads
Packit Service 562438
		 sharing the cache.  */
Packit Service 562438
	      if (max_cpuid >= 11)
Packit Service 562438
		{
Packit Service 562438
		  /* Find the number of logical processors shipped in
Packit Service 562438
		     one core and apply count mask.  */
Packit Service 562438
		  i = 0;
Packit Service 562438
Packit Service 562438
		  /* Count SMT only if there is L3 cache.  Always count
Packit Service 562438
		     core if there is no L3 cache.  */
Packit Service 562438
		  int count = ((threads_l2 > 0 && level == 3)
Packit Service 562438
			       | ((threads_l3 > 0
Packit Service 562438
				   || (threads_l2 > 0 && level == 2)) << 1));
Packit Service 562438
Packit Service 562438
		  while (count)
Packit Service 562438
		    {
Packit Service 562438
		      __cpuid_count (11, i++, eax, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
		      int shipped = ebx & 0xff;
Packit Service 562438
		      int type = ecx & 0xff00;
Packit Service 562438
		      if (shipped == 0 || type == 0)
Packit Service 562438
			break;
Packit Service 562438
		      else if (type == 0x100)
Packit Service 562438
			{
Packit Service 562438
			  /* Count SMT.  */
Packit Service 562438
			  if ((count & 0x1))
Packit Service 562438
			    {
Packit Service 562438
			      int count_mask;
Packit Service 562438
Packit Service 562438
			      /* Compute count mask.  */
Packit Service 562438
			      asm ("bsr %1, %0"
Packit Service 562438
				   : "=r" (count_mask) : "g" (threads_l2));
Packit Service 562438
			      count_mask = ~(-1 << (count_mask + 1));
Packit Service 562438
			      threads_l2 = (shipped - 1) & count_mask;
Packit Service 562438
			      count &= ~0x1;
Packit Service 562438
			    }
Packit Service 562438
			}
Packit Service 562438
		      else if (type == 0x200)
Packit Service 562438
			{
Packit Service 562438
			  /* Count core.  */
Packit Service 562438
			  if ((count & (0x1 << 1)))
Packit Service 562438
			    {
Packit Service 562438
			      int count_mask;
Packit Service 562438
			      int threads_core
Packit Service 562438
				= (level == 2 ? threads_l2 : threads_l3);
Packit Service 562438
Packit Service 562438
			      /* Compute count mask.  */
Packit Service 562438
			      asm ("bsr %1, %0"
Packit Service 562438
				   : "=r" (count_mask) : "g" (threads_core));
Packit Service 562438
			      count_mask = ~(-1 << (count_mask + 1));
Packit Service 562438
			      threads_core = (shipped - 1) & count_mask;
Packit Service 562438
			      if (level == 2)
Packit Service 562438
				threads_l2 = threads_core;
Packit Service 562438
			      else
Packit Service 562438
				threads_l3 = threads_core;
Packit Service 562438
			      count &= ~(0x1 << 1);
Packit Service 562438
			    }
Packit Service 562438
			}
Packit Service 562438
		    }
Packit Service 562438
		}
Packit Service 562438
	      if (threads_l2 > 0)
Packit Service 562438
		threads_l2 += 1;
Packit Service 562438
	      if (threads_l3 > 0)
Packit Service 562438
		threads_l3 += 1;
Packit Service 562438
	      if (level == 2)
Packit Service 562438
		{
Packit Service 562438
		  if (threads_l2)
Packit Service 562438
		    {
Packit Service 562438
		      threads = threads_l2;
Packit Service 562438
		      if (threads > 2 && family == 6)
Packit Service 562438
			switch (model)
Packit Service 562438
			  {
Packit Service 562438
			  case 0x37:
Packit Service 562438
			  case 0x4a:
Packit Service 562438
			  case 0x4d:
Packit Service 562438
			  case 0x5a:
Packit Service 562438
			  case 0x5d:
Packit Service 562438
			    /* Silvermont has L2 cache shared by 2 cores.  */
Packit Service 562438
			    threads = 2;
Packit Service 562438
			    break;
Packit Service 562438
			  default:
Packit Service 562438
			    break;
Packit Service 562438
			  }
Packit Service 562438
		    }
Packit Service 562438
		}
Packit Service 562438
	      else if (threads_l3)
Packit Service 562438
		threads = threads_l3;
Packit Service 562438
	    }
Packit Service 562438
	  else
Packit Service 562438
	    {
Packit Service 562438
intel_bug_no_cache_info:
Packit Service 562438
	      /* Assume that all logical threads share the highest cache
Packit Service 562438
		 level.  */
Packit Service 562438
Packit Service 562438
	      threads
Packit Service 562438
		= ((cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx
Packit Service 562438
		    >> 16) & 0xff);
Packit Service 562438
	    }
Packit Service 562438
Packit Service 562438
	  /* Cap usage of highest cache level to the number of supported
Packit Service 562438
	     threads.  */
Packit Service 562438
	  if (shared > 0 && threads > 0)
Packit Service 562438
	    shared /= threads;
Packit Service 562438
	}
Packit Service 562438
Packit Service 562438
      /* Account for non-inclusive L2 and L3 caches.  */
Packit Service 562438
      if (!inclusive_cache)
Packit Service 562438
	{
Packit Service 562438
	  if (threads_l2 > 0)
Packit Service 562438
	    core /= threads_l2;
Packit Service 562438
	  shared += core;
Packit Service 562438
	}
Packit Service 562438
    }
Packit Service 6e118c
  else if (cpu_features->basic.kind == arch_kind_amd)
Packit Service 562438
    {
Packit Service 562438
      data   = handle_amd (_SC_LEVEL1_DCACHE_SIZE);
Packit Service 562438
      long int core = handle_amd (_SC_LEVEL2_CACHE_SIZE);
Packit Service 562438
      shared = handle_amd (_SC_LEVEL3_CACHE_SIZE);
Packit Service 562438
Packit Service 562438
      /* Get maximum extended function. */
Packit Service 562438
      __cpuid (0x80000000, max_cpuid_ex, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
      if (shared <= 0)
Packit Service 562438
	/* No shared L3 cache.  All we have is the L2 cache.  */
Packit Service 562438
	shared = core;
Packit Service 562438
      else
Packit Service 562438
	{
Packit Service 562438
	  /* Figure out the number of logical threads that share L3.  */
Packit Service 562438
	  if (max_cpuid_ex >= 0x80000008)
Packit Service 562438
	    {
Packit Service 562438
	      /* Get width of APIC ID.  */
Packit Service 562438
	      __cpuid (0x80000008, max_cpuid_ex, ebx, ecx, edx);
Packit Service 562438
	      threads = 1 << ((ecx >> 12) & 0x0f);
Packit Service 562438
	    }
Packit Service 562438
Packit Service 6e118c
	  if (threads == 0 || cpu_features->basic.family >= 0x17)
Packit Service 562438
	    {
Packit Service 562438
	      /* If APIC ID width is not available, use logical
Packit Service 562438
		 processor count.  */
Packit Service 562438
	      __cpuid (0x00000001, max_cpuid_ex, ebx, ecx, edx);
Packit Service 562438
Packit Service 562438
	      if ((edx & (1 << 28)) != 0)
Packit Service 562438
		threads = (ebx >> 16) & 0xff;
Packit Service 562438
	    }
Packit Service 562438
Packit Service 562438
	  /* Cap usage of highest cache level to the number of
Packit Service 562438
	     supported threads.  */
Packit Service 562438
	  if (threads > 0)
Packit Service 562438
	    shared /= threads;
Packit Service 562438
Packit Service f515cf
	  /* Get shared cache per ccx for Zen architectures.  */
Packit Service 6e118c
	  if (cpu_features->basic.family >= 0x17)
Packit Service f515cf
	    {
Packit Service f515cf
	      unsigned int eax;
Packit Service f515cf
Packit Service f515cf
	      /* Get number of threads share the L3 cache in CCX.  */
Packit Service f515cf
	      __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx);
Packit Service f515cf
Packit Service f515cf
	      unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1;
Packit Service f515cf
	      shared *= threads_per_ccx;
Packit Service f515cf
	    }
Packit Service f515cf
	  else
Packit Service f515cf
	    {
Packit Service f515cf
	      /* Account for exclusive L2 and L3 caches.  */
Packit Service f515cf
	      shared += core;
Packit Service f515cf
            }
Packit Service 562438
	}
Packit Service 562438
Packit Service 562438
#ifndef DISABLE_PREFETCHW
Packit Service 562438
      if (max_cpuid_ex >= 0x80000001)
Packit Service 562438
	{
Packit Service 562438
	  __cpuid (0x80000001, eax, ebx, ecx, edx);
Packit Service 562438
	  /*  PREFETCHW     || 3DNow!  */
Packit Service 562438
	  if ((ecx & 0x100) || (edx & 0x80000000))
Packit Service 562438
	    __x86_prefetchw = -1;
Packit Service 562438
	}
Packit Service 562438
#endif
Packit Service 562438
    }
Packit Service 562438
Packit Service 562438
  if (cpu_features->data_cache_size != 0)
Packit Service 562438
    data = cpu_features->data_cache_size;
Packit Service 562438
Packit Service 562438
  if (data > 0)
Packit Service 562438
    {
Packit Service 562438
      __x86_raw_data_cache_size_half = data / 2;
Packit Service 562438
      __x86_raw_data_cache_size = data;
Packit Service 562438
      /* Round data cache size to multiple of 256 bytes.  */
Packit Service 562438
      data = data & ~255L;
Packit Service 562438
      __x86_data_cache_size_half = data / 2;
Packit Service 562438
      __x86_data_cache_size = data;
Packit Service 562438
    }
Packit Service 562438
Packit Service 562438
  if (cpu_features->shared_cache_size != 0)
Packit Service 562438
    shared = cpu_features->shared_cache_size;
Packit Service 562438
Packit Service 562438
  if (shared > 0)
Packit Service 562438
    {
Packit Service 562438
      __x86_raw_shared_cache_size_half = shared / 2;
Packit Service 562438
      __x86_raw_shared_cache_size = shared;
Packit Service 562438
      /* Round shared cache size to multiple of 256 bytes.  */
Packit Service 562438
      shared = shared & ~255L;
Packit Service 562438
      __x86_shared_cache_size_half = shared / 2;
Packit Service 562438
      __x86_shared_cache_size = shared;
Packit Service 562438
    }
Packit Service 562438
Packit Service 6a4279
  /* The default setting for the non_temporal threshold is 3/4 of one
Packit Service 6a4279
     thread's share of the chip's cache. For most Intel and AMD processors
Packit Service 6a4279
     with an initial release date between 2017 and 2020, a thread's typical
Packit Service 6a4279
     share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4
Packit Service 6a4279
     threshold leaves 125 KBytes to 500 KBytes of the thread's data
Packit Service 6a4279
     in cache after a maximum temporal copy, which will maintain
Packit Service 6a4279
     in cache a reasonable portion of the thread's stack and other
Packit Service 6a4279
     active data. If the threshold is set higher than one thread's
Packit Service 6a4279
     share of the cache, it has a substantial risk of negatively
Packit Service 6a4279
     impacting the performance of other threads running on the chip. */
Packit Service 562438
  __x86_shared_non_temporal_threshold
Packit Service 562438
    = (cpu_features->non_temporal_threshold != 0
Packit Service 562438
       ? cpu_features->non_temporal_threshold
Packit Service 6a4279
       : __x86_shared_cache_size * 3 / 4);
Packit Service 562438
}
Packit Service 3b0880
Packit 6c4009
#endif