GDB (API)
|
00001 /* Include file cached obstack implementation. 00002 Written by Fred Fish <fnf@cygnus.com> 00003 Rewritten by Jim Blandy <jimb@cygnus.com> 00004 00005 Copyright (C) 1999-2013 Free Software Foundation, Inc. 00006 00007 This file is part of GDB. 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00021 00022 #ifndef BCACHE_H 00023 #define BCACHE_H 1 00024 00025 /* A bcache is a data structure for factoring out duplication in 00026 read-only structures. You give the bcache some string of bytes S. 00027 If the bcache already contains a copy of S, it hands you back a 00028 pointer to its copy. Otherwise, it makes a fresh copy of S, and 00029 hands you back a pointer to that. In either case, you can throw 00030 away your copy of S, and use the bcache's. 00031 00032 The "strings" in question are arbitrary strings of bytes --- they 00033 can contain zero bytes. You pass in the length explicitly when you 00034 call the bcache function. 00035 00036 This means that you can put ordinary C objects in a bcache. 00037 However, if you do this, remember that structs can contain `holes' 00038 between members, added for alignment. These bytes usually contain 00039 garbage. If you try to bcache two objects which are identical from 00040 your code's point of view, but have different garbage values in the 00041 structure's holes, then the bcache will treat them as separate 00042 strings, and you won't get the nice elimination of duplicates you 00043 were hoping for. So, remember to memset your structures full of 00044 zeros before bcaching them! 00045 00046 You shouldn't modify the strings you get from a bcache, because: 00047 00048 - You don't necessarily know who you're sharing space with. If I 00049 stick eight bytes of text in a bcache, and then stick an eight-byte 00050 structure in the same bcache, there's no guarantee those two 00051 objects don't actually comprise the same sequence of bytes. If 00052 they happen to, the bcache will use a single byte string for both 00053 of them. Then, modifying the structure will change the string. In 00054 bizarre ways. 00055 00056 - Even if you know for some other reason that all that's okay, 00057 there's another problem. A bcache stores all its strings in a hash 00058 table. If you modify a string's contents, you will probably change 00059 its hash value. This means that the modified string is now in the 00060 wrong place in the hash table, and future bcache probes will never 00061 find it. So by mutating a string, you give up any chance of 00062 sharing its space with future duplicates. 00063 00064 00065 Size of bcache VS hashtab: 00066 00067 For bcache, the most critical cost is size (or more exactly the 00068 overhead added by the bcache). It turns out that the bcache is 00069 remarkably efficient. 00070 00071 Assuming a 32-bit system (the hash table slots are 4 bytes), 00072 ignoring alignment, and limit strings to 255 bytes (1 byte length) 00073 we get ... 00074 00075 bcache: This uses a separate linked list to track the hash chain. 00076 The numbers show roughly 100% occupancy of the hash table and an 00077 average chain length of 4. Spreading the slot cost over the 4 00078 chain elements: 00079 00080 4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes 00081 00082 hashtab: This uses a more traditional re-hash algorithm where the 00083 chain is maintained within the hash table. The table occupancy is 00084 kept below 75% but we'll assume its perfect: 00085 00086 4 (slot) x 4/3 (occupancy) + 1 (length) = 6 1/3 bytes 00087 00088 So a perfect hashtab has just slightly larger than an average 00089 bcache. 00090 00091 It turns out that an average hashtab is far worse. Two things 00092 hurt: 00093 00094 - Hashtab's occupancy is more like 50% (it ranges between 38% and 00095 75%) giving a per slot cost of 4x2 vs 4x4/3. 00096 00097 - the string structure needs to be aligned to 8 bytes which for 00098 hashtab wastes 7 bytes, while for bcache wastes only 3. 00099 00100 This gives: 00101 00102 hashtab: 4 x 2 + 1 + 7 = 16 bytes 00103 00104 bcache 4 / 4 + 1 + 4 + 3 = 9 bytes 00105 00106 The numbers of GDB debugging GDB support this. ~40% vs ~70% overhead. 00107 00108 00109 Speed of bcache VS hashtab (the half hash hack): 00110 00111 While hashtab has a typical chain length of 1, bcache has a chain 00112 length of round 4. This means that the bcache will require 00113 something like double the number of compares after that initial 00114 hash. In both cases the comparison takes the form: 00115 00116 a.length == b.length && memcmp (a.data, b.data, a.length) == 0 00117 00118 That is lengths are checked before doing the memcmp. 00119 00120 For GDB debugging GDB, it turned out that all lengths were 24 bytes 00121 (no C++ so only psymbols were cached) and hence, all compares 00122 required a call to memcmp. As a hack, two bytes of padding 00123 (mentioned above) are used to store the upper 16 bits of the 00124 string's hash value and then that is used in the comparison vis: 00125 00126 a.half_hash == b.half_hash && a.length == b.length && memcmp 00127 (a.data, b.data, a.length) 00128 00129 The numbers from GDB debugging GDB show this to be a remarkable 00130 100% effective (only necessary length and memcmp tests being 00131 performed). 00132 00133 Mind you, looking at the wall clock, the same GDB debugging GDB 00134 showed only marginal speed up (0.780 vs 0.773s). Seems GDB is too 00135 busy doing something else :-( 00136 00137 */ 00138 00139 00140 struct bcache; 00141 00142 /* Find a copy of the LENGTH bytes at ADDR in BCACHE. If BCACHE has 00143 never seen those bytes before, add a copy of them to BCACHE. In 00144 either case, return a pointer to BCACHE's copy of that string. 00145 Since the cached value is ment to be read-only, return a const 00146 buffer. */ 00147 extern const void *bcache (const void *addr, int length, 00148 struct bcache *bcache); 00149 00150 /* Like bcache, but if ADDED is not NULL, set *ADDED to true if the 00151 bytes were newly added to the cache, or to false if the bytes were 00152 found in the cache. */ 00153 extern const void *bcache_full (const void *addr, int length, 00154 struct bcache *bcache, int *added); 00155 00156 /* Free all the storage used by BCACHE. */ 00157 extern void bcache_xfree (struct bcache *bcache); 00158 00159 /* Create a new bcache object. */ 00160 extern struct bcache *bcache_xmalloc ( 00161 unsigned long (*hash_function)(const void *, int length), 00162 int (*compare_function)(const void *, const void *, int length)); 00163 00164 /* Print statistics on BCACHE's memory usage and efficacity at 00165 eliminating duplication. TYPE should be a string describing the 00166 kind of data BCACHE holds. Statistics are printed using 00167 `printf_filtered' and its ilk. */ 00168 extern void print_bcache_statistics (struct bcache *bcache, char *type); 00169 extern int bcache_memory_used (struct bcache *bcache); 00170 00171 /* The hash functions */ 00172 extern unsigned long hash(const void *addr, int length); 00173 extern unsigned long hash_continue (const void *addr, int length, 00174 unsigned long h); 00175 00176 #endif /* BCACHE_H */