1 /* Include file cached obstack implementation. 2 Written by Fred Fish <fnf@cygnus.com> 3 Rewritten by Jim Blandy <jimb@cygnus.com> 4 5 Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place - Suite 330, 22 Boston, MA 02111-1307, USA. */ 23 24 #ifndef BCACHE_H 25 #define BCACHE_H 1 26 27 /* A bcache is a data structure for factoring out duplication in 28 read-only structures. You give the bcache some string of bytes S. 29 If the bcache already contains a copy of S, it hands you back a 30 pointer to its copy. Otherwise, it makes a fresh copy of S, and 31 hands you back a pointer to that. In either case, you can throw 32 away your copy of S, and use the bcache's. 33 34 The "strings" in question are arbitrary strings of bytes --- they 35 can contain zero bytes. You pass in the length explicitly when you 36 call the bcache function. 37 38 This means that you can put ordinary C objects in a bcache. 39 However, if you do this, remember that structs can contain `holes' 40 between members, added for alignment. These bytes usually contain 41 garbage. If you try to bcache two objects which are identical from 42 your code's point of view, but have different garbage values in the 43 structure's holes, then the bcache will treat them as separate 44 strings, and you won't get the nice elimination of duplicates you 45 were hoping for. So, remember to memset your structures full of 46 zeros before bcaching them! 47 48 You shouldn't modify the strings you get from a bcache, because: 49 50 - You don't necessarily know who you're sharing space with. If I 51 stick eight bytes of text in a bcache, and then stick an eight-byte 52 structure in the same bcache, there's no guarantee those two 53 objects don't actually comprise the same sequence of bytes. If 54 they happen to, the bcache will use a single byte string for both 55 of them. Then, modifying the structure will change the string. In 56 bizarre ways. 57 58 - Even if you know for some other reason that all that's okay, 59 there's another problem. A bcache stores all its strings in a hash 60 table. If you modify a string's contents, you will probably change 61 its hash value. This means that the modified string is now in the 62 wrong place in the hash table, and future bcache probes will never 63 find it. So by mutating a string, you give up any chance of 64 sharing its space with future duplicates. 65 66 67 Size of bcache VS hashtab: 68 69 For bcache, the most critical cost is size (or more exactly the 70 overhead added by the bcache). It turns out that the bcache is 71 remarkably efficient. 72 73 Assuming a 32-bit system (the hash table slots are 4 bytes), 74 ignoring alignment, and limit strings to 255 bytes (1 byte length) 75 we get ... 76 77 bcache: This uses a separate linked list to track the hash chain. 78 The numbers show roughly 100% occupancy of the hash table and an 79 average chain length of 4. Spreading the slot cost over the 4 80 chain elements: 81 82 4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes 83 84 hashtab: This uses a more traditional re-hash algorithm where the 85 chain is maintained within the hash table. The table occupancy is 86 kept below 75% but we'll assume its perfect: 87 88 4 (slot) x 4/3 (occupancy) + 1 (length) = 6 1/3 bytes 89 90 So a perfect hashtab has just slightly larger than an average 91 bcache. 92 93 It turns out that an average hashtab is far worse. Two things 94 hurt: 95 96 - Hashtab's occupancy is more like 50% (it ranges between 38% and 97 75%) giving a per slot cost of 4x2 vs 4x4/3. 98 99 - the string structure needs to be aligned to 8 bytes which for 100 hashtab wastes 7 bytes, while for bcache wastes only 3. 101 102 This gives: 103 104 hashtab: 4 x 2 + 1 + 7 = 16 bytes 105 106 bcache 4 / 4 + 1 + 4 + 3 = 9 bytes 107 108 The numbers of GDB debugging GDB support this. ~40% vs ~70% overhead. 109 110 111 Speed of bcache VS hashtab (the half hash hack): 112 113 While hashtab has a typical chain length of 1, bcache has a chain 114 length of round 4. This means that the bcache will require 115 something like double the number of compares after that initial 116 hash. In both cases the comparison takes the form: 117 118 a.length == b.length && memcmp (a.data, b.data, a.length) == 0 119 120 That is lengths are checked before doing the memcmp. 121 122 For GDB debugging GDB, it turned out that all lengths were 24 bytes 123 (no C++ so only psymbols were cached) and hence, all compares 124 required a call to memcmp. As a hack, two bytes of padding 125 (mentioned above) are used to store the upper 16 bits of the 126 string's hash value and then that is used in the comparison vis: 127 128 a.half_hash == b.half_hash && a.length == b.length && memcmp 129 (a.data, b.data, a.length) 130 131 The numbers from GDB debugging GDB show this to be a remarkable 132 100% effective (only necessary length and memcmp tests being 133 performed). 134 135 Mind you, looking at the wall clock, the same GDB debugging GDB 136 showed only marginal speed up (0.780 vs 0.773s). Seems GDB is too 137 busy doing something else :-( 138 139 */ 140 141 142 struct bcache; 143 144 /* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has 145 never seen those bytes before, add a copy of them to BCACHE. In 146 either case, return a pointer to BCACHE's copy of that string. 147 Since the cached value is ment to be read-only, return a const 148 buffer. */ 149 extern void *deprecated_bcache (const void *addr, int length, 150 struct bcache *bcache); 151 extern const void *bcache (const void *addr, int length, 152 struct bcache *bcache); 153 154 /* Free all the storage used by BCACHE. */ 155 extern void bcache_xfree (struct bcache *bcache); 156 157 /* Create a new bcache object. */ 158 extern struct bcache *bcache_xmalloc (void); 159 160 /* Print statistics on BCACHE's memory usage and efficacity at 161 eliminating duplication. TYPE should be a string describing the 162 kind of data BCACHE holds. Statistics are printed using 163 `printf_filtered' and its ilk. */ 164 extern void print_bcache_statistics (struct bcache *bcache, char *type); 165 extern int bcache_memory_used (struct bcache *bcache); 166 167 /* The hash function */ 168 extern unsigned long hash(const void *addr, int length); 169 170 #endif /* BCACHE_H */ 171