Subject: Symbol lookups.
To: None <tech-userlevel@netbsd.org>
From: None <ragge@ludd.luth.se>
List: tech-userlevel
Date: 05/07/2003 23:51:50
I have just added some code to do fast symbol table lookups, and
when testing the ioctl's to retrieve symbols from the kernel I found
that it is 3-5 times faster than doing a lookup in kvm.db.
Example (on a Sparc Classic):
Timing 77520 calls to db...took 42 seconds.
Timing 77520 calls to /dev/ksyms...took 16 seconds.
On an Alpha 433au:
Timing 1083400 calls to db...took 44 seconds.
Timing 1083400 calls to /dev/ksyms...took 8 seconds.
This shows that it is quite a gain in speed on some archs :-)
As a result of this, I think there may be a reason to remove the
kvm database alltogether, especially because it would need a bunch
of extra massage anyway to update it if modules are loaded/unloaded;
and fall back to the old "nlist" way of retreiving kernel symbols
if /dev/ksyms is not in the kernel?
Or some other strategy? I want comments here.
Attached here is a small test program that shows the lookup time
difference.
Use it by just compiling:
# cc -o foo foo.c
# nm -p -g /netbsd | awk '{print $3}' > ksfil
# ./foo < ksfil
-- Ragge
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/ksyms.h>
#include <sys/time.h>
#include <stdio.h>
#include <strings.h>
#include <err.h>
#include <db.h>
#include <paths.h>
#include <fcntl.h>
#include <unistd.h>
#define NITER 100
char *syms[50000];
int
main(int argc, char *argv[])
{
struct ksyms_gsymbol kg;
DB *db;
DBT rec;
struct timeval tv, tv2, tv3, tv4;
long val;
int nstr, fd, i, j, rv;
char *str;
char buf[80];
/* Read in symbol strings */
nstr = 0;
while ((str = gets(&buf[1])) != NULL) {
buf[0] = '_';
syms[nstr++] = strdup(buf);
}
if ((fd = open("/dev/ksyms", O_RDONLY)) < 0)
err(1, "open /dev/ksyms");
if ((db = dbopen(_PATH_KVMDB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
err(1, "dbopen");
printf("Timing %d calls to db...", nstr * NITER);
gettimeofday(&tv, NULL);
for (j = 0; j < NITER; j++) {
for (i = 0; i < nstr; i++) {
rec.data = syms[i];
rec.size = strlen(syms[i]);
if ((rv = (db->get)(db, (DBT *)&rec, (DBT *)&rec, 0))) {
if (rv < 0)
warn("no sym %s", syms[i]);
else
warnx("cannot find %s", syms[i]);
}
}
}
gettimeofday(&tv2, NULL);
printf("took %ld seconds.\n\n", tv2.tv_sec - tv.tv_sec);
printf("Timing %d calls to /dev/ksyms...", nstr * NITER);
gettimeofday(&tv3, NULL);
for (j = 0; j < NITER; j++) {
for (i = 0; i < nstr; i++) {
kg.kg_name = &syms[i][1];
kg.kg_value = &val;
if (ioctl(fd, KIOCGVALUE, &kg) < 0)
warnx("cannot get %s", syms[i]);
}
}
gettimeofday(&tv4, NULL);
printf("took %ld seconds.\n\n", tv4.tv_sec - tv3.tv_sec);
close(fd);
(db->close)(db);
}