Count number of logical processors sharing L2 cache

For Intel processors, when there are both L2 and L3 caches, SMT level
type should be ued to count number of available logical processors
sharing L2 cache.  If there is only L2 cache, core level type should
be used to count number of available logical processors sharing L2
cache.  Number of available logical processors sharing L2 cache should
be used for non-inclusive L2 and L3 caches.

	* sysdeps/x86/cacheinfo.c (init_cacheinfo): Count number of
	available logical processors with SMT level type sharing L2
	cache for Intel processors.
This commit is contained in:
H.J. Lu 2016-05-27 15:16:22 -07:00
parent f6ef0657e4
commit d6af2388f7
2 changed files with 122 additions and 34 deletions

View File

@ -1,3 +1,9 @@
2016-05-27 H.J. Lu <hongjiu.lu@intel.com>
* sysdeps/x86/cacheinfo.c (init_cacheinfo): Count number of
available logical processors with SMT level type sharing L2
cache for Intel processors.
2016-05-27 Joseph Myers <joseph@codesourcery.com> 2016-05-27 Joseph Myers <joseph@codesourcery.com>
[BZ #20160] [BZ #20160]

View File

@ -499,11 +499,24 @@ init_cacheinfo (void)
level = 3; level = 3;
shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, max_cpuid); shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, max_cpuid);
/* Number of logical processors sharing L2 cache. */
int threads_l2;
/* Number of logical processors sharing L3 cache. */
int threads_l3;
if (shared <= 0) if (shared <= 0)
{ {
/* Try L2 otherwise. */ /* Try L2 otherwise. */
level = 2; level = 2;
shared = core; shared = core;
threads_l2 = 0;
threads_l3 = -1;
}
else
{
threads_l2 = 0;
threads_l3 = 0;
} }
/* A value of 0 for the HTT bit indicates there is only a single /* A value of 0 for the HTT bit indicates there is only a single
@ -519,7 +532,8 @@ init_cacheinfo (void)
int i = 0; int i = 0;
/* Query until desired cache level is enumerated. */ /* Query until cache level 2 and 3 are enumerated. */
int check = 0x1 | (threads_l3 == 0) << 1;
do do
{ {
__cpuid_count (4, i++, eax, ebx, ecx, edx); __cpuid_count (4, i++, eax, ebx, ecx, edx);
@ -530,24 +544,53 @@ init_cacheinfo (void)
assume there is no such information. */ assume there is no such information. */
if ((eax & 0x1f) == 0) if ((eax & 0x1f) == 0)
goto intel_bug_no_cache_info; goto intel_bug_no_cache_info;
switch ((eax >> 5) & 0x7)
{
default:
break;
case 2:
if ((check & 0x1))
{
/* Get maximum number of logical processors
sharing L2 cache. */
threads_l2 = (eax >> 14) & 0x3ff;
check &= ~0x1;
}
break;
case 3:
if ((check & (0x1 << 1)))
{
/* Get maximum number of logical processors
sharing L3 cache. */
threads_l3 = (eax >> 14) & 0x3ff;
/* Check if L2 and L3 caches are inclusive. */
inclusive_cache = (edx & 0x2) != 0;
check &= ~(0x1 << 1);
}
break;
}
} }
while (((eax >> 5) & 0x7) != level); while (check);
/* Check if cache is inclusive of lower cache levels. */ /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum
inclusive_cache = (edx & 0x2) != 0; numbers of addressable IDs for logical processors sharing
the cache, instead of the maximum number of threads
threads = (eax >> 14) & 0x3ff;
/* If max_cpuid >= 11, THREADS is the maximum number of
addressable IDs for logical processors sharing the
cache, instead of the maximum number of threads
sharing the cache. */ sharing the cache. */
if (threads && max_cpuid >= 11) if (max_cpuid >= 11)
{ {
/* Find the number of logical processors shipped in /* Find the number of logical processors shipped in
one core and apply count mask. */ one core and apply count mask. */
i = 0; i = 0;
while (1)
/* Count SMT only if there is L3 cache. Always count
core if there is no L3 cache. */
int count = ((threads_l2 > 0 && level == 3)
| ((threads_l3 > 0
|| (threads_l2 > 0 && level == 2)) << 1));
while (count)
{ {
__cpuid_count (11, i++, eax, ebx, ecx, edx); __cpuid_count (11, i++, eax, ebx, ecx, edx);
@ -555,36 +598,71 @@ init_cacheinfo (void)
int type = ecx & 0xff00; int type = ecx & 0xff00;
if (shipped == 0 || type == 0) if (shipped == 0 || type == 0)
break; break;
else if (type == 0x100)
{
/* Count SMT. */
if ((count & 0x1))
{
int count_mask;
/* Compute count mask. */
asm ("bsr %1, %0"
: "=r" (count_mask) : "g" (threads_l2));
count_mask = ~(-1 << (count_mask + 1));
threads_l2 = (shipped - 1) & count_mask;
count &= ~0x1;
}
}
else if (type == 0x200) else if (type == 0x200)
{ {
int count_mask; /* Count core. */
if ((count & (0x1 << 1)))
{
int count_mask;
int threads_core
= (level == 2 ? threads_l2 : threads_l3);
/* Compute count mask. */ /* Compute count mask. */
asm ("bsr %1, %0" asm ("bsr %1, %0"
: "=r" (count_mask) : "g" (threads)); : "=r" (count_mask) : "g" (threads_core));
count_mask = ~(-1 << (count_mask + 1)); count_mask = ~(-1 << (count_mask + 1));
threads = (shipped - 1) & count_mask; threads_core = (shipped - 1) & count_mask;
break; if (level == 2)
threads_l2 = threads_core;
else
threads_l3 = threads_core;
count &= ~(0x1 << 1);
}
} }
} }
} }
threads += 1; if (threads_l2 > 0)
if (threads > 2 && level == 2 && family == 6) threads_l2 += 1;
if (threads_l3 > 0)
threads_l3 += 1;
if (level == 2)
{ {
switch (model) if (threads_l2)
{ {
case 0x37: threads = threads_l2;
case 0x4a: if (threads > 2 && family == 6)
case 0x4d: switch (model)
case 0x5a: {
case 0x5d: case 0x37:
/* Silvermont has L2 cache shared by 2 cores. */ case 0x4a:
threads = 2; case 0x4d:
break; case 0x5a:
default: case 0x5d:
break; /* Silvermont has L2 cache shared by 2 cores. */
threads = 2;
break;
default:
break;
}
} }
} }
else if (threads_l3)
threads = threads_l3;
} }
else else
{ {
@ -604,8 +682,12 @@ intel_bug_no_cache_info:
} }
/* Account for non-inclusive L2 and L3 caches. */ /* Account for non-inclusive L2 and L3 caches. */
if (level == 3 && !inclusive_cache) if (!inclusive_cache)
shared += core; {
if (threads_l2 > 0)
core /= threads_l2;
shared += core;
}
} }
/* This spells out "AuthenticAMD". */ /* This spells out "AuthenticAMD". */
else if (is_amd) else if (is_amd)