This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
alpha cache detection
- From: Richard Henderson <rth at twiddle dot net>
- To: libc-alpha at gcc dot gnu dot org
- Date: Thu, 6 May 2004 15:11:41 -0700
- Subject: alpha cache detection
Kernels 2.6.4+ add a couple of AT values for cache parameters
that we cannot determine from userspace.
Is there a better way to read the AT values from libc startup
instead of ld.so startup such that we don't have to export
symbols like this?
r~
* elf/elf.h (AT_L1I_CACHESHAPE, AT_L1D_CACHESHAPE,
AT_L2_CACHESHAPE, AT_L3_CACHESHAPE): New.
* sysdeps/unix/sysv/linux/alpha/Versions: Export
__libc_alpha_cache_shape as a private symbol.
* sysdeps/unix/sysv/linux/alpha/dl-sysdep.c: New file.
* sysdeps/unix/sysv/linux/alpha/sysconf.c: New file.
Index: elf/elf.h
===================================================================
RCS file: /cvs/glibc/libc/elf/elf.h,v
retrieving revision 1.139
diff -c -p -d -r1.139 elf.h
*** elf/elf.h 1 Apr 2004 18:48:40 -0000 1.139
--- elf/elf.h 6 May 2004 22:04:46 -0000
*************** typedef struct
*** 963,968 ****
--- 963,974 ----
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
+ /* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains
+ log2 of line size; mask those to get cache size. */
+ #define AT_L1I_CACHESHAPE 34
+ #define AT_L1D_CACHESHAPE 35
+ #define AT_L2_CACHESHAPE 36
+ #define AT_L3_CACHESHAPE 37
/* Note section contents. Each entry in the note section begins with
a header of a fixed form. */
Index: sysdeps/unix/sysv/linux/alpha/Versions
===================================================================
RCS file: /cvs/glibc/libc/sysdeps/unix/sysv/linux/alpha/Versions,v
retrieving revision 1.11
diff -c -p -d -r1.11 Versions
*** sysdeps/unix/sysv/linux/alpha/Versions 28 Aug 2002 23:55:01 -0000 1.11
--- sysdeps/unix/sysv/linux/alpha/Versions 6 May 2004 22:04:51 -0000
*************** libc {
*** 73,78 ****
--- 73,86 ----
#errlist-compat 132
_sys_errlist; sys_errlist; _sys_nerr; sys_nerr;
}
+ GLIBC_PRIVATE {
+ __libc_alpha_cache_shape;
+ }
+ }
+ ld {
+ GLIBC_PRIVATE {
+ __libc_alpha_cache_shape;
+ }
}
librt {
GLIBC_2.3 {
Index: sysdeps/unix/sysv/linux/alpha/dl-sysdep.c
===================================================================
RCS file: sysdeps/unix/sysv/linux/alpha/dl-sysdep.c
diff -N sysdeps/unix/sysv/linux/alpha/dl-sysdep.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- sysdeps/unix/sysv/linux/alpha/dl-sysdep.c 6 May 2004 22:04:51 -0000
***************
*** 0 ****
--- 1,60 ----
+ /* Operating system support for run-time dynamic linker. Linux/PPC version.
+ Copyright (C) 1997, 1998, 2001, 2003 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+
+ #include "config.h"
+ #include "kernel-features.h"
+ #include <ldsodefs.h>
+
+ extern long __libc_alpha_cache_shape[4];
+ weak_extern (__libc_alpha_cache_shape);
+
+
+ /* Scan the Aux Vector for the cache shape entries. */
+ #define DL_PLATFORM_AUXV \
+ case AT_L1I_CACHESHAPE: \
+ { \
+ long *cls = __libc_alpha_cache_shape; \
+ if (cls != NULL) \
+ cls[0] = av->a_un.a_val; \
+ break; \
+ } \
+ case AT_L1D_CACHESHAPE: \
+ { \
+ long *cls = __libc_alpha_cache_shape; \
+ if (cls != NULL) \
+ cls[1] = av->a_un.a_val; \
+ break; \
+ } \
+ case AT_L2_CACHESHAPE: \
+ { \
+ long *cls = __libc_alpha_cache_shape; \
+ if (cls != NULL) \
+ cls[2] = av->a_un.a_val; \
+ break; \
+ } \
+ case AT_L3_CACHESHAPE: \
+ { \
+ long *cls = __libc_alpha_cache_shape; \
+ if (cls != NULL) \
+ cls[3] = av->a_un.a_val; \
+ break; \
+ }
+
+ #include <sysdeps/unix/sysv/linux/dl-sysdep.c>
Index: sysdeps/unix/sysv/linux/alpha/sysconf.c
===================================================================
RCS file: sysdeps/unix/sysv/linux/alpha/sysconf.c
diff -N sysdeps/unix/sysv/linux/alpha/sysconf.c
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- sysdeps/unix/sysv/linux/alpha/sysconf.c 6 May 2004 22:04:51 -0000
***************
*** 0 ****
--- 1,152 ----
+ /* Copyright (C) 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+ #include <assert.h>
+ #include <stdbool.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+
+
+ static long int linux_sysconf (int name);
+
+ #define CSHAPE(totalsize, linesize, assoc) \
+ ((totalsize & ~0xff) | (linesize << 4) | assoc)
+
+ long __libc_alpha_cache_shape[4] = { -2, -2, -2, -2 };
+
+ static inline unsigned long
+ implver (void)
+ {
+ unsigned long i;
+ #if __GNUC_PREREQ(3,3)
+ i = __builtin_alpha_implver ();
+ #else
+ asm ("implver %0" : "=r" (i));
+ #endif
+ return i;
+ }
+
+ static inline unsigned long
+ amask (unsigned long x)
+ {
+ unsigned long r;
+ #if __GNUC_PREREQ(3,3)
+ r = __builtin_alpha_amask (x);
+ #else
+ asm ("amask %1,%0" : "=r"(r) : "Ir"(x));
+ #endif
+ return r;
+ }
+
+ /* Get the value of the system variable NAME. */
+ long int
+ __sysconf (int name)
+ {
+ long shape, index;
+
+ /* We only handle the cache information here (for now). */
+ if (name < _SC_LEVEL1_ICACHE_SIZE || name > _SC_LEVEL4_CACHE_LINESIZE)
+ return linux_sysconf (name);
+
+ /* No Alpha has L4 caches. */
+ if (name >= _SC_LEVEL4_CACHE_SIZE)
+ return -1;
+
+ index = (name - _SC_LEVEL1_ICACHE_SIZE) / 3;
+ shape = __libc_alpha_cache_shape[index];
+ if (shape == -2)
+ {
+ long shape_l1i, shape_l1d, shape_l2, shape_l3 = -1;
+
+ /* ??? In the cases below for which we do not know L1 cache sizes,
+ we could do timings to measure sizes. But for the Bcache, it's
+ generally big enough that (without additional help) TLB effects
+ get in the way. We'd either need to be able to allocate large
+ pages or have the kernel do the timings from KSEG. Fortunately,
+ kernels beginning with 2.6.5 will pass us this info in auxvec. */
+
+ switch (implver())
+ {
+ case 0: /* EV4 */
+ /* EV4/LCA45 had 8k L1 caches; EV45 had 16k L1 caches. */
+ /* EV4/EV45 had 128k to 16M 32-byte direct Bcache. LCA45
+ had 64k to 8M 8-byte direct Bcache. Can't tell. */
+ shape_l1i = shape_l1d = shape_l2 = CSHAPE (0, 5, 1);
+ break;
+
+ case 1: /* EV5 */
+ if (amask (1 << 8))
+ {
+ /* MAX insns not present; either EV5 or EV56. */
+ shape_l1i = shape_l1d = CSHAPE(8*1024, 5, 1);
+ /* ??? L2 and L3 *can* be configured as 32-byte line. */
+ shape_l2 = CSHAPE (96*1024, 6, 3);
+ /* EV5/EV56 has 1M to 16M Bcache. */
+ shape_l3 = CSHAPE (0, 6, 1);
+ }
+ else
+ {
+ /* MAX insns present; either PCA56 or PCA57. */
+ /* PCA56 had 16k 64-byte cache; PCA57 had 32k Icache. */
+ /* PCA56 had 8k 64-byte cache; PCA57 had 16k Dcache. */
+ /* PCA5[67] had 512k to 4M Bcache. */
+ shape_l1i = shape_l1d = shape_l2 = CSHAPE (0, 6, 1);
+ }
+ break;
+
+ case 2: /* EV6 */
+ shape_l1i = shape_l1d = CSHAPE(64*1024, 6, 2);
+ /* EV6/EV67/EV68* had 1M to 16M Bcache. */
+ shape_l2 = CSHAPE (0, 6, 1);
+ break;
+
+ case 3: /* EV7 */
+ shape_l1i = shape_l1d = CSHAPE(64*1024, 6, 2);
+ shape_l2 = CSHAPE(7*1024*1024/4, 6, 7);
+ break;
+
+ default:
+ shape_l1i = shape_l1d = shape_l2 = 0;
+ break;
+ }
+
+ __libc_alpha_cache_shape[0] = shape_l1i;
+ __libc_alpha_cache_shape[1] = shape_l1d;
+ __libc_alpha_cache_shape[2] = shape_l2;
+ __libc_alpha_cache_shape[3] = shape_l3;
+ shape = __libc_alpha_cache_shape[index];
+ }
+
+ if (shape <= 0)
+ return shape;
+
+ switch (name % 3)
+ {
+ case 0: /* total size */
+ return shape & -0x100;
+ case 1: /* associativity */
+ return shape & 0xf;
+ default: /* line size */
+ return 1L << ((shape >> 4) & 0xf);
+ }
+ }
+
+ /* Now the generic Linux version. */
+ #undef __sysconf
+ #define __sysconf static linux_sysconf
+ #include "../sysconf.c"