aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/kconfig
diff options
context:
space:
mode:
authorAndi Kleen <andi@firstfloor.org>2010-01-13 11:02:44 -0500
committerMichal Marek <mmarek@suse.cz>2010-02-02 08:33:55 -0500
commite66f25d7d1be19e177cf55126a40799757efae89 (patch)
treec60ae380f0ee00ab56dc821dcff56037980a38fd /scripts/kconfig
parent62718979780720e526a411dc66e810288aaa7bf6 (diff)
Improve kconfig symbol hashing
While looking for something else I noticed that the symbol hash function used by kconfig is quite poor. It doesn't use any of the standard hash techniques but simply adds up the string and then uses power of two masking, which is both known to perform poorly. The current x86 kconfig has over 7000 symbols. When I instrumented it showed that the minimum hash chain length was 16 and a significant number of them was over 30. It didn't help that the hash table size was only 256 buckets. This patch increases the hash table size to a larger prime and switches to a FNV32 hash. I played around with a couple of hash functions, but that one seemed to perform best with reasonable hash table sizes. Increasing the hash table size even further didn't seem like a good idea, because there are a couple of global walks which walk the complete hash table. I also moved the unnamed bucket to 0. It's still the longest of all the buckets (44 entries), but hopefully it's not often hit except for the global walk which doesn't care. The result is a much nicer distribution: (first column bucket length, second number of buckets with that length) 1: 3505 2: 1236 3: 294 4: 52 5: 3 47: 1 <--- this is the unnamed symbols bucket There are still some 5+ buckets, but increasing the hash table even more would be likely not worth it. This also cleans up the code slightly by removing hard coded magic numbers. I didn't notice a big performance difference either way on my Nehalem system, but I presume it'll help somewhat on slower systems. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Michal Marek <mmarek@suse.cz>
Diffstat (limited to 'scripts/kconfig')
-rw-r--r--scripts/kconfig/expr.h5
-rw-r--r--scripts/kconfig/symbol.c29
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped2
-rw-r--r--scripts/kconfig/zconf.y2
4 files changed, 21 insertions, 17 deletions
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 6408fefae083..891cd9ce9ba2 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -86,7 +86,7 @@ struct symbol {
86 struct expr_value rev_dep; 86 struct expr_value rev_dep;
87}; 87};
88 88
89#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) 89#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
90 90
91#define SYMBOL_CONST 0x0001 /* symbol is const */ 91#define SYMBOL_CONST 0x0001 /* symbol is const */
92#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ 92#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
@@ -108,8 +108,7 @@ struct symbol {
108#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ 108#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
109 109
110#define SYMBOL_MAXLENGTH 256 110#define SYMBOL_MAXLENGTH 256
111#define SYMBOL_HASHSIZE 257 111#define SYMBOL_HASHSIZE 9973
112#define SYMBOL_HASHMASK 0xff
113 112
114/* A property represent the config options that can be associated 113/* A property represent the config options that can be associated
115 * with a config "symbol". 114 * with a config "symbol".
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 6c8fbbb66ebc..9ee3923117ee 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -651,12 +651,20 @@ bool sym_is_changable(struct symbol *sym)
651 return sym->visible > sym->rev_dep.tri; 651 return sym->visible > sym->rev_dep.tri;
652} 652}
653 653
654static unsigned strhash(const char *s)
655{
656 /* fnv32 hash */
657 unsigned hash = 2166136261U;
658 for (; *s; s++)
659 hash = (hash ^ *s) * 0x01000193;
660 return hash;
661}
662
654struct symbol *sym_lookup(const char *name, int flags) 663struct symbol *sym_lookup(const char *name, int flags)
655{ 664{
656 struct symbol *symbol; 665 struct symbol *symbol;
657 const char *ptr;
658 char *new_name; 666 char *new_name;
659 int hash = 0; 667 int hash;
660 668
661 if (name) { 669 if (name) {
662 if (name[0] && !name[1]) { 670 if (name[0] && !name[1]) {
@@ -666,12 +674,11 @@ struct symbol *sym_lookup(const char *name, int flags)
666 case 'n': return &symbol_no; 674 case 'n': return &symbol_no;
667 } 675 }
668 } 676 }
669 for (ptr = name; *ptr; ptr++) 677 hash = strhash(name) % SYMBOL_HASHSIZE;
670 hash += *ptr;
671 hash &= 0xff;
672 678
673 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 679 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
674 if (!strcmp(symbol->name, name) && 680 if (symbol->name &&
681 !strcmp(symbol->name, name) &&
675 (flags ? symbol->flags & flags 682 (flags ? symbol->flags & flags
676 : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) 683 : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
677 return symbol; 684 return symbol;
@@ -679,7 +686,7 @@ struct symbol *sym_lookup(const char *name, int flags)
679 new_name = strdup(name); 686 new_name = strdup(name);
680 } else { 687 } else {
681 new_name = NULL; 688 new_name = NULL;
682 hash = 256; 689 hash = 0;
683 } 690 }
684 691
685 symbol = malloc(sizeof(*symbol)); 692 symbol = malloc(sizeof(*symbol));
@@ -697,7 +704,6 @@ struct symbol *sym_lookup(const char *name, int flags)
697struct symbol *sym_find(const char *name) 704struct symbol *sym_find(const char *name)
698{ 705{
699 struct symbol *symbol = NULL; 706 struct symbol *symbol = NULL;
700 const char *ptr;
701 int hash = 0; 707 int hash = 0;
702 708
703 if (!name) 709 if (!name)
@@ -710,12 +716,11 @@ struct symbol *sym_find(const char *name)
710 case 'n': return &symbol_no; 716 case 'n': return &symbol_no;
711 } 717 }
712 } 718 }
713 for (ptr = name; *ptr; ptr++) 719 hash = strhash(name) % SYMBOL_HASHSIZE;
714 hash += *ptr;
715 hash &= 0xff;
716 720
717 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 721 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
718 if (!strcmp(symbol->name, name) && 722 if (symbol->name &&
723 !strcmp(symbol->name, name) &&
719 !(symbol->flags & SYMBOL_CONST)) 724 !(symbol->flags & SYMBOL_CONST))
720 break; 725 break;
721 } 726 }
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index 8a0867a32b0f..7df3264c3f3d 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -104,7 +104,7 @@ static void zconf_error(const char *err, ...);
104static void zconferror(const char *err); 104static void zconferror(const char *err);
105static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); 105static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
106 106
107struct symbol *symbol_hash[257]; 107struct symbol *symbol_hash[SYMBOL_HASHSIZE];
108 108
109static struct menu *current_menu, *current_entry; 109static struct menu *current_menu, *current_entry;
110 110
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 361b54318c8d..258f16608ec0 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -27,7 +27,7 @@ static void zconf_error(const char *err, ...);
27static void zconferror(const char *err); 27static void zconferror(const char *err);
28static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken); 28static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
29 29
30struct symbol *symbol_hash[257]; 30struct symbol *symbol_hash[SYMBOL_HASHSIZE];
31 31
32static struct menu *current_menu, *current_entry; 32static struct menu *current_menu, *current_entry;
33 33