GDB (API)
/home/stan/gdb/src/gdb/bcache.h
Go to the documentation of this file.
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 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines