Changeset 3138 for vendor/gnumake/current/strcache.c
- Timestamp:
- Mar 12, 2018, 8:32:29 PM (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/gnumake/current/strcache.c
r2596 r3138 1 1 /* Constant string caching for GNU Make. 2 Copyright (C) 2006 , 2007, 2008, 2009, 2010Free Software Foundation, Inc.2 Copyright (C) 2006-2016 Free Software Foundation, Inc. 3 3 This file is part of GNU Make. 4 4 … … 15 15 this program. If not, see <http://www.gnu.org/licenses/>. */ 16 16 17 #include "make.h" 18 17 #include "makeint.h" 18 19 #include <stddef.h> 19 20 #include <assert.h> 20 21 21 22 #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 23 28 24 /* A string cached here will never be freed, so we don't need to worry about … … 30 26 hash so it can be looked up again. */ 31 27 28 typedef unsigned short int sc_buflen_t; 29 32 30 struct strcache { 33 struct strcache *next; /* The next block of strings. */34 char *end; /* Pointer to the beginning of thefree space. */35 int count; /* # of strings in this buffer (for stats). */36 int bytesfree; /* The amount of the buffer that is free. */31 struct strcache *next; /* The next block of strings. Must be first! */ 32 sc_buflen_t end; /* Offset to the beginning of free space. */ 33 sc_buflen_t bytesfree; /* Free space left in this buffer. */ 34 sc_buflen_t count; /* # of strings in this buffer (for stats). */ 37 35 char buffer[1]; /* The buffer comes after this. */ 38 36 }; 39 37 40 static int bufsize = CACHE_BUFFER_SIZE; 38 /* The size (in bytes) of each cache buffer. 39 Try to pick something that will map well into the heap. 40 This must be able to be represented by a short int (<=65535). */ 41 #define CACHE_BUFFER_BASE (8192) 42 #define CACHE_BUFFER_ALLOC(_s) ((_s) - (2 * sizeof (size_t))) 43 #define CACHE_BUFFER_OFFSET (offsetof (struct strcache, buffer)) 44 #define CACHE_BUFFER_SIZE(_s) (CACHE_BUFFER_ALLOC(_s) - CACHE_BUFFER_OFFSET) 45 #define BUFSIZE CACHE_BUFFER_SIZE (CACHE_BUFFER_BASE) 46 41 47 static struct strcache *strcache = NULL; 48 static struct strcache *fullcache = NULL; 49 50 static unsigned long total_buffers = 0; 51 static unsigned long total_strings = 0; 52 static unsigned long total_size = 0; 42 53 43 54 /* Add a new buffer to the cache. Add it at the front to reduce search time. … … 47 58 */ 48 59 static struct strcache * 49 new_cache() 50 { 51 struct strcache *new; 52 new = xmalloc (sizeof (*new) + bufsize); 53 new->end = new->buffer; 60 new_cache (struct strcache **head, sc_buflen_t buflen) 61 { 62 struct strcache *new = xmalloc (buflen + CACHE_BUFFER_OFFSET); 63 new->end = 0; 54 64 new->count = 0; 55 new->bytesfree = bufsize; 56 57 new->next = strcache; 58 strcache = new; 59 65 new->bytesfree = buflen; 66 67 new->next = *head; 68 *head = new; 69 70 ++total_buffers; 60 71 return new; 61 72 } 62 73 63 74 static const char * 64 add_string(const char *str, int len) 65 { 66 struct strcache *best = NULL; 75 copy_string (struct strcache *sp, const char *str, unsigned int len) 76 { 77 /* Add the string to this cache. */ 78 char *res = &sp->buffer[sp->end]; 79 80 memmove (res, str, len); 81 res[len++] = '\0'; 82 sp->end += len; 83 sp->bytesfree -= len; 84 ++sp->count; 85 86 return res; 87 } 88 89 static const char * 90 add_string (const char *str, unsigned int len) 91 { 92 const char *res; 67 93 struct strcache *sp; 68 const char *res; 94 struct strcache **spp = &strcache; 95 /* We need space for the nul char. */ 96 unsigned int sz = len + 1; 97 98 ++total_strings; 99 total_size += sz; 69 100 70 101 /* If the string we want is too large to fit into a single buffer, then 71 we're screwed; nothing will ever fit! Change the maximum size of the 72 cache to be big enough. */ 73 if (len > bufsize) 74 bufsize = len * 2; 75 76 /* First, find a cache with enough free space. We always look through all 77 the blocks and choose the one with the best fit (the one that leaves the 78 least amount of space free). */ 79 for (sp = strcache; sp != NULL; sp = sp->next) 80 if (sp->bytesfree > len && (!best || best->bytesfree > sp->bytesfree)) 81 best = sp; 82 83 /* If nothing is big enough, make a new cache. */ 84 if (!best) 85 best = new_cache(); 86 87 assert (best->bytesfree > len); 88 89 /* Add the string to the best cache. */ 90 res = best->end; 91 memcpy (best->end, str, len); 92 best->end += len; 93 *(best->end++) = '\0'; 94 best->bytesfree -= len + 1; 95 ++best->count; 102 no existing cache is large enough. Add it directly to the fullcache. */ 103 if (sz > BUFSIZE) 104 { 105 sp = new_cache (&fullcache, sz); 106 return copy_string (sp, str, len); 107 } 108 109 /* Find the first cache with enough free space. */ 110 for (; *spp != NULL; spp = &(*spp)->next) 111 if ((*spp)->bytesfree > sz) 112 break; 113 sp = *spp; 114 115 /* If nothing is big enough, make a new cache at the front. */ 116 if (sp == NULL) 117 { 118 sp = new_cache (&strcache, BUFSIZE); 119 spp = &strcache; 120 } 121 122 /* Add the string to this cache. */ 123 res = copy_string (sp, str, len); 124 125 /* If the amount free in this cache is less than the average string size, 126 consider it full and move it to the full list. */ 127 if (total_strings > 20 && sp->bytesfree < (total_size / total_strings) + 1) 128 { 129 *spp = sp->next; 130 sp->next = fullcache; 131 fullcache = sp; 132 } 96 133 97 134 return res; 98 135 } 99 136 137 /* For strings too large for the strcache, we just save them in a list. */ 138 struct hugestring { 139 struct hugestring *next; /* The next string. */ 140 char buffer[1]; /* The string. */ 141 }; 142 143 static struct hugestring *hugestrings = NULL; 144 145 static const char * 146 add_hugestring (const char *str, unsigned int len) 147 { 148 struct hugestring *new = xmalloc (sizeof (struct hugestring) + len); 149 memcpy (new->buffer, str, len); 150 new->buffer[len] = '\0'; 151 152 new->next = hugestrings; 153 hugestrings = new; 154 155 return new->buffer; 156 } 100 157 101 158 /* Hash table of strings in the cache. */ … … 123 180 124 181 static const char * 125 add_hash (const char *str, int len) 126 { 182 add_hash (const char *str, unsigned int len) 183 { 184 char *const *slot; 185 const char *key; 186 187 /* If it's too large for the string cache, just copy it. 188 We don't bother trying to match these. */ 189 if (len > USHRT_MAX - 1) 190 return add_hugestring (str, len); 191 127 192 /* Look up the string in the hash. If it's there, return it. */ 128 char *const *slot = (char *const *) hash_find_slot (&strings, str);129 const char *key = *slot;130 131 /* Count the total number of add s we performed. */193 slot = (char *const *) hash_find_slot (&strings, str); 194 key = *slot; 195 196 /* Count the total number of add operations we performed. */ 132 197 ++total_adds; 133 198 … … 148 213 149 214 for (sp = strcache; sp != 0; sp = sp->next) 150 if (str >= sp->buffer && str < sp-> end)215 if (str >= sp->buffer && str < sp->buffer + sp->end) 151 216 return 1; 217 for (sp = fullcache; sp != 0; sp = sp->next) 218 if (str >= sp->buffer && str < sp->buffer + sp->end) 219 return 1; 220 221 { 222 struct hugestring *hp; 223 for (hp = hugestrings; hp != 0; hp = hp->next) 224 if (str == hp->buffer) 225 return 1; 226 } 152 227 153 228 return 0; … … 164 239 165 240 const char * 166 strcache_add_len (const char *str, int len)241 strcache_add_len (const char *str, unsigned int len) 167 242 { 168 243 /* If we're not given a nul-terminated string we have to create one, because … … 179 254 } 180 255 181 int182 strcache_setbufsize(int size)183 {184 if (size > bufsize)185 bufsize = size;186 return bufsize;187 }188 189 256 void 190 257 strcache_init (void) … … 199 266 strcache_print_stats (const char *prefix) 200 267 { 201 int numbuffs = 0, numstrs = 0; 202 int totsize = 0, avgsize, maxsize = 0, minsize = bufsize; 203 int totfree = 0, avgfree, maxfree = 0, minfree = bufsize; 204 int lastused = 0, lastfree = 0; 205 206 if (strcache) 207 { 208 const struct strcache *sp; 209 210 /* Count the first buffer separately since it's not full. */ 211 lastused = strcache->end - strcache->buffer; 212 lastfree = strcache->bytesfree; 213 214 for (sp = strcache->next; sp != NULL; sp = sp->next) 215 { 216 int bf = sp->bytesfree; 217 int sz = sp->end - sp->buffer; 218 219 ++numbuffs; 220 numstrs += sp->count; 221 222 totsize += sz; 223 maxsize = (sz > maxsize ? sz : maxsize); 224 minsize = (sz < minsize ? sz : minsize); 225 226 totfree += bf; 227 maxfree = (bf > maxfree ? bf : maxfree); 228 minfree = (bf < minfree ? bf : minfree); 229 } 230 } 231 232 avgsize = numbuffs ? (int)(totsize / numbuffs) : 0; 233 avgfree = numbuffs ? (int)(totfree / numbuffs) : 0; 234 235 printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"), 236 prefix, numstrs, total_adds, (total_adds - numstrs)); 237 printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"), 238 prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize)); 239 printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"), 240 prefix, totsize, lastused, maxsize, minsize, avgsize); 241 printf (_("%s strcache free: total = %d (%d) / max = %d / min = %d / avg = %d\n"), 242 prefix, totfree, lastfree, maxfree, minfree, avgfree); 243 244 fputs (_("\n# strcache hash-table stats:\n# "), stdout); 268 const struct strcache *sp; 269 unsigned long numbuffs = 0, fullbuffs = 0; 270 unsigned long totfree = 0, maxfree = 0, minfree = BUFSIZE; 271 272 if (! strcache) 273 { 274 printf (_("\n%s No strcache buffers\n"), prefix); 275 return; 276 } 277 278 /* Count the first buffer separately since it's not full. */ 279 for (sp = strcache->next; sp != NULL; sp = sp->next) 280 { 281 sc_buflen_t bf = sp->bytesfree; 282 283 totfree += bf; 284 maxfree = (bf > maxfree ? bf : maxfree); 285 minfree = (bf < minfree ? bf : minfree); 286 287 ++numbuffs; 288 } 289 for (sp = fullcache; sp != NULL; sp = sp->next) 290 { 291 sc_buflen_t bf = sp->bytesfree; 292 293 totfree += bf; 294 maxfree = (bf > maxfree ? bf : maxfree); 295 minfree = (bf < minfree ? bf : minfree); 296 297 ++numbuffs; 298 ++fullbuffs; 299 } 300 301 /* Make sure we didn't lose any buffers. */ 302 assert (total_buffers == numbuffs + 1); 303 304 printf (_("\n%s strcache buffers: %lu (%lu) / strings = %lu / storage = %lu B / avg = %lu B\n"), 305 prefix, numbuffs + 1, fullbuffs, total_strings, total_size, 306 (total_size / total_strings)); 307 308 printf (_("%s current buf: size = %hu B / used = %hu B / count = %hu / avg = %hu B\n"), 309 prefix, (sc_buflen_t)BUFSIZE, strcache->end, strcache->count, 310 (strcache->end / strcache->count)); 311 312 if (numbuffs) 313 { 314 /* Show information about non-current buffers. */ 315 unsigned long sz = total_size - strcache->end; 316 unsigned long cnt = total_strings - strcache->count; 317 sc_buflen_t avgfree = totfree / numbuffs; 318 319 printf (_("%s other used: total = %lu B / count = %lu / avg = %lu B\n"), 320 prefix, sz, cnt, sz / cnt); 321 322 printf (_("%s other free: total = %lu B / max = %lu B / min = %lu B / avg = %hu B\n"), 323 prefix, totfree, maxfree, minfree, avgfree); 324 } 325 326 printf (_("\n%s strcache performance: lookups = %lu / hit rate = %lu%%\n"), 327 prefix, total_adds, (long unsigned)(100.0 * (total_adds - total_strings) / total_adds)); 328 fputs (_("# hash-table stats:\n# "), stdout); 245 329 hash_print_stats (&strings, stdout); 246 330 }
Note:
See TracChangeset
for help on using the changeset viewer.