15796c8dcSSimon Schubert /* Include file cached obstack implementation. 25796c8dcSSimon Schubert Written by Fred Fish <fnf@cygnus.com> 35796c8dcSSimon Schubert Rewritten by Jim Blandy <jimb@cygnus.com> 45796c8dcSSimon Schubert 5*ef5ccd6cSJohn Marino Copyright (C) 1999-2013 Free Software Foundation, Inc. 65796c8dcSSimon Schubert 75796c8dcSSimon Schubert This file is part of GDB. 85796c8dcSSimon Schubert 95796c8dcSSimon Schubert This program is free software; you can redistribute it and/or modify 105796c8dcSSimon Schubert it under the terms of the GNU General Public License as published by 115796c8dcSSimon Schubert the Free Software Foundation; either version 3 of the License, or 125796c8dcSSimon Schubert (at your option) any later version. 135796c8dcSSimon Schubert 145796c8dcSSimon Schubert This program is distributed in the hope that it will be useful, 155796c8dcSSimon Schubert but WITHOUT ANY WARRANTY; without even the implied warranty of 165796c8dcSSimon Schubert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 175796c8dcSSimon Schubert GNU General Public License for more details. 185796c8dcSSimon Schubert 195796c8dcSSimon Schubert You should have received a copy of the GNU General Public License 205796c8dcSSimon Schubert along with this program. If not, see <http://www.gnu.org/licenses/>. */ 215796c8dcSSimon Schubert 225796c8dcSSimon Schubert #ifndef BCACHE_H 235796c8dcSSimon Schubert #define BCACHE_H 1 245796c8dcSSimon Schubert 255796c8dcSSimon Schubert /* A bcache is a data structure for factoring out duplication in 265796c8dcSSimon Schubert read-only structures. You give the bcache some string of bytes S. 275796c8dcSSimon Schubert If the bcache already contains a copy of S, it hands you back a 285796c8dcSSimon Schubert pointer to its copy. Otherwise, it makes a fresh copy of S, and 295796c8dcSSimon Schubert hands you back a pointer to that. In either case, you can throw 305796c8dcSSimon Schubert away your copy of S, and use the bcache's. 315796c8dcSSimon Schubert 325796c8dcSSimon Schubert The "strings" in question are arbitrary strings of bytes --- they 335796c8dcSSimon Schubert can contain zero bytes. You pass in the length explicitly when you 345796c8dcSSimon Schubert call the bcache function. 355796c8dcSSimon Schubert 365796c8dcSSimon Schubert This means that you can put ordinary C objects in a bcache. 375796c8dcSSimon Schubert However, if you do this, remember that structs can contain `holes' 385796c8dcSSimon Schubert between members, added for alignment. These bytes usually contain 395796c8dcSSimon Schubert garbage. If you try to bcache two objects which are identical from 405796c8dcSSimon Schubert your code's point of view, but have different garbage values in the 415796c8dcSSimon Schubert structure's holes, then the bcache will treat them as separate 425796c8dcSSimon Schubert strings, and you won't get the nice elimination of duplicates you 435796c8dcSSimon Schubert were hoping for. So, remember to memset your structures full of 445796c8dcSSimon Schubert zeros before bcaching them! 455796c8dcSSimon Schubert 465796c8dcSSimon Schubert You shouldn't modify the strings you get from a bcache, because: 475796c8dcSSimon Schubert 485796c8dcSSimon Schubert - You don't necessarily know who you're sharing space with. If I 495796c8dcSSimon Schubert stick eight bytes of text in a bcache, and then stick an eight-byte 505796c8dcSSimon Schubert structure in the same bcache, there's no guarantee those two 515796c8dcSSimon Schubert objects don't actually comprise the same sequence of bytes. If 525796c8dcSSimon Schubert they happen to, the bcache will use a single byte string for both 535796c8dcSSimon Schubert of them. Then, modifying the structure will change the string. In 545796c8dcSSimon Schubert bizarre ways. 555796c8dcSSimon Schubert 565796c8dcSSimon Schubert - Even if you know for some other reason that all that's okay, 575796c8dcSSimon Schubert there's another problem. A bcache stores all its strings in a hash 585796c8dcSSimon Schubert table. If you modify a string's contents, you will probably change 595796c8dcSSimon Schubert its hash value. This means that the modified string is now in the 605796c8dcSSimon Schubert wrong place in the hash table, and future bcache probes will never 615796c8dcSSimon Schubert find it. So by mutating a string, you give up any chance of 625796c8dcSSimon Schubert sharing its space with future duplicates. 635796c8dcSSimon Schubert 645796c8dcSSimon Schubert 655796c8dcSSimon Schubert Size of bcache VS hashtab: 665796c8dcSSimon Schubert 675796c8dcSSimon Schubert For bcache, the most critical cost is size (or more exactly the 685796c8dcSSimon Schubert overhead added by the bcache). It turns out that the bcache is 695796c8dcSSimon Schubert remarkably efficient. 705796c8dcSSimon Schubert 715796c8dcSSimon Schubert Assuming a 32-bit system (the hash table slots are 4 bytes), 725796c8dcSSimon Schubert ignoring alignment, and limit strings to 255 bytes (1 byte length) 735796c8dcSSimon Schubert we get ... 745796c8dcSSimon Schubert 755796c8dcSSimon Schubert bcache: This uses a separate linked list to track the hash chain. 765796c8dcSSimon Schubert The numbers show roughly 100% occupancy of the hash table and an 775796c8dcSSimon Schubert average chain length of 4. Spreading the slot cost over the 4 785796c8dcSSimon Schubert chain elements: 795796c8dcSSimon Schubert 805796c8dcSSimon Schubert 4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes 815796c8dcSSimon Schubert 825796c8dcSSimon Schubert hashtab: This uses a more traditional re-hash algorithm where the 835796c8dcSSimon Schubert chain is maintained within the hash table. The table occupancy is 845796c8dcSSimon Schubert kept below 75% but we'll assume its perfect: 855796c8dcSSimon Schubert 865796c8dcSSimon Schubert 4 (slot) x 4/3 (occupancy) + 1 (length) = 6 1/3 bytes 875796c8dcSSimon Schubert 885796c8dcSSimon Schubert So a perfect hashtab has just slightly larger than an average 895796c8dcSSimon Schubert bcache. 905796c8dcSSimon Schubert 915796c8dcSSimon Schubert It turns out that an average hashtab is far worse. Two things 925796c8dcSSimon Schubert hurt: 935796c8dcSSimon Schubert 945796c8dcSSimon Schubert - Hashtab's occupancy is more like 50% (it ranges between 38% and 955796c8dcSSimon Schubert 75%) giving a per slot cost of 4x2 vs 4x4/3. 965796c8dcSSimon Schubert 975796c8dcSSimon Schubert - the string structure needs to be aligned to 8 bytes which for 985796c8dcSSimon Schubert hashtab wastes 7 bytes, while for bcache wastes only 3. 995796c8dcSSimon Schubert 1005796c8dcSSimon Schubert This gives: 1015796c8dcSSimon Schubert 1025796c8dcSSimon Schubert hashtab: 4 x 2 + 1 + 7 = 16 bytes 1035796c8dcSSimon Schubert 1045796c8dcSSimon Schubert bcache 4 / 4 + 1 + 4 + 3 = 9 bytes 1055796c8dcSSimon Schubert 1065796c8dcSSimon Schubert The numbers of GDB debugging GDB support this. ~40% vs ~70% overhead. 1075796c8dcSSimon Schubert 1085796c8dcSSimon Schubert 1095796c8dcSSimon Schubert Speed of bcache VS hashtab (the half hash hack): 1105796c8dcSSimon Schubert 1115796c8dcSSimon Schubert While hashtab has a typical chain length of 1, bcache has a chain 1125796c8dcSSimon Schubert length of round 4. This means that the bcache will require 1135796c8dcSSimon Schubert something like double the number of compares after that initial 1145796c8dcSSimon Schubert hash. In both cases the comparison takes the form: 1155796c8dcSSimon Schubert 1165796c8dcSSimon Schubert a.length == b.length && memcmp (a.data, b.data, a.length) == 0 1175796c8dcSSimon Schubert 1185796c8dcSSimon Schubert That is lengths are checked before doing the memcmp. 1195796c8dcSSimon Schubert 1205796c8dcSSimon Schubert For GDB debugging GDB, it turned out that all lengths were 24 bytes 1215796c8dcSSimon Schubert (no C++ so only psymbols were cached) and hence, all compares 1225796c8dcSSimon Schubert required a call to memcmp. As a hack, two bytes of padding 1235796c8dcSSimon Schubert (mentioned above) are used to store the upper 16 bits of the 1245796c8dcSSimon Schubert string's hash value and then that is used in the comparison vis: 1255796c8dcSSimon Schubert 1265796c8dcSSimon Schubert a.half_hash == b.half_hash && a.length == b.length && memcmp 1275796c8dcSSimon Schubert (a.data, b.data, a.length) 1285796c8dcSSimon Schubert 1295796c8dcSSimon Schubert The numbers from GDB debugging GDB show this to be a remarkable 1305796c8dcSSimon Schubert 100% effective (only necessary length and memcmp tests being 1315796c8dcSSimon Schubert performed). 1325796c8dcSSimon Schubert 1335796c8dcSSimon Schubert Mind you, looking at the wall clock, the same GDB debugging GDB 1345796c8dcSSimon Schubert showed only marginal speed up (0.780 vs 0.773s). Seems GDB is too 1355796c8dcSSimon Schubert busy doing something else :-( 1365796c8dcSSimon Schubert 1375796c8dcSSimon Schubert */ 1385796c8dcSSimon Schubert 1395796c8dcSSimon Schubert 1405796c8dcSSimon Schubert struct bcache; 1415796c8dcSSimon Schubert 1425796c8dcSSimon Schubert /* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has 1435796c8dcSSimon Schubert never seen those bytes before, add a copy of them to BCACHE. In 1445796c8dcSSimon Schubert either case, return a pointer to BCACHE's copy of that string. 1455796c8dcSSimon Schubert Since the cached value is ment to be read-only, return a const 1465796c8dcSSimon Schubert buffer. */ 1475796c8dcSSimon Schubert extern const void *bcache (const void *addr, int length, 1485796c8dcSSimon Schubert struct bcache *bcache); 1495796c8dcSSimon Schubert 1505796c8dcSSimon Schubert /* Like bcache, but if ADDED is not NULL, set *ADDED to true if the 1515796c8dcSSimon Schubert bytes were newly added to the cache, or to false if the bytes were 1525796c8dcSSimon Schubert found in the cache. */ 1535796c8dcSSimon Schubert extern const void *bcache_full (const void *addr, int length, 1545796c8dcSSimon Schubert struct bcache *bcache, int *added); 1555796c8dcSSimon Schubert 1565796c8dcSSimon Schubert /* Free all the storage used by BCACHE. */ 1575796c8dcSSimon Schubert extern void bcache_xfree (struct bcache *bcache); 1585796c8dcSSimon Schubert 1595796c8dcSSimon Schubert /* Create a new bcache object. */ 160c50c785cSJohn Marino extern struct bcache *bcache_xmalloc ( 161c50c785cSJohn Marino unsigned long (*hash_function)(const void *, int length), 162c50c785cSJohn Marino int (*compare_function)(const void *, const void *, int length)); 1635796c8dcSSimon Schubert 1645796c8dcSSimon Schubert /* Print statistics on BCACHE's memory usage and efficacity at 1655796c8dcSSimon Schubert eliminating duplication. TYPE should be a string describing the 1665796c8dcSSimon Schubert kind of data BCACHE holds. Statistics are printed using 1675796c8dcSSimon Schubert `printf_filtered' and its ilk. */ 1685796c8dcSSimon Schubert extern void print_bcache_statistics (struct bcache *bcache, char *type); 1695796c8dcSSimon Schubert extern int bcache_memory_used (struct bcache *bcache); 1705796c8dcSSimon Schubert 171c50c785cSJohn Marino /* The hash functions */ 1725796c8dcSSimon Schubert extern unsigned long hash(const void *addr, int length); 173c50c785cSJohn Marino extern unsigned long hash_continue (const void *addr, int length, 174c50c785cSJohn Marino unsigned long h); 1755796c8dcSSimon Schubert 1765796c8dcSSimon Schubert #endif /* BCACHE_H */ 177