[2/2] Initialize tunable list with the GLIBC_TUNABLES environment variable
Commit Message
Read tunables values from the users using the GLIBC_TUNABLES
environment variable. The value of this variable is a colon-separated
list of name=value pairs. So a typical string would look like this:
GLIBC_TUNABLES=glibc.malloc.mmap_threshold=2048:glibc.malloc.trim_threshold=1024
* elf/dl-tunables.c: Include string.h.
(parse_tunables): New function.
(GLIBC_TUNABLES): New macro.
(__tunables_init): Use it.
---
elf/dl-tunables.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
Comments
On Sat, Jul 2, 2016 at 10:12 AM, Siddhesh Poyarekar
<siddhesh@sourceware.org> wrote:
> Read tunables values from the users using the GLIBC_TUNABLES
> environment variable. The value of this variable is a colon-separated
> list of name=value pairs. So a typical string would look like this:
>
> GLIBC_TUNABLES=glibc.malloc.mmap_threshold=2048:glibc.malloc.trim_threshold=1024
>
> * elf/dl-tunables.c: Include string.h.
> (parse_tunables): New function.
> (GLIBC_TUNABLES): New macro.
> (__tunables_init): Use it.
> ---
> elf/dl-tunables.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 69 insertions(+)
>
> diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
> index 8a26dfc..04d1d52 100644
> --- a/elf/dl-tunables.c
> +++ b/elf/dl-tunables.c
> @@ -22,10 +22,13 @@
> #include <stdbool.h>
> #include <unistd.h>
> #include <stdlib.h>
> +#include <string.h>
>
> #define TUNABLES_INTERNAL 1
> #include "dl-tunables.h"
>
> +#define GLIBC_TUNABLES "GLIBC_TUNABLES"
> +
> /* Compare environment names, bounded by the name hardcoded in glibc. */
> static bool
> is_name (const char *orig, const char *envname)
> @@ -104,6 +107,66 @@ tunable_initialize (tunable_t *cur)
> }
> }
>
> +static void
> +parse_tunables (char *tunestr)
> +{
> + if (tunestr == NULL || *tunestr == '\0')
> + return;
> +
> + char *p = tunestr;
> +
> + while (true)
> + {
> + char *name = p;
> + size_t len = 0;
> +
> + /* First, find where the name ends. */
> + while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
> + len++;
> +
> + /* If we reach the end of the string before getting a valid name-value
> + pair, bail out. */
> + if (p[len] == '\0')
> + return;
> +
> + /* We did not find a valid name-value pair before encountering the
> + colon. */
> + if (p[len]== ':')
> + {
> + p += len + 1;
> + continue;
> + }
> +
> + p += len + 1;
> +
> + char *value = p;
> + len = 0;
> +
> + while (p[len] != ':' && p[len] != '\0')
> + len++;
> +
> + char end = p[len];
> + p[len] = '\0';
> +
> + /* Add the tunable if it exists. */
> + for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
> + {
> + if (is_name (tunable_list[i].name, name))
Can you add the length of name to tunable_list field and check
if the length matches first?
> + {
> + /* Tunable values take precedence over the env_alias. */
> + tunable_list[i].strval = value;
> + tunable_initialize (&tunable_list[i]);
> + break;
> + }
> + }
> +
> + if (end == ':')
> + p += len + 1;
> + else
> + return;
> + }
> +}
> +
> /* Initialize the tunables list from the environment. For now we only use the
> ENV_ALIAS to find values. Later we will also use the tunable names to find
> values. */
> @@ -116,6 +179,12 @@ __tunables_init (char **envp)
>
> while (get_next_env (&envp, &envname, &len, &envval))
> {
> + if (is_name (GLIBC_TUNABLES, envname))
> + {
> + parse_tunables (strdup (envval));
> + continue;
> + }
> +
> for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
> {
> tunable_t *cur = &tunable_list[i];
> --
> 2.5.5
>
On Sat, Jul 2, 2016 at 10:12 AM, Siddhesh Poyarekar
<siddhesh@sourceware.org> wrote:
> Read tunables values from the users using the GLIBC_TUNABLES
> environment variable. The value of this variable is a colon-separated
> list of name=value pairs. So a typical string would look like this:
>
> GLIBC_TUNABLES=glibc.malloc.mmap_threshold=2048:glibc.malloc.trim_threshold=1024
>
> * elf/dl-tunables.c: Include string.h.
> (parse_tunables): New function.
> (GLIBC_TUNABLES): New macro.
> (__tunables_init): Use it.
I didn't see any tests for GLIBC_TUNABLES=glibc.malloc and I don't think
it works for static executable:
gdb) bt
#0 __tunable_set_val (id=glibc_malloc_check, valp=0x6b67d0 <check_action>,
callback=0x414460 <_dl_tunable_set_mallopt_check>) at dl-tunables.c:221
#1 0x0000000000413cda in ptmalloc_init () at arena.c:299
#2 0x0000000000414dfe in ptmalloc_init () at hooks.c:29
#3 malloc_hook_ini (sz=66, caller=<optimized out>) at hooks.c:31
#4 0x0000000000418b2a in __strdup (
s=0x7fffffffef66
"glibc.malloc.mmap_threshold=2048:glibc.malloc.trim_threshold=1024")
at strdup.c:42
#5 0x0000000000437e01 in __tunables_init (envp=0x7fffffffe088,
envp@entry=0x7fffffffdeb8) at dl-tunables.c:184
#6 0x000000000043908b in __libc_init_first (argc=argc@entry=1,
argv=argv@entry=0x7fffffffdea8, envp=0x7fffffffdeb8)
at ../csu/init-first.c:81
#7 0x00000000004012d5 in generic_start_main (main=0x400550 <main>, argc=1,
argv=argv@entry=0x7fffffffdea8,
init=init@entry=0x401b20 <__libc_csu_init>,
fini=0x401bb0 <__libc_csu_fini>, rtld_fini=0x0, stack_end=0x7fffffffde98)
at ../csu/libc-start.c:225
#8 0x00000000004015c7 in __libc_start_main (main=<optimized out>,
argc=<optimized out>, argv=0x7fffffffdea8,
init=0x401b20 <__libc_csu_init>, fini=0x401bb0 <__libc_csu_fini>,
rtld_fini=<optimized out>, stack_end=0x7fffffffde98)
at ../sysdeps/x86/libc-start.c:38
---Type <return> to continue, or q <return> to quit---
#9 0x0000000000400e1a in _start () at ../sysdeps/x86_64/start.S:120
if (is_name (GLIBC_TUNABLES, envname))
{
parse_tunables (strdup (envval));
^^^^^^^^^ Which calls malloc and
other library functions.
continue;
}
Since tunable code is called very early, it can't use any C library functions.
On Sun, Jul 03, 2016 at 07:38:54AM -0700, H.J. Lu wrote:
> Can you add the length of name to tunable_list field and check
> if the length matches first?
Similar to passing the length in is_name, can we do this as an addon
if we see a significant performance impact?
Siddhesh
On Sun, Jul 03, 2016 at 08:53:12AM -0700, H.J. Lu wrote:
> I didn't see any tests for GLIBC_TUNABLES=glibc.malloc and I don't think
> it works for static executable:
Hmm, right, I need to fix this. I had manually run the
tst-malloc-usable patch with GLIBC_TUNABLES but didn't do it for
static case again. I'll fix this up, write those tests and repost.
Thanks,
Siddhesh
@@ -22,10 +22,13 @@
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
+#include <string.h>
#define TUNABLES_INTERNAL 1
#include "dl-tunables.h"
+#define GLIBC_TUNABLES "GLIBC_TUNABLES"
+
/* Compare environment names, bounded by the name hardcoded in glibc. */
static bool
is_name (const char *orig, const char *envname)
@@ -104,6 +107,66 @@ tunable_initialize (tunable_t *cur)
}
}
+static void
+parse_tunables (char *tunestr)
+{
+ if (tunestr == NULL || *tunestr == '\0')
+ return;
+
+ char *p = tunestr;
+
+ while (true)
+ {
+ char *name = p;
+ size_t len = 0;
+
+ /* First, find where the name ends. */
+ while (p[len] != '=' && p[len] != ':' && p[len] != '\0')
+ len++;
+
+ /* If we reach the end of the string before getting a valid name-value
+ pair, bail out. */
+ if (p[len] == '\0')
+ return;
+
+ /* We did not find a valid name-value pair before encountering the
+ colon. */
+ if (p[len]== ':')
+ {
+ p += len + 1;
+ continue;
+ }
+
+ p += len + 1;
+
+ char *value = p;
+ len = 0;
+
+ while (p[len] != ':' && p[len] != '\0')
+ len++;
+
+ char end = p[len];
+ p[len] = '\0';
+
+ /* Add the tunable if it exists. */
+ for (size_t i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
+ {
+ if (is_name (tunable_list[i].name, name))
+ {
+ /* Tunable values take precedence over the env_alias. */
+ tunable_list[i].strval = value;
+ tunable_initialize (&tunable_list[i]);
+ break;
+ }
+ }
+
+ if (end == ':')
+ p += len + 1;
+ else
+ return;
+ }
+}
+
/* Initialize the tunables list from the environment. For now we only use the
ENV_ALIAS to find values. Later we will also use the tunable names to find
values. */
@@ -116,6 +179,12 @@ __tunables_init (char **envp)
while (get_next_env (&envp, &envname, &len, &envval))
{
+ if (is_name (GLIBC_TUNABLES, envname))
+ {
+ parse_tunables (strdup (envval));
+ continue;
+ }
+
for (int i = 0; i < sizeof (tunable_list) / sizeof (tunable_t); i++)
{
tunable_t *cur = &tunable_list[i];