VirtualBox

source: kBuild/trunk/src/kmk/strcache.c@ 1864

Last change on this file since 1864 was 1858, checked in by bird, 16 years ago

kmk: Added hash_find_slot_prehashed for the benefit of the strcache and includedep.

  • Property svn:eol-style set to native
File size: 12.6 KB
Line 
1/* Constant string caching for GNU Make.
2Copyright (C) 2006 Free Software Foundation, Inc.
3This file is part of GNU Make.
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 2, or (at your option) any later version.
8
9GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License along with
14GNU Make; see the file COPYING. If not, write to the Free Software
15Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
16
17#include "make.h"
18
19#include <assert.h>
20
21#include "hash.h"
22
23/* The size (in bytes) of each cache buffer.
24 Try to pick something that will map well into the heap. */
25#define CACHE_BUFFER_SIZE (8192 - 16)
26
27
28/* A string cached here will never be freed, so we don't need to worry about
29 reference counting. We just store the string, and then remember it in a
30 hash so it can be looked up again. */
31
32struct strcache {
33 struct strcache *next; /* The next block of strings. */
34 char *end; /* Pointer to the beginning of the free space. */
35 int count; /* # of strings in this buffer (for stats). */
36 int bytesfree; /* The amount of the buffer that is free. */
37 char buffer[1]; /* The buffer comes after this. */
38};
39
40static int bufsize = CACHE_BUFFER_SIZE;
41static struct strcache *strcache = NULL;
42
43/* Add a new buffer to the cache. Add it at the front to reduce search time.
44 This can also increase the overhead, since it's less likely that older
45 buffers will be filled in. However, GNU make has so many smaller strings
46 that this doesn't seem to be much of an issue in practice.
47 */
48static struct strcache *
49new_cache()
50{
51 struct strcache *new;
52 new = xmalloc (sizeof (*new) + bufsize);
53 new->end = new->buffer;
54 new->count = 0;
55 new->bytesfree = bufsize;
56
57 new->next = strcache;
58 strcache = new;
59
60 return new;
61}
62
63#ifndef CONFIG_WITH_VALUE_LENGTH
64static const char *
65add_string(const char *str, int len)
66{
67 struct strcache *best = NULL;
68 struct strcache *sp;
69 const char *res;
70
71 /* If the string we want is too large to fit into a single buffer, then
72 we're screwed; nothing will ever fit! Change the maximum size of the
73 cache to be big enough. */
74 if (len > bufsize)
75 bufsize = len * 2;
76
77 /* First, find a cache with enough free space. We always look through all
78 the blocks and choose the one with the best fit (the one that leaves the
79 least amount of space free). */
80 for (sp = strcache; sp != NULL; sp = sp->next)
81 if (sp->bytesfree > len && (!best || best->bytesfree > sp->bytesfree))
82 best = sp;
83
84 /* If nothing is big enough, make a new cache. */
85 if (!best)
86 best = new_cache();
87
88 assert (best->bytesfree > len);
89
90 /* Add the string to the best cache. */
91 res = best->end;
92 memcpy (best->end, str, len);
93 best->end += len;
94 *(best->end++) = '\0';
95 best->bytesfree -= len + 1;
96 ++best->count;
97 return res;
98}
99
100#else /* CONFIG_WITH_VALUE_LENGTH */
101
102static const char *
103add_string(const char *str, struct strcache_pref *prefix)
104{
105 struct strcache *best = NULL;
106 struct strcache *sp;
107 struct strcache_pref *real_prefix;
108 int len;
109 const char *res;
110 char *dst;
111
112 /* Calc the entry length; the prefix data + the string + alignment. */
113 len = sizeof(struct strcache_pref) + prefix->len + 1;
114 len = (len + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
115
116 /* If the string we want is too large to fit into a single buffer, then
117 we're screwed; nothing will ever fit! Change the maximum size of the
118 cache to be big enough. */
119 if (len > bufsize)
120 bufsize = len * 2;
121
122 /* First, find a cache with enough free space. We always look through all
123 the blocks and choose the one with the best fit (the one that leaves the
124 least amount of space free). */
125 for (sp = strcache; sp != NULL; sp = sp->next)
126 if (sp->bytesfree >= len && (!best || best->bytesfree > sp->bytesfree))
127 best = sp;
128
129 /* If nothing is big enough, make a new cache. */
130 if (!best)
131 best = new_cache();
132
133 assert (best->bytesfree >= len);
134
135 /* Add the string to the best cache. */
136 real_prefix = (struct strcache_pref *)best->end;
137 *real_prefix = *prefix;
138
139 res = dst = (char *)(real_prefix + 1);
140 assert(!((size_t)res & (sizeof(void *) - 1)));
141 memcpy (dst, str, prefix->len);
142 dst += prefix->len;
143 *(dst++) = '\0';
144
145 best->end += len;
146 best->bytesfree -= len;
147 ++best->count;
148
149 return res;
150}
151
152/* Hackish globals for passing data to the hash functions.
153 There isn't really any other way without running the
154 risk of breaking rehashing. */
155static const char *lookup_string;
156static struct strcache_pref *lookup_prefix;
157
158#endif /* CONFIG_WITH_VALUE_LENGTH */
159
160
161/* Hash table of strings in the cache. */
162
163static unsigned long
164str_hash_1 (const void *key)
165{
166#if 0
167#ifdef CONFIG_WITH_VALUE_LENGTH
168 if (MY_PREDICT_TRUE ((const char *) key == lookup_string))
169 return lookup_prefix->hash1;
170#endif
171#endif
172 return_ISTRING_HASH_1 ((const char *) key);
173}
174
175static unsigned long
176str_hash_2 (const void *key)
177{
178#ifdef CONFIG_WITH_VALUE_LENGTH
179 if (MY_PREDICT_TRUE ((const char *) key == lookup_string))
180 {
181 if (lookup_prefix->hash2)
182 {
183 unsigned long hash2 = 0;
184 ISTRING_HASH_2 ((const char *)key, hash2);
185 lookup_prefix->hash2 = hash2;
186 }
187 return lookup_prefix->hash2;
188 }
189#endif
190 return_ISTRING_HASH_2 ((const char *) key);
191}
192
193static int
194str_hash_cmp (const void *x, const void *y)
195{
196#ifdef CONFIG_WITH_VALUE_LENGTH
197 /* Use the string length to avoid some unncessary comparing.
198 X is either the add_hash input (during hash_find_slot)
199 or a cache entry (during rare hash_insert_at calls).
200 This catches 520253 out of 1341947 calls in the typical
201 kBuild scenario. */
202
203 if (MY_PREDICT_TRUE ((const char *) x == lookup_string))
204 {
205 assert (lookup_prefix->len == strlen ((const char *)x));
206 if (strcache_get_len ((const char *)y) != lookup_prefix->len)
207 return -1;
208 }
209#endif
210 return_ISTRING_COMPARE ((const char *) x, (const char *) y);
211}
212
213static struct hash_table strings;
214static unsigned long total_adds = 0;
215
216#ifndef CONFIG_WITH_VALUE_LENGTH
217static const char *
218add_hash (const char *str, int len)
219{
220 /* Look up the string in the hash. If it's there, return it. */
221 char *const *slot = (char *const *) hash_find_slot (&strings, str);
222 const char *key = *slot;
223
224 /* Count the total number of adds we performed. */
225 ++total_adds;
226
227 if (!HASH_VACANT (key))
228 return key;
229
230 /* Not there yet so add it to a buffer, then into the hash table. */
231 key = add_string (str, len);
232 hash_insert_at (&strings, key, slot);
233 return key;
234}
235
236#else /* CONFIG_WITH_VALUE_LENGTH */
237
238static const char *
239add_hash (const char *str, int len, unsigned long hash1, unsigned long hash2)
240{
241 void const **slot;
242 const char *key;
243 struct strcache_pref prefix;
244
245 /* Look up the string in the hash. If it's there, return it. */
246 prefix.len = len;
247 prefix.hash2 = hash2;
248 if (!hash1 && !hash2)
249 ISTRING_HASH_1 (str, hash1);
250 prefix.hash1 = hash1;
251
252 lookup_string = str;
253 lookup_prefix = &prefix;
254
255 slot = hash_find_slot_prehashed (&strings, str, prefix.hash1, prefix.hash2);
256 key = *(const char **)slot;
257
258 /* Count the total number of adds we performed. */
259 ++total_adds;
260
261 if (!HASH_VACANT (key))
262 return key;
263
264 /* Not there yet so add it to a buffer, then into the hash table. */
265 key = add_string (str, &prefix);
266 hash_insert_at (&strings, key, slot);
267 return key;
268}
269
270/* Verifies that a string cache entry didn't change and that the
271 prefix is still valid. */
272int
273strcache_check_sanity (const char *str)
274{
275 struct strcache_pref const *prefix = (struct strcache_pref const *)str - 1;
276 unsigned long hash;
277
278 if (strlen (str) != prefix->len)
279 {
280 MY_ASSERT_MSG (0, ("len: %u != %u - '%s'\n", (unsigned int)strlen (str),
281 prefix->len, str));
282 return -1;
283 }
284
285 hash = 0;
286 ISTRING_HASH_1 (str, hash);
287 if (hash != prefix->hash1)
288 {
289 MY_ASSERT_MSG (0, ("hash1: %lx != %lx - '%s'\n", hash, prefix->hash1, str));
290 return -1;
291 }
292
293 if (prefix->hash2)
294 {
295 hash = 0;
296 ISTRING_HASH_2 (str, hash);
297 if (hash != prefix->hash2)
298 {
299 MY_ASSERT_MSG (0, ("hash2: %lx != %lx - '%s'\n", hash, prefix->hash2, str));
300 return -1;
301 }
302 }
303
304 return 0;
305}
306
307/* Fallback for when the hash2 value isn't present. */
308unsigned long
309strcache_get_hash2_fallback (const char *str)
310{
311 struct strcache_pref *prefix = (struct strcache_pref *)str - 1;
312 unsigned long hash2 = 0;
313
314 ISTRING_HASH_2 (str, hash2);
315 prefix->hash2 = hash2;
316
317 return hash2;
318}
319
320#endif /* CONFIG_WITH_VALUE_LENGTH */
321
322/* Returns true if the string is in the cache; false if not. */
323int
324strcache_iscached (const char *str)
325{
326 struct strcache *sp;
327
328 for (sp = strcache; sp != 0; sp = sp->next)
329 if (str >= sp->buffer && str < sp->end)
330 return 1;
331
332 return 0;
333}
334
335/* If the string is already in the cache, return a pointer to the cached
336 version. If not, add it then return a pointer to the cached version.
337 Note we do NOT take control of the string passed in. */
338const char *
339strcache_add (const char *str)
340{
341#ifndef CONFIG_WITH_VALUE_LENGTH
342 return add_hash (str, strlen (str));
343#else
344 /* XXX: calc the hash1 while determining the string length. */
345 return add_hash (str, strlen (str), 0, 0);
346#endif
347}
348
349const char *
350strcache_add_len (const char *str, int len)
351{
352 /* If we're not given a nul-terminated string we have to create one, because
353 the hashing functions expect it. */
354 if (str[len] != '\0')
355 {
356 char *key = alloca (len + 1);
357 memcpy (key, str, len);
358 key[len] = '\0';
359 str = key;
360 }
361
362#ifndef CONFIG_WITH_VALUE_LENGTH
363 return add_hash (str, len);
364#else
365 /* XXX: eliminate the alloca mess using the prefixing? */
366 return add_hash (str, len, 0, 0);
367#endif
368}
369
370#ifdef CONFIG_WITH_INCLUDEDEP
371
372/* A special variant used by the includedep worker threads, it off loads
373 the main thread when it adds the strings to the cache later. */
374const char *
375strcache_add_prehashed (const char *str, int len, unsigned long hash1,
376 unsigned long hash2)
377{
378 return add_hash (str, len, hash1, hash2);
379}
380
381/* Performs the prehashing for use with strcache_add_prehashed(). */
382void
383strcache_prehash_str (const char *str, unsigned long *hash1p,
384 unsigned long *hash2p)
385{
386 *hash1p = str_hash_1 (str);
387 *hash2p = str_hash_2 (str);
388}
389
390#endif /* CONFIG_WITH_INCLUDEDEP */
391
392int
393strcache_setbufsize(int size)
394{
395 if (size > bufsize)
396 bufsize = size;
397 return bufsize;
398}
399
400void
401strcache_init (void)
402{
403#ifdef KMK
404 hash_init (&strings, 65535, str_hash_1, str_hash_2, str_hash_cmp);
405#else
406 hash_init (&strings, 8000, str_hash_1, str_hash_2, str_hash_cmp);
407#endif
408}
409
410
411/* Generate some stats output. */
412
413void
414strcache_print_stats (const char *prefix)
415{
416 int numbuffs = 0, numstrs = 0;
417 int totsize = 0, avgsize, maxsize = 0, minsize = bufsize;
418 int totfree = 0, avgfree, maxfree = 0, minfree = bufsize;
419 int lastused = 0, lastfree = 0;
420
421 if (strcache)
422 {
423 const struct strcache *sp;
424
425 /* Count the first buffer separately since it's not full. */
426 lastused = strcache->end - strcache->buffer;
427 lastfree = strcache->bytesfree;
428
429 for (sp = strcache->next; sp != NULL; sp = sp->next)
430 {
431 int bf = sp->bytesfree;
432 int sz = sp->end - sp->buffer;
433
434 ++numbuffs;
435 numstrs += sp->count;
436
437 totsize += sz;
438 maxsize = (sz > maxsize ? sz : maxsize);
439 minsize = (sz < minsize ? sz : minsize);
440
441 totfree += bf;
442 maxfree = (bf > maxfree ? bf : maxfree);
443 minfree = (bf < minfree ? bf : minfree);
444 }
445 }
446
447 avgsize = numbuffs ? (int)(totsize / numbuffs) : 0;
448 avgfree = numbuffs ? (int)(totfree / numbuffs) : 0;
449
450 printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"),
451 prefix, numstrs, total_adds, (total_adds - numstrs));
452 printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"),
453 prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize));
454 printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
455 prefix, totsize, lastused, maxsize, minsize, avgsize);
456 printf (_("%s strcache free: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
457 prefix, totfree, lastfree, maxfree, minfree, avgfree);
458
459 fputs (_("\n# strcache hash-table stats:\n# "), stdout);
460 hash_print_stats (&strings, stdout);
461}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette