diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-11-09 10:29:27 -0500 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2010-11-11 11:12:06 -0500 |
commit | 8af27e1dc4e4dd7a7b04c2cd0fc3d419d91d45b0 (patch) | |
tree | 0cf6febb82aafa421259a69007a6e848c3b9fa3c /scripts/basic | |
parent | d63f6d1b4d3ad0d88685a5f8eb1c3cac01ddd0db (diff) |
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: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Michal Marek <mmarek@suse.cz>
Diffstat (limited to 'scripts/basic')
-rw-r--r-- | scripts/basic/fixdep.c | 109 |
1 files changed, 61 insertions, 48 deletions
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index ea26b23de082..ed0584623690 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c | |||
@@ -138,38 +138,36 @@ static void print_cmdline(void) | |||
138 | printf("cmd_%s := %s\n\n", target, cmdline); | 138 | printf("cmd_%s := %s\n\n", target, cmdline); |
139 | } | 139 | } |
140 | 140 | ||
141 | char * str_config = NULL; | 141 | struct item { |
142 | int size_config = 0; | 142 | struct item *next; |
143 | int len_config = 0; | 143 | unsigned int len; |
144 | unsigned int hash; | ||
145 | char name[0]; | ||
146 | }; | ||
144 | 147 | ||
145 | /* | 148 | #define HASHSZ 256 |
146 | * Grow the configuration string to a desired length. | 149 | static struct item *hashtab[HASHSZ]; |
147 | * Usually the first growth is plenty. | ||
148 | */ | ||
149 | static void grow_config(int len) | ||
150 | { | ||
151 | while (len_config + len > size_config) { | ||
152 | if (size_config == 0) | ||
153 | size_config = 2048; | ||
154 | str_config = realloc(str_config, size_config *= 2); | ||
155 | if (str_config == NULL) | ||
156 | { perror("fixdep:malloc"); exit(1); } | ||
157 | } | ||
158 | } | ||
159 | 150 | ||
151 | static unsigned int strhash(const char *str, unsigned int sz) | ||
152 | { | ||
153 | /* fnv32 hash */ | ||
154 | unsigned int i, hash = 2166136261U; | ||
160 | 155 | ||
156 | for (i = 0; i < sz; i++) | ||
157 | hash = (hash ^ str[i]) * 0x01000193; | ||
158 | return hash; | ||
159 | } | ||
161 | 160 | ||
162 | /* | 161 | /* |
163 | * Lookup a value in the configuration string. | 162 | * Lookup a value in the configuration string. |
164 | */ | 163 | */ |
165 | static int is_defined_config(const char * name, int len) | 164 | static int is_defined_config(const char *name, int len, unsigned int hash) |
166 | { | 165 | { |
167 | const char * pconfig; | 166 | struct item *aux; |
168 | const char * plast = str_config + len_config - len; | 167 | |
169 | for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) { | 168 | for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) { |
170 | if (pconfig[ -1] == '\n' | 169 | if (aux->hash == hash && aux->len == len && |
171 | && pconfig[len] == '\n' | 170 | memcmp(aux->name, name, len) == 0) |
172 | && !memcmp(pconfig, name, len)) | ||
173 | return 1; | 171 | return 1; |
174 | } | 172 | } |
175 | return 0; | 173 | return 0; |
@@ -178,13 +176,19 @@ static int is_defined_config(const char * name, int len) | |||
178 | /* | 176 | /* |
179 | * Add a new value to the configuration string. | 177 | * Add a new value to the configuration string. |
180 | */ | 178 | */ |
181 | static void define_config(const char * name, int len) | 179 | static void define_config(const char *name, int len, unsigned int hash) |
182 | { | 180 | { |
183 | grow_config(len + 1); | 181 | struct item *aux = malloc(sizeof(*aux) + len); |
184 | 182 | ||
185 | memcpy(str_config+len_config, name, len); | 183 | if (!aux) { |
186 | len_config += len; | 184 | perror("fixdep:malloc"); |
187 | str_config[len_config++] = '\n'; | 185 | exit(1); |
186 | } | ||
187 | memcpy(aux->name, name, len); | ||
188 | aux->len = len; | ||
189 | aux->hash = hash; | ||
190 | aux->next = hashtab[hash % HASHSZ]; | ||
191 | hashtab[hash % HASHSZ] = aux; | ||
188 | } | 192 | } |
189 | 193 | ||
190 | /* | 194 | /* |
@@ -192,40 +196,49 @@ static void define_config(const char * name, int len) | |||
192 | */ | 196 | */ |
193 | static void clear_config(void) | 197 | static void clear_config(void) |
194 | { | 198 | { |
195 | len_config = 0; | 199 | struct item *aux, *next; |
196 | define_config("", 0); | 200 | unsigned int i; |
201 | |||
202 | for (i = 0; i < HASHSZ; i++) { | ||
203 | for (aux = hashtab[i]; aux; aux = next) { | ||
204 | next = aux->next; | ||
205 | free(aux); | ||
206 | } | ||
207 | hashtab[i] = NULL; | ||
208 | } | ||
197 | } | 209 | } |
198 | 210 | ||
199 | /* | 211 | /* |
200 | * Record the use of a CONFIG_* word. | 212 | * Record the use of a CONFIG_* word. |
201 | */ | 213 | */ |
202 | static void use_config(char *m, int slen) | 214 | static void use_config(const char *m, int slen) |
203 | { | 215 | { |
204 | char s[PATH_MAX]; | 216 | unsigned int hash = strhash(m, slen); |
205 | char *p; | 217 | int c, i; |
206 | 218 | ||
207 | if (is_defined_config(m, slen)) | 219 | if (is_defined_config(m, slen, hash)) |
208 | return; | 220 | return; |
209 | 221 | ||
210 | define_config(m, slen); | 222 | define_config(m, slen, hash); |
211 | |||
212 | memcpy(s, m, slen); s[slen] = 0; | ||
213 | 223 | ||
214 | for (p = s; p < s + slen; p++) { | 224 | printf(" $(wildcard include/config/"); |
215 | if (*p == '_') | 225 | for (i = 0; i < slen; i++) { |
216 | *p = '/'; | 226 | c = m[i]; |
227 | if (c == '_') | ||
228 | c = '/'; | ||
217 | else | 229 | else |
218 | *p = tolower((int)*p); | 230 | c = tolower(c); |
231 | putchar(c); | ||
219 | } | 232 | } |
220 | printf(" $(wildcard include/config/%s.h) \\\n", s); | 233 | printf(".h) \\\n"); |
221 | } | 234 | } |
222 | 235 | ||
223 | static void parse_config_file(char *map, size_t len) | 236 | static void parse_config_file(const char *map, size_t len) |
224 | { | 237 | { |
225 | int *end = (int *) (map + len); | 238 | const int *end = (const int *) (map + len); |
226 | /* start at +1, so that p can never be < map */ | 239 | /* start at +1, so that p can never be < map */ |
227 | int *m = (int *) map + 1; | 240 | const int *m = (const int *) map + 1; |
228 | char *p, *q; | 241 | const char *p, *q; |
229 | 242 | ||
230 | for (; m < end; m++) { | 243 | for (; m < end; m++) { |
231 | if (*m == INT_CONF) { p = (char *) m ; goto conf; } | 244 | if (*m == INT_CONF) { p = (char *) m ; goto conf; } |
@@ -265,7 +278,7 @@ static int strrcmp(char *s, char *sub) | |||
265 | return memcmp(s + slen - sublen, sub, sublen); | 278 | return memcmp(s + slen - sublen, sub, sublen); |
266 | } | 279 | } |
267 | 280 | ||
268 | static void do_config_file(char *filename) | 281 | static void do_config_file(const char *filename) |
269 | { | 282 | { |
270 | struct stat st; | 283 | struct stat st; |
271 | int fd; | 284 | int fd; |