• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/trace_event/memory_usage_estimator.h"
6 
7 #include <stdlib.h>
8 
9 #include <string>
10 
11 #include "base/memory/ptr_util.h"
12 #include "build/build_config.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 #if defined(ARCH_CPU_64_BITS)
16 #define EXPECT_EQ_32_64(_, e, a) EXPECT_EQ(e, a)
17 #else
18 #define EXPECT_EQ_32_64(e, _, a) EXPECT_EQ(e, a)
19 #endif
20 
21 namespace base {
22 namespace trace_event {
23 
24 namespace {
25 
26 // Test class with predictable memory usage.
27 class Data {
28  public:
Data(size_t size=17)29   explicit Data(size_t size = 17): size_(size) {
30   }
31 
size() const32   size_t size() const { return size_; }
33 
EstimateMemoryUsage() const34   size_t EstimateMemoryUsage() const {
35     return size_;
36   }
37 
operator <(const Data & other) const38   bool operator < (const Data& other) const {
39     return size_ < other.size_;
40   }
operator ==(const Data & other) const41   bool operator == (const Data& other) const {
42     return size_ == other.size_;
43   }
44 
45   struct Hasher {
operator ()base::trace_event::__anonf48f24f00111::Data::Hasher46     size_t operator () (const Data& data) const {
47       return data.size();
48     }
49   };
50 
51  private:
52   size_t size_;
53 };
54 
55 }  // namespace
56 
57 namespace internal {
58 
59 // This kills variance of bucket_count across STL implementations.
60 template <>
HashMapBucketCountForTesting(size_t)61 size_t HashMapBucketCountForTesting<Data>(size_t) {
62   return 10;
63 }
64 template <>
HashMapBucketCountForTesting(size_t)65 size_t HashMapBucketCountForTesting<std::pair<const Data, short>>(size_t) {
66   return 10;
67 }
68 
69 }  // namespace internal
70 
TEST(EstimateMemoryUsageTest,String)71 TEST(EstimateMemoryUsageTest, String) {
72   std::string string(777, 'a');
73   EXPECT_EQ(string.capacity() + 1, EstimateMemoryUsage(string));
74 }
75 
TEST(EstimateMemoryUsageTest,String16)76 TEST(EstimateMemoryUsageTest, String16) {
77   std::u16string string(777, 'a');
78   EXPECT_EQ(sizeof(char16_t) * (string.capacity() + 1),
79             EstimateMemoryUsage(string));
80 }
81 
TEST(EstimateMemoryUsageTest,Arrays)82 TEST(EstimateMemoryUsageTest, Arrays) {
83   // std::array
84   {
85     std::array<Data, 10> array;
86     EXPECT_EQ(170u, EstimateMemoryUsage(array));
87   }
88 
89   // T[N]
90   {
91     Data array[10];
92     EXPECT_EQ(170u, EstimateMemoryUsage(array));
93   }
94 
95   // C array
96   {
97     struct Item {
98       char payload[10];
99     };
100     Item* array = new Item[7];
101     EXPECT_EQ(70u, EstimateMemoryUsage(array, 7));
102     delete[] array;
103   }
104 }
105 
TEST(EstimateMemoryUsageTest,UniquePtr)106 TEST(EstimateMemoryUsageTest, UniquePtr) {
107   // Empty
108   {
109     std::unique_ptr<Data> ptr;
110     EXPECT_EQ(0u, EstimateMemoryUsage(ptr));
111   }
112 
113   // Not empty
114   {
115     std::unique_ptr<Data> ptr(new Data());
116     EXPECT_EQ_32_64(21u, 25u, EstimateMemoryUsage(ptr));
117   }
118 
119   // With a pointer
120   {
121     std::unique_ptr<Data*> ptr(new Data*());
122     EXPECT_EQ(sizeof(void*), EstimateMemoryUsage(ptr));
123   }
124 
125   // With an array
126   {
127     struct Item {
128       uint32_t payload[10];
129     };
130     std::unique_ptr<Item[]> ptr(new Item[7]);
131     EXPECT_EQ(280u, EstimateMemoryUsage(ptr, 7));
132   }
133 }
134 
TEST(EstimateMemoryUsageTest,Vector)135 TEST(EstimateMemoryUsageTest, Vector) {
136   std::vector<Data> vector;
137   vector.reserve(1000);
138 
139   // For an empty vector we should return memory usage of its buffer
140   size_t capacity = vector.capacity();
141   size_t expected_size = capacity * sizeof(Data);
142   EXPECT_EQ(expected_size, EstimateMemoryUsage(vector));
143 
144   // If vector is not empty, its size should also include memory usages
145   // of all elements.
146   for (size_t i = 0; i != capacity / 2; ++i) {
147     vector.push_back(Data(i));
148     expected_size += EstimateMemoryUsage(vector.back());
149   }
150   EXPECT_EQ(expected_size, EstimateMemoryUsage(vector));
151 }
152 
TEST(EstimateMemoryUsageTest,List)153 TEST(EstimateMemoryUsageTest, List) {
154   struct POD {
155     short data;
156   };
157   std::list<POD> list;
158   for (int i = 0; i != 1000; ++i) {
159     list.push_back(POD());
160   }
161   EXPECT_EQ_32_64(12000u, 24000u, EstimateMemoryUsage(list));
162 }
163 
TEST(EstimateMemoryUsageTest,Set)164 TEST(EstimateMemoryUsageTest, Set) {
165   std::set<std::pair<int, Data>> set;
166   for (int i = 0; i != 1000; ++i) {
167     set.insert({i, Data(i)});
168   }
169   EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(set));
170 }
171 
TEST(EstimateMemoryUsageTest,MultiSet)172 TEST(EstimateMemoryUsageTest, MultiSet) {
173   std::multiset<bool> set;
174   for (int i = 0; i != 1000; ++i) {
175     set.insert((i & 1) != 0);
176   }
177   EXPECT_EQ_32_64(16000u, 32000u, EstimateMemoryUsage(set));
178 }
179 
TEST(EstimateMemoryUsageTest,Map)180 TEST(EstimateMemoryUsageTest, Map) {
181   std::map<Data, int> map;
182   for (int i = 0; i != 1000; ++i) {
183     map.insert({Data(i), i});
184   }
185   EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(map));
186 }
187 
TEST(EstimateMemoryUsageTest,MultiMap)188 TEST(EstimateMemoryUsageTest, MultiMap) {
189   std::multimap<char, Data> map;
190   for (int i = 0; i != 1000; ++i) {
191     map.insert({static_cast<char>(i), Data(i)});
192   }
193   EXPECT_EQ_32_64(523500u, 547500u, EstimateMemoryUsage(map));
194 }
195 
TEST(EstimateMemoryUsageTest,UnorderedSet)196 TEST(EstimateMemoryUsageTest, UnorderedSet) {
197   std::unordered_set<Data, Data::Hasher> set;
198   for (int i = 0; i != 1000; ++i) {
199     set.insert(Data(i));
200   }
201   EXPECT_EQ_32_64(511540u, 523580u, EstimateMemoryUsage(set));
202 }
203 
TEST(EstimateMemoryUsageTest,UnorderedMultiSet)204 TEST(EstimateMemoryUsageTest, UnorderedMultiSet) {
205   std::unordered_multiset<Data, Data::Hasher> set;
206   for (int i = 0; i != 500; ++i) {
207     set.insert(Data(i));
208     set.insert(Data(i));
209   }
210   EXPECT_EQ_32_64(261540u, 273580u, EstimateMemoryUsage(set));
211 }
212 
TEST(EstimateMemoryUsageTest,UnorderedMap)213 TEST(EstimateMemoryUsageTest, UnorderedMap) {
214   std::unordered_map<Data, short, Data::Hasher> map;
215   for (int i = 0; i != 1000; ++i) {
216     map.insert({Data(i), static_cast<short>(i)});
217   }
218   EXPECT_EQ_32_64(515540u, 531580u, EstimateMemoryUsage(map));
219 }
220 
TEST(EstimateMemoryUsageTest,UnorderedMultiMap)221 TEST(EstimateMemoryUsageTest, UnorderedMultiMap) {
222   std::unordered_multimap<Data, short, Data::Hasher> map;
223   for (int i = 0; i != 1000; ++i) {
224     map.insert({Data(i), static_cast<short>(i)});
225   }
226   EXPECT_EQ_32_64(515540u, 531580u, EstimateMemoryUsage(map));
227 }
228 
TEST(EstimateMemoryUsageTest,Deque)229 TEST(EstimateMemoryUsageTest, Deque) {
230   std::deque<Data> deque;
231 
232   // Pick a large value so that platform-specific accounting
233   // for deque's blocks is small compared to usage of all items.
234   constexpr size_t kDataSize = 100000;
235   for (int i = 0; i != 1500; ++i) {
236     deque.push_back(Data(kDataSize));
237   }
238 
239   // Compare against a reasonable minimum (i.e. no overhead).
240   size_t min_expected_usage = deque.size() * (sizeof(Data) + kDataSize);
241   EXPECT_LE(min_expected_usage, EstimateMemoryUsage(deque));
242 }
243 
TEST(EstimateMemoryUsageTest,IsStandardContainerComplexIteratorTest)244 TEST(EstimateMemoryUsageTest, IsStandardContainerComplexIteratorTest) {
245   struct abstract {
246     virtual void method() = 0;
247   };
248 
249   static_assert(
250       internal::IsStandardContainerComplexIterator<std::list<int>::iterator>(),
251       "");
252   static_assert(internal::IsStandardContainerComplexIterator<
253                     std::list<int>::const_iterator>(),
254                 "");
255   static_assert(internal::IsStandardContainerComplexIterator<
256                     std::list<int>::reverse_iterator>(),
257                 "");
258   static_assert(internal::IsStandardContainerComplexIterator<
259                     std::list<int>::const_reverse_iterator>(),
260                 "");
261   static_assert(!internal::IsStandardContainerComplexIterator<int>(), "");
262   static_assert(!internal::IsStandardContainerComplexIterator<abstract*>(), "");
263 }
264 
265 }  // namespace trace_event
266 }  // namespace base
267