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