raw_hash_set.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. // Copyright 2018 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/container/internal/raw_hash_set.h"
  15. #include <atomic>
  16. #include <cassert>
  17. #include <cstddef>
  18. #include <cstdint>
  19. #include <cstring>
  20. #include "absl/base/attributes.h"
  21. #include "absl/base/config.h"
  22. #include "absl/base/dynamic_annotations.h"
  23. #include "absl/base/internal/endian.h"
  24. #include "absl/base/internal/raw_logging.h"
  25. #include "absl/base/optimization.h"
  26. #include "absl/container/internal/container_memory.h"
  27. #include "absl/container/internal/hashtablez_sampler.h"
  28. #include "absl/hash/hash.h"
  29. #include "absl/numeric/bits.h"
  30. namespace absl {
  31. ABSL_NAMESPACE_BEGIN
  32. namespace container_internal {
  33. // Represents a control byte corresponding to a full slot with arbitrary hash.
  34. constexpr ctrl_t ZeroCtrlT() { return static_cast<ctrl_t>(0); }
  35. // We have space for `growth_info` before a single block of control bytes. A
  36. // single block of empty control bytes for tables without any slots allocated.
  37. // This enables removing a branch in the hot path of find(). In order to ensure
  38. // that the control bytes are aligned to 16, we have 16 bytes before the control
  39. // bytes even though growth_info only needs 8.
  40. alignas(16) ABSL_CONST_INIT ABSL_DLL const ctrl_t kEmptyGroup[32] = {
  41. ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
  42. ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
  43. ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
  44. ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(), ZeroCtrlT(),
  45. ctrl_t::kSentinel, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
  46. ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
  47. ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
  48. ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty};
  49. // We need one full byte followed by a sentinel byte for iterator::operator++ to
  50. // work. We have a full group after kSentinel to be safe (in case operator++ is
  51. // changed to read a full group).
  52. ABSL_CONST_INIT ABSL_DLL const ctrl_t kSooControl[17] = {
  53. ZeroCtrlT(), ctrl_t::kSentinel, ZeroCtrlT(), ctrl_t::kEmpty,
  54. ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
  55. ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
  56. ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty, ctrl_t::kEmpty,
  57. ctrl_t::kEmpty};
  58. static_assert(NumControlBytes(SooCapacity()) <= 17,
  59. "kSooControl capacity too small");
  60. #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
  61. constexpr size_t Group::kWidth;
  62. #endif
  63. namespace {
  64. // Returns "random" seed.
  65. inline size_t RandomSeed() {
  66. #ifdef ABSL_HAVE_THREAD_LOCAL
  67. static thread_local size_t counter = 0;
  68. // On Linux kernels >= 5.4 the MSAN runtime has a false-positive when
  69. // accessing thread local storage data from loaded libraries
  70. // (https://github.com/google/sanitizers/issues/1265), for this reason counter
  71. // needs to be annotated as initialized.
  72. ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(&counter, sizeof(size_t));
  73. size_t value = ++counter;
  74. #else // ABSL_HAVE_THREAD_LOCAL
  75. static std::atomic<size_t> counter(0);
  76. size_t value = counter.fetch_add(1, std::memory_order_relaxed);
  77. #endif // ABSL_HAVE_THREAD_LOCAL
  78. return value ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(&counter));
  79. }
  80. bool ShouldRehashForBugDetection(const ctrl_t* ctrl, size_t capacity) {
  81. // Note: we can't use the abseil-random library because abseil-random
  82. // depends on swisstable. We want to return true with probability
  83. // `min(1, RehashProbabilityConstant() / capacity())`. In order to do this,
  84. // we probe based on a random hash and see if the offset is less than
  85. // RehashProbabilityConstant().
  86. return probe(ctrl, capacity, absl::HashOf(RandomSeed())).offset() <
  87. RehashProbabilityConstant();
  88. }
  89. // Find a non-deterministic hash for single group table.
  90. // Last two bits are used to find a position for a newly inserted element after
  91. // resize.
  92. // This function is mixing all bits of hash and control pointer to maximize
  93. // entropy.
  94. size_t SingleGroupTableH1(size_t hash, ctrl_t* control) {
  95. return static_cast<size_t>(absl::popcount(
  96. hash ^ static_cast<size_t>(reinterpret_cast<uintptr_t>(control))));
  97. }
  98. } // namespace
  99. GenerationType* EmptyGeneration() {
  100. if (SwisstableGenerationsEnabled()) {
  101. constexpr size_t kNumEmptyGenerations = 1024;
  102. static constexpr GenerationType kEmptyGenerations[kNumEmptyGenerations]{};
  103. return const_cast<GenerationType*>(
  104. &kEmptyGenerations[RandomSeed() % kNumEmptyGenerations]);
  105. }
  106. return nullptr;
  107. }
  108. bool CommonFieldsGenerationInfoEnabled::
  109. should_rehash_for_bug_detection_on_insert(const ctrl_t* ctrl,
  110. size_t capacity) const {
  111. if (reserved_growth_ == kReservedGrowthJustRanOut) return true;
  112. if (reserved_growth_ > 0) return false;
  113. return ShouldRehashForBugDetection(ctrl, capacity);
  114. }
  115. bool CommonFieldsGenerationInfoEnabled::should_rehash_for_bug_detection_on_move(
  116. const ctrl_t* ctrl, size_t capacity) const {
  117. return ShouldRehashForBugDetection(ctrl, capacity);
  118. }
  119. bool ShouldInsertBackwardsForDebug(size_t capacity, size_t hash,
  120. const ctrl_t* ctrl) {
  121. // To avoid problems with weak hashes and single bit tests, we use % 13.
  122. // TODO(kfm,sbenza): revisit after we do unconditional mixing
  123. return !is_small(capacity) && (H1(hash, ctrl) ^ RandomSeed()) % 13 > 6;
  124. }
  125. size_t PrepareInsertAfterSoo(size_t hash, size_t slot_size,
  126. CommonFields& common) {
  127. assert(common.capacity() == NextCapacity(SooCapacity()));
  128. // After resize from capacity 1 to 3, we always have exactly the slot with
  129. // index 1 occupied, so we need to insert either at index 0 or index 2.
  130. assert(HashSetResizeHelper::SooSlotIndex() == 1);
  131. PrepareInsertCommon(common);
  132. const size_t offset = SingleGroupTableH1(hash, common.control()) & 2;
  133. common.growth_info().OverwriteEmptyAsFull();
  134. SetCtrlInSingleGroupTable(common, offset, H2(hash), slot_size);
  135. common.infoz().RecordInsert(hash, /*distance_from_desired=*/0);
  136. return offset;
  137. }
  138. void ConvertDeletedToEmptyAndFullToDeleted(ctrl_t* ctrl, size_t capacity) {
  139. assert(ctrl[capacity] == ctrl_t::kSentinel);
  140. assert(IsValidCapacity(capacity));
  141. for (ctrl_t* pos = ctrl; pos < ctrl + capacity; pos += Group::kWidth) {
  142. Group{pos}.ConvertSpecialToEmptyAndFullToDeleted(pos);
  143. }
  144. // Copy the cloned ctrl bytes.
  145. std::memcpy(ctrl + capacity + 1, ctrl, NumClonedBytes());
  146. ctrl[capacity] = ctrl_t::kSentinel;
  147. }
  148. // Extern template instantiation for inline function.
  149. template FindInfo find_first_non_full(const CommonFields&, size_t);
  150. FindInfo find_first_non_full_outofline(const CommonFields& common,
  151. size_t hash) {
  152. return find_first_non_full(common, hash);
  153. }
  154. namespace {
  155. // Returns the address of the slot just after slot assuming each slot has the
  156. // specified size.
  157. static inline void* NextSlot(void* slot, size_t slot_size) {
  158. return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) + slot_size);
  159. }
  160. // Returns the address of the slot just before slot assuming each slot has the
  161. // specified size.
  162. static inline void* PrevSlot(void* slot, size_t slot_size) {
  163. return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(slot) - slot_size);
  164. }
  165. // Finds guaranteed to exists empty slot from the given position.
  166. // NOTE: this function is almost never triggered inside of the
  167. // DropDeletesWithoutResize, so we keep it simple.
  168. // The table is rather sparse, so empty slot will be found very quickly.
  169. size_t FindEmptySlot(size_t start, size_t end, const ctrl_t* ctrl) {
  170. for (size_t i = start; i < end; ++i) {
  171. if (IsEmpty(ctrl[i])) {
  172. return i;
  173. }
  174. }
  175. assert(false && "no empty slot");
  176. return ~size_t{};
  177. }
  178. void DropDeletesWithoutResize(CommonFields& common,
  179. const PolicyFunctions& policy) {
  180. void* set = &common;
  181. void* slot_array = common.slot_array();
  182. const size_t capacity = common.capacity();
  183. assert(IsValidCapacity(capacity));
  184. assert(!is_small(capacity));
  185. // Algorithm:
  186. // - mark all DELETED slots as EMPTY
  187. // - mark all FULL slots as DELETED
  188. // - for each slot marked as DELETED
  189. // hash = Hash(element)
  190. // target = find_first_non_full(hash)
  191. // if target is in the same group
  192. // mark slot as FULL
  193. // else if target is EMPTY
  194. // transfer element to target
  195. // mark slot as EMPTY
  196. // mark target as FULL
  197. // else if target is DELETED
  198. // swap current element with target element
  199. // mark target as FULL
  200. // repeat procedure for current slot with moved from element (target)
  201. ctrl_t* ctrl = common.control();
  202. ConvertDeletedToEmptyAndFullToDeleted(ctrl, capacity);
  203. const void* hash_fn = policy.hash_fn(common);
  204. auto hasher = policy.hash_slot;
  205. auto transfer = policy.transfer;
  206. const size_t slot_size = policy.slot_size;
  207. size_t total_probe_length = 0;
  208. void* slot_ptr = SlotAddress(slot_array, 0, slot_size);
  209. // The index of an empty slot that can be used as temporary memory for
  210. // the swap operation.
  211. constexpr size_t kUnknownId = ~size_t{};
  212. size_t tmp_space_id = kUnknownId;
  213. for (size_t i = 0; i != capacity;
  214. ++i, slot_ptr = NextSlot(slot_ptr, slot_size)) {
  215. assert(slot_ptr == SlotAddress(slot_array, i, slot_size));
  216. if (IsEmpty(ctrl[i])) {
  217. tmp_space_id = i;
  218. continue;
  219. }
  220. if (!IsDeleted(ctrl[i])) continue;
  221. const size_t hash = (*hasher)(hash_fn, slot_ptr);
  222. const FindInfo target = find_first_non_full(common, hash);
  223. const size_t new_i = target.offset;
  224. total_probe_length += target.probe_length;
  225. // Verify if the old and new i fall within the same group wrt the hash.
  226. // If they do, we don't need to move the object as it falls already in the
  227. // best probe we can.
  228. const size_t probe_offset = probe(common, hash).offset();
  229. const auto probe_index = [probe_offset, capacity](size_t pos) {
  230. return ((pos - probe_offset) & capacity) / Group::kWidth;
  231. };
  232. // Element doesn't move.
  233. if (ABSL_PREDICT_TRUE(probe_index(new_i) == probe_index(i))) {
  234. SetCtrl(common, i, H2(hash), slot_size);
  235. continue;
  236. }
  237. void* new_slot_ptr = SlotAddress(slot_array, new_i, slot_size);
  238. if (IsEmpty(ctrl[new_i])) {
  239. // Transfer element to the empty spot.
  240. // SetCtrl poisons/unpoisons the slots so we have to call it at the
  241. // right time.
  242. SetCtrl(common, new_i, H2(hash), slot_size);
  243. (*transfer)(set, new_slot_ptr, slot_ptr);
  244. SetCtrl(common, i, ctrl_t::kEmpty, slot_size);
  245. // Initialize or change empty space id.
  246. tmp_space_id = i;
  247. } else {
  248. assert(IsDeleted(ctrl[new_i]));
  249. SetCtrl(common, new_i, H2(hash), slot_size);
  250. // Until we are done rehashing, DELETED marks previously FULL slots.
  251. if (tmp_space_id == kUnknownId) {
  252. tmp_space_id = FindEmptySlot(i + 1, capacity, ctrl);
  253. }
  254. void* tmp_space = SlotAddress(slot_array, tmp_space_id, slot_size);
  255. SanitizerUnpoisonMemoryRegion(tmp_space, slot_size);
  256. // Swap i and new_i elements.
  257. (*transfer)(set, tmp_space, new_slot_ptr);
  258. (*transfer)(set, new_slot_ptr, slot_ptr);
  259. (*transfer)(set, slot_ptr, tmp_space);
  260. SanitizerPoisonMemoryRegion(tmp_space, slot_size);
  261. // repeat the processing of the ith slot
  262. --i;
  263. slot_ptr = PrevSlot(slot_ptr, slot_size);
  264. }
  265. }
  266. ResetGrowthLeft(common);
  267. common.infoz().RecordRehash(total_probe_length);
  268. }
  269. static bool WasNeverFull(CommonFields& c, size_t index) {
  270. if (is_single_group(c.capacity())) {
  271. return true;
  272. }
  273. const size_t index_before = (index - Group::kWidth) & c.capacity();
  274. const auto empty_after = Group(c.control() + index).MaskEmpty();
  275. const auto empty_before = Group(c.control() + index_before).MaskEmpty();
  276. // We count how many consecutive non empties we have to the right and to the
  277. // left of `it`. If the sum is >= kWidth then there is at least one probe
  278. // window that might have seen a full group.
  279. return empty_before && empty_after &&
  280. static_cast<size_t>(empty_after.TrailingZeros()) +
  281. empty_before.LeadingZeros() <
  282. Group::kWidth;
  283. }
  284. } // namespace
  285. void EraseMetaOnly(CommonFields& c, size_t index, size_t slot_size) {
  286. assert(IsFull(c.control()[index]) && "erasing a dangling iterator");
  287. c.decrement_size();
  288. c.infoz().RecordErase();
  289. if (WasNeverFull(c, index)) {
  290. SetCtrl(c, index, ctrl_t::kEmpty, slot_size);
  291. c.growth_info().OverwriteFullAsEmpty();
  292. return;
  293. }
  294. c.growth_info().OverwriteFullAsDeleted();
  295. SetCtrl(c, index, ctrl_t::kDeleted, slot_size);
  296. }
  297. void ClearBackingArray(CommonFields& c, const PolicyFunctions& policy,
  298. bool reuse, bool soo_enabled) {
  299. c.set_size(0);
  300. if (reuse) {
  301. assert(!soo_enabled || c.capacity() > SooCapacity());
  302. ResetCtrl(c, policy.slot_size);
  303. ResetGrowthLeft(c);
  304. c.infoz().RecordStorageChanged(0, c.capacity());
  305. } else {
  306. // We need to record infoz before calling dealloc, which will unregister
  307. // infoz.
  308. c.infoz().RecordClearedReservation();
  309. c.infoz().RecordStorageChanged(0, soo_enabled ? SooCapacity() : 0);
  310. (*policy.dealloc)(c, policy);
  311. c = soo_enabled ? CommonFields{soo_tag_t{}} : CommonFields{non_soo_tag_t{}};
  312. }
  313. }
  314. void HashSetResizeHelper::GrowIntoSingleGroupShuffleControlBytes(
  315. ctrl_t* __restrict new_ctrl, size_t new_capacity) const {
  316. assert(is_single_group(new_capacity));
  317. constexpr size_t kHalfWidth = Group::kWidth / 2;
  318. ABSL_ASSUME(old_capacity_ < kHalfWidth);
  319. ABSL_ASSUME(old_capacity_ > 0);
  320. static_assert(Group::kWidth == 8 || Group::kWidth == 16,
  321. "Group size is not supported.");
  322. // NOTE: operations are done with compile time known size = 8.
  323. // Compiler optimizes that into single ASM operation.
  324. // Load the bytes from old_capacity. This contains
  325. // - the sentinel byte
  326. // - all the old control bytes
  327. // - the rest is filled with kEmpty bytes
  328. // Example:
  329. // old_ctrl = 012S012EEEEEEEEE...
  330. // copied_bytes = S012EEEE
  331. uint64_t copied_bytes =
  332. absl::little_endian::Load64(old_ctrl() + old_capacity_);
  333. // We change the sentinel byte to kEmpty before storing to both the start of
  334. // the new_ctrl, and past the end of the new_ctrl later for the new cloned
  335. // bytes. Note that this is faster than setting the sentinel byte to kEmpty
  336. // after the copy directly in new_ctrl because we are limited on store
  337. // bandwidth.
  338. static constexpr uint64_t kEmptyXorSentinel =
  339. static_cast<uint8_t>(ctrl_t::kEmpty) ^
  340. static_cast<uint8_t>(ctrl_t::kSentinel);
  341. // Replace the first byte kSentinel with kEmpty.
  342. // Resulting bytes will be shifted by one byte old control blocks.
  343. // Example:
  344. // old_ctrl = 012S012EEEEEEEEE...
  345. // before = S012EEEE
  346. // after = E012EEEE
  347. copied_bytes ^= kEmptyXorSentinel;
  348. if (Group::kWidth == 8) {
  349. // With group size 8, we can grow with two write operations.
  350. assert(old_capacity_ < 8 && "old_capacity_ is too large for group size 8");
  351. absl::little_endian::Store64(new_ctrl, copied_bytes);
  352. static constexpr uint64_t kSentinal64 =
  353. static_cast<uint8_t>(ctrl_t::kSentinel);
  354. // Prepend kSentinel byte to the beginning of copied_bytes.
  355. // We have maximum 3 non-empty bytes at the beginning of copied_bytes for
  356. // group size 8.
  357. // Example:
  358. // old_ctrl = 012S012EEEE
  359. // before = E012EEEE
  360. // after = SE012EEE
  361. copied_bytes = (copied_bytes << 8) ^ kSentinal64;
  362. absl::little_endian::Store64(new_ctrl + new_capacity, copied_bytes);
  363. // Example for capacity 3:
  364. // old_ctrl = 012S012EEEE
  365. // After the first store:
  366. // >!
  367. // new_ctrl = E012EEEE???????
  368. // After the second store:
  369. // >!
  370. // new_ctrl = E012EEESE012EEE
  371. return;
  372. }
  373. assert(Group::kWidth == 16);
  374. // Fill the second half of the main control bytes with kEmpty.
  375. // For small capacity that may write into mirrored control bytes.
  376. // It is fine as we will overwrite all the bytes later.
  377. std::memset(new_ctrl + kHalfWidth, static_cast<int8_t>(ctrl_t::kEmpty),
  378. kHalfWidth);
  379. // Fill the second half of the mirrored control bytes with kEmpty.
  380. std::memset(new_ctrl + new_capacity + kHalfWidth,
  381. static_cast<int8_t>(ctrl_t::kEmpty), kHalfWidth);
  382. // Copy the first half of the non-mirrored control bytes.
  383. absl::little_endian::Store64(new_ctrl, copied_bytes);
  384. new_ctrl[new_capacity] = ctrl_t::kSentinel;
  385. // Copy the first half of the mirrored control bytes.
  386. absl::little_endian::Store64(new_ctrl + new_capacity + 1, copied_bytes);
  387. // Example for growth capacity 1->3:
  388. // old_ctrl = 0S0EEEEEEEEEEEEEE
  389. // new_ctrl at the end = E0ESE0EEEEEEEEEEEEE
  390. // >!
  391. // new_ctrl after 1st memset = ????????EEEEEEEE???
  392. // >!
  393. // new_ctrl after 2nd memset = ????????EEEEEEEEEEE
  394. // >!
  395. // new_ctrl after 1st store = E0EEEEEEEEEEEEEEEEE
  396. // new_ctrl after kSentinel = E0ESEEEEEEEEEEEEEEE
  397. // >!
  398. // new_ctrl after 2nd store = E0ESE0EEEEEEEEEEEEE
  399. // Example for growth capacity 3->7:
  400. // old_ctrl = 012S012EEEEEEEEEEEE
  401. // new_ctrl at the end = E012EEESE012EEEEEEEEEEE
  402. // >!
  403. // new_ctrl after 1st memset = ????????EEEEEEEE???????
  404. // >!
  405. // new_ctrl after 2nd memset = ????????EEEEEEEEEEEEEEE
  406. // >!
  407. // new_ctrl after 1st store = E012EEEEEEEEEEEEEEEEEEE
  408. // new_ctrl after kSentinel = E012EEESEEEEEEEEEEEEEEE
  409. // >!
  410. // new_ctrl after 2nd store = E012EEESE012EEEEEEEEEEE
  411. // Example for growth capacity 7->15:
  412. // old_ctrl = 0123456S0123456EEEEEEEE
  413. // new_ctrl at the end = E0123456EEEEEEESE0123456EEEEEEE
  414. // >!
  415. // new_ctrl after 1st memset = ????????EEEEEEEE???????????????
  416. // >!
  417. // new_ctrl after 2nd memset = ????????EEEEEEEE???????EEEEEEEE
  418. // >!
  419. // new_ctrl after 1st store = E0123456EEEEEEEE???????EEEEEEEE
  420. // new_ctrl after kSentinel = E0123456EEEEEEES???????EEEEEEEE
  421. // >!
  422. // new_ctrl after 2nd store = E0123456EEEEEEESE0123456EEEEEEE
  423. }
  424. void HashSetResizeHelper::InitControlBytesAfterSoo(ctrl_t* new_ctrl, ctrl_t h2,
  425. size_t new_capacity) {
  426. assert(is_single_group(new_capacity));
  427. std::memset(new_ctrl, static_cast<int8_t>(ctrl_t::kEmpty),
  428. NumControlBytes(new_capacity));
  429. assert(HashSetResizeHelper::SooSlotIndex() == 1);
  430. // This allows us to avoid branching on had_soo_slot_.
  431. assert(had_soo_slot_ || h2 == ctrl_t::kEmpty);
  432. new_ctrl[1] = new_ctrl[new_capacity + 2] = h2;
  433. new_ctrl[new_capacity] = ctrl_t::kSentinel;
  434. }
  435. void HashSetResizeHelper::GrowIntoSingleGroupShuffleTransferableSlots(
  436. void* new_slots, size_t slot_size) const {
  437. ABSL_ASSUME(old_capacity_ > 0);
  438. SanitizerUnpoisonMemoryRegion(old_slots(), slot_size * old_capacity_);
  439. std::memcpy(SlotAddress(new_slots, 1, slot_size), old_slots(),
  440. slot_size * old_capacity_);
  441. }
  442. void HashSetResizeHelper::GrowSizeIntoSingleGroupTransferable(
  443. CommonFields& c, size_t slot_size) {
  444. assert(old_capacity_ < Group::kWidth / 2);
  445. assert(is_single_group(c.capacity()));
  446. assert(IsGrowingIntoSingleGroupApplicable(old_capacity_, c.capacity()));
  447. GrowIntoSingleGroupShuffleControlBytes(c.control(), c.capacity());
  448. GrowIntoSingleGroupShuffleTransferableSlots(c.slot_array(), slot_size);
  449. // We poison since GrowIntoSingleGroupShuffleTransferableSlots
  450. // may leave empty slots unpoisoned.
  451. PoisonSingleGroupEmptySlots(c, slot_size);
  452. }
  453. void HashSetResizeHelper::TransferSlotAfterSoo(CommonFields& c,
  454. size_t slot_size) {
  455. assert(was_soo_);
  456. assert(had_soo_slot_);
  457. assert(is_single_group(c.capacity()));
  458. std::memcpy(SlotAddress(c.slot_array(), SooSlotIndex(), slot_size),
  459. old_soo_data(), slot_size);
  460. PoisonSingleGroupEmptySlots(c, slot_size);
  461. }
  462. namespace {
  463. // Called whenever the table needs to vacate empty slots either by removing
  464. // tombstones via rehash or growth.
  465. ABSL_ATTRIBUTE_NOINLINE
  466. FindInfo FindInsertPositionWithGrowthOrRehash(CommonFields& common, size_t hash,
  467. const PolicyFunctions& policy) {
  468. const size_t cap = common.capacity();
  469. if (cap > Group::kWidth &&
  470. // Do these calculations in 64-bit to avoid overflow.
  471. common.size() * uint64_t{32} <= cap * uint64_t{25}) {
  472. // Squash DELETED without growing if there is enough capacity.
  473. //
  474. // Rehash in place if the current size is <= 25/32 of capacity.
  475. // Rationale for such a high factor: 1) DropDeletesWithoutResize() is
  476. // faster than resize, and 2) it takes quite a bit of work to add
  477. // tombstones. In the worst case, seems to take approximately 4
  478. // insert/erase pairs to create a single tombstone and so if we are
  479. // rehashing because of tombstones, we can afford to rehash-in-place as
  480. // long as we are reclaiming at least 1/8 the capacity without doing more
  481. // than 2X the work. (Where "work" is defined to be size() for rehashing
  482. // or rehashing in place, and 1 for an insert or erase.) But rehashing in
  483. // place is faster per operation than inserting or even doubling the size
  484. // of the table, so we actually afford to reclaim even less space from a
  485. // resize-in-place. The decision is to rehash in place if we can reclaim
  486. // at about 1/8th of the usable capacity (specifically 3/28 of the
  487. // capacity) which means that the total cost of rehashing will be a small
  488. // fraction of the total work.
  489. //
  490. // Here is output of an experiment using the BM_CacheInSteadyState
  491. // benchmark running the old case (where we rehash-in-place only if we can
  492. // reclaim at least 7/16*capacity) vs. this code (which rehashes in place
  493. // if we can recover 3/32*capacity).
  494. //
  495. // Note that although in the worst-case number of rehashes jumped up from
  496. // 15 to 190, but the number of operations per second is almost the same.
  497. //
  498. // Abridged output of running BM_CacheInSteadyState benchmark from
  499. // raw_hash_set_benchmark. N is the number of insert/erase operations.
  500. //
  501. // | OLD (recover >= 7/16 | NEW (recover >= 3/32)
  502. // size | N/s LoadFactor NRehashes | N/s LoadFactor NRehashes
  503. // 448 | 145284 0.44 18 | 140118 0.44 19
  504. // 493 | 152546 0.24 11 | 151417 0.48 28
  505. // 538 | 151439 0.26 11 | 151152 0.53 38
  506. // 583 | 151765 0.28 11 | 150572 0.57 50
  507. // 628 | 150241 0.31 11 | 150853 0.61 66
  508. // 672 | 149602 0.33 12 | 150110 0.66 90
  509. // 717 | 149998 0.35 12 | 149531 0.70 129
  510. // 762 | 149836 0.37 13 | 148559 0.74 190
  511. // 807 | 149736 0.39 14 | 151107 0.39 14
  512. // 852 | 150204 0.42 15 | 151019 0.42 15
  513. DropDeletesWithoutResize(common, policy);
  514. } else {
  515. // Otherwise grow the container.
  516. policy.resize(common, NextCapacity(cap), HashtablezInfoHandle{});
  517. }
  518. // This function is typically called with tables containing deleted slots.
  519. // The table will be big and `FindFirstNonFullAfterResize` will always
  520. // fallback to `find_first_non_full`. So using `find_first_non_full` directly.
  521. return find_first_non_full(common, hash);
  522. }
  523. } // namespace
  524. const void* GetHashRefForEmptyHasher(const CommonFields& common) {
  525. // Empty base optimization typically make the empty base class address to be
  526. // the same as the first address of the derived class object.
  527. // But we generally assume that for empty hasher we can return any valid
  528. // pointer.
  529. return &common;
  530. }
  531. FindInfo HashSetResizeHelper::FindFirstNonFullAfterResize(const CommonFields& c,
  532. size_t old_capacity,
  533. size_t hash) {
  534. size_t new_capacity = c.capacity();
  535. if (!IsGrowingIntoSingleGroupApplicable(old_capacity, new_capacity)) {
  536. return find_first_non_full(c, hash);
  537. }
  538. // We put the new element either at the beginning or at the end of the table
  539. // with approximately equal probability.
  540. size_t offset =
  541. SingleGroupTableH1(hash, c.control()) & 1 ? 0 : new_capacity - 1;
  542. assert(IsEmpty(c.control()[offset]));
  543. return FindInfo{offset, 0};
  544. }
  545. size_t PrepareInsertNonSoo(CommonFields& common, size_t hash, FindInfo target,
  546. const PolicyFunctions& policy) {
  547. // When there are no deleted slots in the table
  548. // and growth_left is positive, we can insert at the first
  549. // empty slot in the probe sequence (target).
  550. const bool use_target_hint =
  551. // Optimization is disabled when generations are enabled.
  552. // We have to rehash even sparse tables randomly in such mode.
  553. !SwisstableGenerationsEnabled() &&
  554. common.growth_info().HasNoDeletedAndGrowthLeft();
  555. if (ABSL_PREDICT_FALSE(!use_target_hint)) {
  556. // Notes about optimized mode when generations are disabled:
  557. // We do not enter this branch if table has no deleted slots
  558. // and growth_left is positive.
  559. // We enter this branch in the following cases listed in decreasing
  560. // frequency:
  561. // 1. Table without deleted slots (>95% cases) that needs to be resized.
  562. // 2. Table with deleted slots that has space for the inserting element.
  563. // 3. Table with deleted slots that needs to be rehashed or resized.
  564. if (ABSL_PREDICT_TRUE(common.growth_info().HasNoGrowthLeftAndNoDeleted())) {
  565. const size_t old_capacity = common.capacity();
  566. policy.resize(common, NextCapacity(old_capacity), HashtablezInfoHandle{});
  567. target = HashSetResizeHelper::FindFirstNonFullAfterResize(
  568. common, old_capacity, hash);
  569. } else {
  570. // Note: the table may have no deleted slots here when generations
  571. // are enabled.
  572. const bool rehash_for_bug_detection =
  573. common.should_rehash_for_bug_detection_on_insert();
  574. if (rehash_for_bug_detection) {
  575. // Move to a different heap allocation in order to detect bugs.
  576. const size_t cap = common.capacity();
  577. policy.resize(common,
  578. common.growth_left() > 0 ? cap : NextCapacity(cap),
  579. HashtablezInfoHandle{});
  580. }
  581. if (ABSL_PREDICT_TRUE(common.growth_left() > 0)) {
  582. target = find_first_non_full(common, hash);
  583. } else {
  584. target = FindInsertPositionWithGrowthOrRehash(common, hash, policy);
  585. }
  586. }
  587. }
  588. PrepareInsertCommon(common);
  589. common.growth_info().OverwriteControlAsFull(common.control()[target.offset]);
  590. SetCtrl(common, target.offset, H2(hash), policy.slot_size);
  591. common.infoz().RecordInsert(hash, target.probe_length);
  592. return target.offset;
  593. }
  594. void HashTableSizeOverflow() {
  595. ABSL_RAW_LOG(FATAL, "Hash table size overflow");
  596. }
  597. } // namespace container_internal
  598. ABSL_NAMESPACE_END
  599. } // namespace absl