Subject: Fully sysctl-aware ld.elf_so, second try
To: None <tech-userlevel@netbsd.org>
From: Quentin Garnier <cube@NetBSD.org>
List: tech-userlevel
Date: 06/30/2004 15:57:03
This is a multi-part message in MIME format.
--Multipart=_Wed__30_Jun_2004_15_57_03_+0200_ijuKTQp1FOZHi.EG
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
I've been doing a lot of tests with the attached patch, including
several full builds of NetBSD, and the conclusion is that there is no
real speed difference between the old ld.elf_so and the patched one.
The difference between the two always measures in less than 1%, and the
general trend is that the new one wins in the situations where sysctl()
is not used, which means when /etc/ld.so.conf is empty (all archs but
i386 and sparc64), and when the loaded binary is not linked against any
of the libs listed in ld.so.conf (all non-libm binaries in i386).
When sysctl() is used, the patched one tends to be slightly slower, but
it's barely noticeable. After 100000 execs in a row (all of them
inducing sysctl() calls), the patched might even get faster from time to
time, but in average is slower by about 0.20%. My test system is a
i386, so this might be different on archs where making a syscall costs
more.
The resulting binary is slightly smaller (about 600 bytes according to
size(1)).
I plan to commit the change in the next few days, unless points against
it are raised.
Quentin Garnier.
--Multipart=_Wed__30_Jun_2004_15_57_03_+0200_ijuKTQp1FOZHi.EG
Content-Type: text/plain;
name="ld.elf_so.diff"
Content-Disposition: attachment;
filename="ld.elf_so.diff"
Content-Transfer-Encoding: 7bit
Index: load.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/load.c,v
retrieving revision 1.27
diff -u -r1.27 load.c
--- load.c 25 Nov 2003 14:36:49 -0000 1.27
+++ load.c 29 Jun 2004 07:35:01 -0000
@@ -179,6 +179,7 @@
bool got = false;
union {
int i;
+ u_quad_t q;
char s[16];
} val;
@@ -187,22 +188,24 @@
if (strcmp(x->name, name) != 0)
continue;
- i = sizeof(val);
-
- if (sysctl(x->ctl, x->ctlmax, &val, &i, NULL, 0) == -1) {
- xwarnx(_PATH_LD_HINTS ": unknown sysctl for %s", name);
+ j = sizeof(val);
+ if ((i = _rtld_sysctl(x->ctlname, &val, &j)) == -1) {
+ xwarnx(_PATH_LD_HINTS ": invalid/unknown sysctl for %s (%d)",
+ name, errno);
break;
}
- switch (x->ctltype[x->ctlmax - 1]) {
+ switch (i) {
+ case CTLTYPE_QUAD:
+ xsnprintf(val.s, sizeof(val.s), "%" PRIu64, val.q);
+ break;
case CTLTYPE_INT:
xsnprintf(val.s, sizeof(val.s), "%d", val.i);
break;
case CTLTYPE_STRING:
break;
default:
- xwarnx("unsupported sysctl type %d",
- x->ctltype[x->ctlmax - 1]);
+ xwarnx("unsupported sysctl type %d", (int)i);
break;
}
Index: paths.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/paths.c,v
retrieving revision 1.30
diff -u -r1.30 paths.c
--- paths.c 16 Mar 2004 05:25:12 -0000 1.30
+++ paths.c 29 Jun 2004 07:35:01 -0000
@@ -216,49 +216,6 @@
}
}
-struct list {
- const struct ctlname *ctl;
- int numentries;
-};
-
-#ifdef CTL_MACHDEP_NAMES
-static const struct ctlname ctl_machdep[] = CTL_MACHDEP_NAMES;
-#endif
-static const struct ctlname ctl_toplvl[] = CTL_NAMES;
-
-const struct list toplevel[] = {
- { 0, 0 },
- { ctl_toplvl, CTL_MAXID },
- { 0, -1 },
-};
-
-const struct list secondlevel[] = {
- { 0, 0 }, /* CTL_UNSPEC */
- { 0, KERN_MAXID }, /* CTL_KERN */
- { 0, VM_MAXID }, /* CTL_VM */
- { 0, VFS_MAXID }, /* CTL_VFS */
- { 0, NET_MAXID }, /* CTL_NET */
- { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
- { 0, HW_MAXID }, /* CTL_HW */
-#ifdef CTL_MACHDEP_NAMES
- { ctl_machdep, CPU_MAXID }, /* CTL_MACHDEP */
-#else
- { 0, 0 }, /* CTL_MACHDEP */
-#endif
- { 0, USER_MAXID }, /* CTL_USER_NAMES */
- { 0, DDBCTL_MAXID }, /* CTL_DDB_NAMES */
- { 0, 2 }, /* dummy name */
- { 0, -1 },
-};
-
-const struct list *lists[] = {
- toplevel,
- secondlevel,
- 0
-};
-
-#define CTL_MACHDEP_SIZE (sizeof(ctl_machdep) / sizeof(ctl_machdep[0]))
-
/*
* Process library mappings of the form:
* <library_name> <machdep_variable> <value,...:library_name,...> ...
@@ -268,7 +225,7 @@
{
Library_Xform *hwptr = NULL;
const char *ptr, *key, *ekey, *lib, *elib, *l;
- int i, j, k;
+ int i, j;
dbg((" processing mapping \"%.*s\"", (int)(ep - bp), bp));
@@ -290,37 +247,7 @@
dbg((" sysctl \"%.*s\"", (int)(bp - ptr), ptr));
- for (i = 0; (l = getstr(&ptr, bp, ".")) != NULL; i++, ptr++) {
-
- if (lists[i] == NULL || i >= RTLD_MAX_CTL) {
- xwarnx("sysctl nesting too deep");
- goto cleanup;
- }
-
- for (j = 1; lists[i][j].numentries != -1; j++) {
-
- if (lists[i][j].ctl == NULL)
- continue;
-
- for (k = 1; k < lists[i][j].numentries; k++)
- if (matchstr(lists[i][j].ctl[k].ctl_name, l,
- ptr))
- break;
-
- if (lists[i][j].numentries == -1) {
- xwarnx("unknown sysctl variable name `%.*s'",
- (int)(ptr - l), l);
- goto cleanup;
- }
-
- hwptr->ctl[hwptr->ctlmax] = k;
- hwptr->ctltype[hwptr->ctlmax++] =
- lists[i][j].ctl[k].ctl_type;
- }
- }
-
- for (i = 0; i < hwptr->ctlmax; i++)
- dbg((" sysctl %d, %d", hwptr->ctl[i], hwptr->ctltype[i]));
+ hwptr->ctlname = exstrdup(ptr, bp);
for (i = 0; bp++, (ptr = getword(&bp, ep, WS)) != NULL;) {
dbg((" ptr = %.*s", (int)(bp - ptr), ptr));
@@ -456,3 +383,69 @@
(void)munmap(buf, sz);
}
+
+/* Basic name -> sysctl MIB translation */
+int
+_rtld_sysctl(const char *name, void *oldp, size_t *oldlen)
+{
+ const char *node, *ep;
+ struct sysctlnode query, *result, *newresult;
+ int mib[CTL_MAXNAME], i, r;
+ size_t res_size, n;
+ u_int miblen = 0;
+
+ /* Start with 16 entries, will grow it up as needed. */
+ res_size = 16 * sizeof(struct sysctlnode);
+ result = (struct sysctlnode *)malloc(res_size);
+ if (result == NULL)
+ return (-1);
+
+ ep = name + strlen(name);
+ do {
+ while (*name == '/' || *name == '.')
+ name++;
+ if (name >= ep)
+ break;
+
+ mib[miblen] = CTL_QUERY;
+ memset(&query, 0, sizeof(query));
+ query.sysctl_flags = SYSCTL_VERSION;
+
+ if (sysctl(mib, miblen+1, result, &res_size, &query,
+ sizeof(query)) == -1) {
+ if (errno != ENOMEM)
+ goto bad;
+ /* Grow up result */
+ newresult = (struct sysctlnode *)realloc(result, res_size);
+ if (newresult == NULL)
+ goto bad;
+ result = newresult;
+ if (sysctl(mib, miblen+1, result, &res_size, &query,
+ sizeof(query)) == -1)
+ goto bad;
+ }
+ n = res_size / sizeof(struct sysctlnode);
+
+ node = getstr(&name, ep, "./");
+
+ for (i = 0; i < n; i++)
+ if (matchstr(result[i].sysctl_name, node, name)) {
+ mib[miblen] = result[i].sysctl_num;
+ miblen++;
+ break;
+ }
+ } while (name < ep && miblen <= CTL_MAXNAME);
+
+ if (name < ep)
+ goto bad;
+ r = SYSCTL_TYPE(result[i].sysctl_flags);
+
+ free(result);
+ if (sysctl(mib, miblen, oldp, oldlen, NULL, 0) == -1)
+ return (-1);
+ return r;
+
+bad:
+ free(result);
+ return (-1);
+}
Index: rtld.h
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/rtld.h,v
retrieving revision 1.70
diff -u -r1.70 rtld.h
--- rtld.h 12 Aug 2003 09:18:49 -0000 1.70
+++ rtld.h 29 Jun 2004 07:35:01 -0000
@@ -97,9 +97,7 @@
typedef struct _rtld_library_xform_t {
struct _rtld_library_xform_t *next;
char *name;
- int ctl[RTLD_MAX_CTL];
- int ctltype[RTLD_MAX_CTL];
- int ctlmax;
+ const char *ctlname;
struct {
char *value;
char *library[RTLD_MAX_LIBRARY];
@@ -243,6 +241,7 @@
/* path.c */
void _rtld_add_paths(Search_Path **, const char *);
void _rtld_process_hints(Search_Path **, Library_Xform **, const char *);
+int _rtld_sysctl(const char *, void *, size_t *);
/* reloc.c */
int _rtld_do_copy_relocations(const Obj_Entry *);
--Multipart=_Wed__30_Jun_2004_15_57_03_+0200_ijuKTQp1FOZHi.EG--