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