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