tunables, aarch64: New tunable to override cpu

Add a new tunable (glibc.tune.cpu) to override CPU identification on
aarch64.  This is useful in two cases: one where it is desirable to
pretend to be another CPU for purposes of testing or because routines
written for that CPU are beneficial for specific workloads and second
where the underlying kernel does not support emulation of MRS to get
the MIDR of the CPU.

	* elf/dl-tunables.h (tunable_is_name): Move from...
	* elf/dl-tunables.c (is_name): ... here.
	(parse_tunables, __tunables_init): Adjust.
	* manual/tunables.texi: Document glibc.tune.cpu.
	* sysdeps/aarch64/dl-tunables.list: New file.
	* sysdeps/unix/sysv/linux/aarch64/cpu-features.c (struct
	cpu_list): New type.
	(cpu_list): New list of CPU names and their MIDR.
	(get_midr_from_mcpu): New function.
	(init_cpu_features): Override MIDR if necessary.
This commit is contained in:
Siddhesh Poyarekar 2017-06-30 22:58:39 +05:30
parent ab85da1530
commit 28cfa3a48e
6 changed files with 106 additions and 26 deletions

View file

@ -1,5 +1,16 @@
2017-06-30 Siddhesh Poyarekar <siddhesh@sourceware.org>
* elf/dl-tunables.h (tunable_is_name): Move from...
* elf/dl-tunables.c (is_name): ... here.
(parse_tunables, __tunables_init): Adjust.
* manual/tunables.texi: Document glibc.tune.cpu.
* sysdeps/aarch64/dl-tunables.list: New file.
* sysdeps/unix/sysv/linux/aarch64/cpu-features.c (struct
cpu_list): New type.
(cpu_list): New list of CPU names and their MIDR.
(get_midr_from_mcpu): New function.
(init_cpu_features): Override MIDR if necessary.
* sysdeps/aarch64/multiarch/ifunc-impl-list.c
(__libc_ifunc_impl_list): Unconditionally select thunderx
routine for testing.

View file

@ -33,22 +33,6 @@
# define GLIBC_TUNABLES "GLIBC_TUNABLES"
#endif
/* Compare environment or tunable names, bounded by the name hardcoded in
glibc. */
static bool
is_name (const char *orig, const char *envname)
{
for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
if (*orig != *envname)
break;
/* The ENVNAME is immediately followed by a value. */
if (*orig == '\0' && *envname == '=')
return true;
else
return false;
}
#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
static char *
tunables_strdup (const char *in)
@ -235,7 +219,7 @@ parse_tunables (char *tunestr, char *valstring)
{
tunable_t *cur = &tunable_list[i];
if (is_name (cur->name, name))
if (tunable_is_name (cur->name, name))
{
/* If we are in a secure context (AT_SECURE) then ignore the tunable
unless it is explicitly marked as secure. Tunable values take
@ -318,7 +302,7 @@ __tunables_init (char **envp)
&prev_envp)) != NULL)
{
#if TUNABLES_FRONTEND == TUNABLES_FRONTEND_valstring
if (is_name (GLIBC_TUNABLES, envname))
if (tunable_is_name (GLIBC_TUNABLES, envname))
{
char *new_env = tunables_strdup (envname);
if (new_env != NULL)
@ -341,7 +325,7 @@ __tunables_init (char **envp)
const char *name = cur->env_alias;
/* We have a match. Initialize and move on to the next line. */
if (is_name (name, envname))
if (tunable_is_name (name, envname))
{
/* For AT_SECURE binaries, we need to check the security settings of
the tunable and decide whether we read the value and also whether
@ -356,7 +340,7 @@ __tunables_init (char **envp)
while (*ep != NULL)
{
if (is_name (name, *ep))
if (tunable_is_name (name, *ep))
{
char **dp = ep;

View file

@ -111,5 +111,22 @@ rtld_hidden_proto (__tunable_get_val)
# define TUNABLES_FRONTEND_valstring 1
/* The default value for TUNABLES_FRONTEND. */
# define TUNABLES_FRONTEND_yes TUNABLES_FRONTEND_valstring
/* Compare two name strings, bounded by the name hardcoded in glibc. */
static inline bool
__always_inline
tunable_is_name (const char *orig, const char *envname)
{
for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
if (*orig != *envname)
break;
/* The ENVNAME is immediately followed by a value. */
if (*orig == '\0' && *envname == '=')
return true;
else
return false;
}
#endif
#endif

View file

@ -231,6 +231,14 @@ the ones in @code{sysdeps/x86/cpu-features.h}.
This tunable is specific to i386 and x86-64.
@end deftp
@deftp Tunable glibc.tune.cpu
The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to
assume that the CPU is @code{xxx} where xxx may have one of these values:
@code{generic}, @code{thunderxt88}.
This tunable is specific to aarch64.
@end deftp
@deftp Tunable glibc.tune.x86_data_cache_size
The @code{glibc.tune.x86_data_cache_size} tunable allows the user to set
data cache size in bytes for use in memory and string routines.

View file

@ -0,0 +1,25 @@
# aarch64 specific tunables.
# Copyright (C) 2017 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, see
# <http://www.gnu.org/licenses/>.
glibc {
tune {
cpu {
type: STRING
}
}
}

View file

@ -20,18 +20,53 @@
#include <sys/auxv.h>
#include <elf/dl-hwcaps.h>
#if HAVE_TUNABLES
struct cpu_list
{
const char *name;
uint64_t midr;
};
static struct cpu_list cpu_list[] = {
{"thunderxt88", 0x430F0A10},
{"generic", 0x0}
};
static uint64_t
get_midr_from_mcpu (const char *mcpu)
{
for (int i = 0; i < sizeof (cpu_list) / sizeof (struct cpu_list); i++)
if (tunable_is_name (mcpu, cpu_list[i].name) == 0)
return cpu_list[i].midr;
return UINT64_MAX;
}
#endif
static inline void
init_cpu_features (struct cpu_features *cpu_features)
{
uint64_t hwcap_mask = GET_HWCAP_MASK();
uint64_t hwcap = GLRO (dl_hwcap) & hwcap_mask;
if (hwcap & HWCAP_CPUID)
register uint64_t midr = UINT64_MAX;
#if HAVE_TUNABLES
/* Get the tunable override. */
const char *mcpu = TUNABLE_GET (glibc, tune, mcpu, const char *, NULL);
if (mcpu != NULL)
midr = get_midr_from_mcpu (mcpu);
#endif
/* If there was no useful tunable override, query the MIDR if the kernel
allows it. */
if (midr == UINT64_MAX)
{
register uint64_t id = 0;
asm volatile ("mrs %0, midr_el1" : "=r"(id));
cpu_features->midr_el1 = id;
if (hwcap & HWCAP_CPUID)
asm volatile ("mrs %0, midr_el1" : "=r"(midr));
else
midr = 0;
}
else
cpu_features->midr_el1 = 0;
cpu_features->midr_el1 = midr;
}