sample_element_size_test.cc (4675B)
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 15 #include <cstddef> 16 #include <unordered_set> 17 #include <utility> 18 #include <vector> 19 20 #include "gmock/gmock.h" 21 #include "gtest/gtest.h" 22 #include "absl/container/flat_hash_map.h" 23 #include "absl/container/flat_hash_set.h" 24 #include "absl/container/internal/hashtablez_sampler.h" 25 #include "absl/container/node_hash_map.h" 26 #include "absl/container/node_hash_set.h" 27 28 namespace absl { 29 ABSL_NAMESPACE_BEGIN 30 namespace container_internal { 31 namespace { 32 33 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) 34 // Create some tables of type `Table`, then look at all the new 35 // `HashtablezInfo`s to make sure that the `inline_element_size == 36 // expected_element_size`. The `inline_element_size` is the amount of memory 37 // allocated for each slot of a hash table, that is `sizeof(slot_type)`. Add 38 // the new `HashtablezInfo`s to `preexisting_info`. Store all the new tables 39 // into `tables`. 40 template <class Table> 41 void TestInlineElementSize( 42 HashtablezSampler& sampler, 43 // clang-tidy gives a false positive on this declaration. This unordered 44 // set cannot be flat_hash_set, however, since that would introduce a mutex 45 // deadlock. 46 std::unordered_set<const HashtablezInfo*>& preexisting_info, // NOLINT 47 std::vector<Table>& tables, 48 const std::vector<typename Table::value_type>& values, 49 size_t expected_element_size) { 50 EXPECT_GT(values.size(), 0); 51 for (int i = 0; i < 10; ++i) { 52 // We create a new table and must store it somewhere so that when we store 53 // a pointer to the resulting `HashtablezInfo` into `preexisting_info` 54 // that we aren't storing a dangling pointer. 55 tables.emplace_back(); 56 // We must insert elements to get a hashtablez to instantiate. 57 tables.back().insert(values.begin(), values.end()); 58 } 59 size_t new_count = 0; 60 sampler.Iterate([&](const HashtablezInfo& info) { 61 if (preexisting_info.insert(&info).second) { 62 EXPECT_EQ(info.inline_element_size, expected_element_size); 63 ++new_count; 64 } 65 }); 66 // Make sure we actually did get a new hashtablez. 67 EXPECT_GT(new_count, 0); 68 } 69 70 struct bigstruct { 71 char a[1000]; 72 friend bool operator==(const bigstruct& x, const bigstruct& y) { 73 return memcmp(x.a, y.a, sizeof(x.a)) == 0; 74 } 75 template <typename H> 76 friend H AbslHashValue(H h, const bigstruct& c) { 77 return H::combine_contiguous(std::move(h), c.a, sizeof(c.a)); 78 } 79 }; 80 #endif 81 82 TEST(FlatHashMap, SampleElementSize) { 83 #if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE) 84 // Enable sampling even if the prod default is off. 85 SetHashtablezEnabled(true); 86 SetHashtablezSampleParameter(1); 87 TestOnlyRefreshSamplingStateForCurrentThread(); 88 89 auto& sampler = GlobalHashtablezSampler(); 90 std::vector<flat_hash_map<int, bigstruct>> flat_map_tables; 91 std::vector<flat_hash_set<bigstruct>> flat_set_tables; 92 std::vector<node_hash_map<int, bigstruct>> node_map_tables; 93 std::vector<node_hash_set<bigstruct>> node_set_tables; 94 std::vector<bigstruct> set_values = {bigstruct{{0}}, bigstruct{{1}}}; 95 std::vector<std::pair<const int, bigstruct>> map_values = {{0, bigstruct{}}, 96 {1, bigstruct{}}}; 97 98 // clang-tidy gives a false positive on this declaration. This unordered set 99 // cannot be a flat_hash_set, however, since that would introduce a mutex 100 // deadlock. 101 std::unordered_set<const HashtablezInfo*> preexisting_info; // NOLINT 102 sampler.Iterate( 103 [&](const HashtablezInfo& info) { preexisting_info.insert(&info); }); 104 TestInlineElementSize(sampler, preexisting_info, flat_map_tables, map_values, 105 sizeof(int) + sizeof(bigstruct)); 106 TestInlineElementSize(sampler, preexisting_info, node_map_tables, map_values, 107 sizeof(void*)); 108 TestInlineElementSize(sampler, preexisting_info, flat_set_tables, set_values, 109 sizeof(bigstruct)); 110 TestInlineElementSize(sampler, preexisting_info, node_set_tables, set_values, 111 sizeof(void*)); 112 #endif 113 } 114 115 } // namespace 116 } // namespace container_internal 117 ABSL_NAMESPACE_END 118 } // namespace absl