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