Commit 8af27e1d authored by Eric Dumazet's avatar Eric Dumazet Committed by Michal Marek

fixdep: use hash table instead of a single array

I noticed fixdep uses ~2% of cpu time in kernel build, in function
use_config()

fixdep spends a lot of cpu cycles in linear searches in its internal
string array. With about 400 stored strings per dep file, this begins to
be noticeable.

Convert fixdep to use a hash table.

kbuild results on my x86_64 allmodconfig

Before patch :

real	10m30.414s
user	61m51.456s
sys	8m28.200s

real	10m12.334s
user	61m50.236s
sys	8m30.448s

real	10m42.947s
user	61m50.028s
sys	8m32.380s

After:

real	10m8.180s
user	61m22.506s
sys	8m32.384s

real	10m35.039s
user	61m21.654s
sys	8m32.212s

real	10m14.487s
user	61m23.498s
sys	8m32.312s
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarMichal Marek <mmarek@suse.cz>
parent d63f6d1b
...@@ -138,38 +138,36 @@ static void print_cmdline(void) ...@@ -138,38 +138,36 @@ static void print_cmdline(void)
printf("cmd_%s := %s\n\n", target, cmdline); printf("cmd_%s := %s\n\n", target, cmdline);
} }
char * str_config = NULL; struct item {
int size_config = 0; struct item *next;
int len_config = 0; unsigned int len;
unsigned int hash;
char name[0];
};
/* #define HASHSZ 256
* Grow the configuration string to a desired length. static struct item *hashtab[HASHSZ];
* Usually the first growth is plenty.
*/
static void grow_config(int len)
{
while (len_config + len > size_config) {
if (size_config == 0)
size_config = 2048;
str_config = realloc(str_config, size_config *= 2);
if (str_config == NULL)
{ perror("fixdep:malloc"); exit(1); }
}
}
static unsigned int strhash(const char *str, unsigned int sz)
{
/* fnv32 hash */
unsigned int i, hash = 2166136261U;
for (i = 0; i < sz; i++)
hash = (hash ^ str[i]) * 0x01000193;
return hash;
}
/* /*
* Lookup a value in the configuration string. * Lookup a value in the configuration string.
*/ */
static int is_defined_config(const char * name, int len) static int is_defined_config(const char *name, int len, unsigned int hash)
{ {
const char * pconfig; struct item *aux;
const char * plast = str_config + len_config - len;
for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) { for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
if (pconfig[ -1] == '\n' if (aux->hash == hash && aux->len == len &&
&& pconfig[len] == '\n' memcmp(aux->name, name, len) == 0)
&& !memcmp(pconfig, name, len))
return 1; return 1;
} }
return 0; return 0;
...@@ -178,13 +176,19 @@ static int is_defined_config(const char * name, int len) ...@@ -178,13 +176,19 @@ static int is_defined_config(const char * name, int len)
/* /*
* Add a new value to the configuration string. * Add a new value to the configuration string.
*/ */
static void define_config(const char * name, int len) static void define_config(const char *name, int len, unsigned int hash)
{ {
grow_config(len + 1); struct item *aux = malloc(sizeof(*aux) + len);
memcpy(str_config+len_config, name, len); if (!aux) {
len_config += len; perror("fixdep:malloc");
str_config[len_config++] = '\n'; exit(1);
}
memcpy(aux->name, name, len);
aux->len = len;
aux->hash = hash;
aux->next = hashtab[hash % HASHSZ];
hashtab[hash % HASHSZ] = aux;
} }
/* /*
...@@ -192,40 +196,49 @@ static void define_config(const char * name, int len) ...@@ -192,40 +196,49 @@ static void define_config(const char * name, int len)
*/ */
static void clear_config(void) static void clear_config(void)
{ {
len_config = 0; struct item *aux, *next;
define_config("", 0); unsigned int i;
for (i = 0; i < HASHSZ; i++) {
for (aux = hashtab[i]; aux; aux = next) {
next = aux->next;
free(aux);
}
hashtab[i] = NULL;
}
} }
/* /*
* Record the use of a CONFIG_* word. * Record the use of a CONFIG_* word.
*/ */
static void use_config(char *m, int slen) static void use_config(const char *m, int slen)
{ {
char s[PATH_MAX]; unsigned int hash = strhash(m, slen);
char *p; int c, i;
if (is_defined_config(m, slen)) if (is_defined_config(m, slen, hash))
return; return;
define_config(m, slen); define_config(m, slen, hash);
memcpy(s, m, slen); s[slen] = 0;
for (p = s; p < s + slen; p++) { printf(" $(wildcard include/config/");
if (*p == '_') for (i = 0; i < slen; i++) {
*p = '/'; c = m[i];
if (c == '_')
c = '/';
else else
*p = tolower((int)*p); c = tolower(c);
putchar(c);
} }
printf(" $(wildcard include/config/%s.h) \\\n", s); printf(".h) \\\n");
} }
static void parse_config_file(char *map, size_t len) static void parse_config_file(const char *map, size_t len)
{ {
int *end = (int *) (map + len); const int *end = (const int *) (map + len);
/* start at +1, so that p can never be < map */ /* start at +1, so that p can never be < map */
int *m = (int *) map + 1; const int *m = (const int *) map + 1;
char *p, *q; const char *p, *q;
for (; m < end; m++) { for (; m < end; m++) {
if (*m == INT_CONF) { p = (char *) m ; goto conf; } if (*m == INT_CONF) { p = (char *) m ; goto conf; }
...@@ -265,7 +278,7 @@ static int strrcmp(char *s, char *sub) ...@@ -265,7 +278,7 @@ static int strrcmp(char *s, char *sub)
return memcmp(s + slen - sublen, sub, sublen); return memcmp(s + slen - sublen, sub, sublen);
} }
static void do_config_file(char *filename) static void do_config_file(const char *filename)
{ {
struct stat st; struct stat st;
int fd; int fd;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment