This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
PATCH: PR libc/12587: sysconf(_SC_*CACHE) returns 0 for all cacheson some CPUs
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Cc: Ulrich Drepper <drepper at gmail dot com>
- Date: Mon, 21 Mar 2011 21:14:32 -0700
- Subject: PATCH: PR libc/12587: sysconf(_SC_*CACHE) returns 0 for all cacheson some CPUs
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
Hi,
Fix for
http://sourceware.org/bugzilla/show_bug.cgi?id=12587
doesn't work since the loop may not terminate. It goes into an infinite
loop on Xeon X5670. Also we should use __cpuid_count like the rest of
sysdeps/x86_64/cacheinfo.c. With this patch, I got
LEVEL1_ICACHE_SIZE 32768
LEVEL1_ICACHE_ASSOC 4
LEVEL1_ICACHE_LINESIZE 64
LEVEL1_DCACHE_SIZE 32768
LEVEL1_DCACHE_ASSOC 8
LEVEL1_DCACHE_LINESIZE 64
LEVEL2_CACHE_SIZE 262144
LEVEL2_CACHE_ASSOC 8
LEVEL2_CACHE_LINESIZE 64
LEVEL3_CACHE_SIZE 12582912
LEVEL3_CACHE_ASSOC 16
LEVEL3_CACHE_LINESIZE 64
LEVEL4_CACHE_SIZE 0
LEVEL4_CACHE_ASSOC 0
LEVEL4_CACHE_LINESIZE 0
H.J.
--
2011-03-22 H.J. Lu <hongjiu.lu@intel.com>
PR libc/12587
* sysdeps/unix/sysv/linux/i386/sysconf.c: Include <cpuid.h>.
(__cpuid_count): New.
(intel_check_word): Use __cpuid_count and increment round.
* sysdeps/x86_64/cacheinfo.c (intel_check_word): Likewise.
diff --git a/sysdeps/unix/sysv/linux/i386/sysconf.c b/sysdeps/unix/sysv/linux/i386/sysconf.c
index 4ea1a2b..540bdd5 100644
--- a/sysdeps/unix/sysv/linux/i386/sysconf.c
+++ b/sysdeps/unix/sysv/linux/i386/sysconf.c
@@ -22,6 +22,26 @@
#include <stdlib.h>
#include <unistd.h>
#include <hp-timing.h>
+#include <cpuid.h>
+
+#ifndef __cpuid_count
+/* FIXME: Provide __cpuid_count if it isn't defined. Copied from gcc
+ 4.4.0. Remove this if gcc 4.4 is the minimum requirement. */
+# if defined(__i386__) && defined(__PIC__)
+/* %ebx may be the PIC register. */
+# define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("xchg{l}\t{%%}ebx, %1\n\t" \
+ "cpuid\n\t" \
+ "xchg{l}\t{%%}ebx, %1\n\t" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+# else
+# define __cpuid_count(level, count, a, b, c, d) \
+ __asm__ ("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level), "2" (count))
+# endif
+#endif
static long int linux_sysconf (int name);
@@ -198,9 +218,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
unsigned int round = 0;
while (1)
{
- asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
- : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
- : "0" (4), "2" (round));
+ __cpuid_count (4, round++, eax, ebx, ecx, edx);
enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
if (type == null)
diff --git a/sysdeps/x86_64/cacheinfo.c b/sysdeps/x86_64/cacheinfo.c
index fdd6427..2d33508 100644
--- a/sysdeps/x86_64/cacheinfo.c
+++ b/sysdeps/x86_64/cacheinfo.c
@@ -193,9 +193,7 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
unsigned int round = 0;
while (1)
{
- asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
- : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
- : "0" (4), "2" (round));
+ __cpuid_count (4, round++, eax, ebx, ecx, edx);
enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
if (type == null)