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