bcache.h 8.1 KB

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