xref: /aosp_15_r20/external/cronet/base/profiler/metadata_recorder_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 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/profiler/metadata_recorder.h"
6 
7 #include <optional>
8 
9 #include "base/ranges/algorithm.h"
10 #include "base/test/gtest_util.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace base {
15 
operator ==(const MetadataRecorder::Item & lhs,const MetadataRecorder::Item & rhs)16 bool operator==(const MetadataRecorder::Item& lhs,
17                 const MetadataRecorder::Item& rhs) {
18   return lhs.name_hash == rhs.name_hash && lhs.value == rhs.value;
19 }
20 
operator <(const MetadataRecorder::Item & lhs,const MetadataRecorder::Item & rhs)21 bool operator<(const MetadataRecorder::Item& lhs,
22                const MetadataRecorder::Item& rhs) {
23   return lhs.name_hash < rhs.name_hash;
24 }
25 
TEST(MetadataRecorderTest,GetItems_Empty)26 TEST(MetadataRecorderTest, GetItems_Empty) {
27   MetadataRecorder recorder;
28   MetadataRecorder::ItemArray items;
29 
30   EXPECT_EQ(0u, MetadataRecorder::MetadataProvider(&recorder,
31                                                    PlatformThread::CurrentId())
32                     .GetItems(&items));
33   EXPECT_EQ(0u, MetadataRecorder::MetadataProvider(&recorder,
34                                                    PlatformThread::CurrentId())
35                     .GetItems(&items));
36 }
37 
TEST(MetadataRecorderTest,Set_NewNameHash)38 TEST(MetadataRecorderTest, Set_NewNameHash) {
39   MetadataRecorder recorder;
40 
41   recorder.Set(10, std::nullopt, std::nullopt, 20);
42 
43   MetadataRecorder::ItemArray items;
44   size_t item_count;
45   {
46     item_count = MetadataRecorder::MetadataProvider(&recorder,
47                                                     PlatformThread::CurrentId())
48                      .GetItems(&items);
49     ASSERT_EQ(1u, item_count);
50     EXPECT_EQ(10u, items[0].name_hash);
51     EXPECT_FALSE(items[0].key.has_value());
52     EXPECT_FALSE(items[0].thread_id.has_value());
53     EXPECT_EQ(20, items[0].value);
54   }
55 
56   recorder.Set(20, std::nullopt, std::nullopt, 30);
57 
58   {
59     item_count = MetadataRecorder::MetadataProvider(&recorder,
60                                                     PlatformThread::CurrentId())
61                      .GetItems(&items);
62     ASSERT_EQ(2u, item_count);
63     EXPECT_EQ(20u, items[1].name_hash);
64     EXPECT_FALSE(items[1].key.has_value());
65     EXPECT_FALSE(items[1].thread_id.has_value());
66     EXPECT_EQ(30, items[1].value);
67   }
68 }
69 
TEST(MetadataRecorderTest,Set_ExistingNameNash)70 TEST(MetadataRecorderTest, Set_ExistingNameNash) {
71   MetadataRecorder recorder;
72   recorder.Set(10, std::nullopt, std::nullopt, 20);
73   recorder.Set(10, std::nullopt, std::nullopt, 30);
74 
75   MetadataRecorder::ItemArray items;
76   size_t item_count =
77       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
78           .GetItems(&items);
79   ASSERT_EQ(1u, item_count);
80   EXPECT_EQ(10u, items[0].name_hash);
81   EXPECT_FALSE(items[0].key.has_value());
82   EXPECT_FALSE(items[0].thread_id.has_value());
83   EXPECT_EQ(30, items[0].value);
84 }
85 
TEST(MetadataRecorderTest,Set_ReAddRemovedNameNash)86 TEST(MetadataRecorderTest, Set_ReAddRemovedNameNash) {
87   MetadataRecorder recorder;
88   MetadataRecorder::ItemArray items;
89   std::vector<MetadataRecorder::Item> expected;
90   for (size_t i = 0; i < items.size(); ++i) {
91     expected.emplace_back(i, std::nullopt, std::nullopt, 0);
92     recorder.Set(i, std::nullopt, std::nullopt, 0);
93   }
94 
95   // By removing an item from a full recorder, re-setting the same item, and
96   // verifying that the item is returned, we can verify that the recorder is
97   // reusing the inactive slot for the same name hash instead of trying (and
98   // failing) to allocate a new slot.
99   recorder.Remove(3, std::nullopt, std::nullopt);
100   recorder.Set(3, std::nullopt, std::nullopt, 0);
101 
102   size_t item_count =
103       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
104           .GetItems(&items);
105   EXPECT_EQ(items.size(), item_count);
106   EXPECT_THAT(expected, ::testing::UnorderedElementsAreArray(items));
107 }
108 
TEST(MetadataRecorderTest,Set_AddPastMaxCount)109 TEST(MetadataRecorderTest, Set_AddPastMaxCount) {
110   MetadataRecorder recorder;
111   MetadataRecorder::ItemArray items;
112   for (size_t i = 0; i < items.size(); ++i) {
113     recorder.Set(i, std::nullopt, std::nullopt, 0);
114   }
115 
116   // This should fail silently.
117   recorder.Set(items.size(), std::nullopt, std::nullopt, 0);
118 }
119 
TEST(MetadataRecorderTest,Set_NulloptKeyIsIndependentOfNonNulloptKey)120 TEST(MetadataRecorderTest, Set_NulloptKeyIsIndependentOfNonNulloptKey) {
121   MetadataRecorder recorder;
122 
123   recorder.Set(10, 100, std::nullopt, 20);
124 
125   MetadataRecorder::ItemArray items;
126   size_t item_count;
127   {
128     item_count = MetadataRecorder::MetadataProvider(&recorder,
129                                                     PlatformThread::CurrentId())
130                      .GetItems(&items);
131     ASSERT_EQ(1u, item_count);
132     EXPECT_EQ(10u, items[0].name_hash);
133     ASSERT_TRUE(items[0].key.has_value());
134     EXPECT_EQ(100, *items[0].key);
135     EXPECT_EQ(20, items[0].value);
136   }
137 
138   recorder.Set(10, std::nullopt, std::nullopt, 30);
139 
140   {
141     item_count = MetadataRecorder::MetadataProvider(&recorder,
142                                                     PlatformThread::CurrentId())
143                      .GetItems(&items);
144     ASSERT_EQ(2u, item_count);
145 
146     EXPECT_EQ(10u, items[0].name_hash);
147     ASSERT_TRUE(items[0].key.has_value());
148     EXPECT_EQ(100, *items[0].key);
149     EXPECT_EQ(20, items[0].value);
150 
151     EXPECT_EQ(10u, items[1].name_hash);
152     EXPECT_FALSE(items[1].key.has_value());
153     EXPECT_EQ(30, items[1].value);
154   }
155 }
156 
TEST(MetadataRecorderTest,Set_ThreadIdIsScoped)157 TEST(MetadataRecorderTest, Set_ThreadIdIsScoped) {
158   MetadataRecorder recorder;
159 
160   recorder.Set(10, std::nullopt, PlatformThread::CurrentId(), 20);
161 
162   MetadataRecorder::ItemArray items;
163   size_t item_count;
164   {
165     item_count = MetadataRecorder::MetadataProvider(&recorder,
166                                                     PlatformThread::CurrentId())
167                      .GetItems(&items);
168     ASSERT_EQ(1u, item_count);
169     EXPECT_EQ(10u, items[0].name_hash);
170     EXPECT_FALSE(items[0].key.has_value());
171     ASSERT_TRUE(items[0].thread_id.has_value());
172     EXPECT_EQ(PlatformThread::CurrentId(), *items[0].thread_id);
173     EXPECT_EQ(20, items[0].value);
174   }
175   {
176     item_count = MetadataRecorder::MetadataProvider(&recorder, kInvalidThreadId)
177                      .GetItems(&items);
178     EXPECT_EQ(0U, item_count);
179   }
180 }
181 
TEST(MetadataRecorderTest,Set_NulloptThreadAndNonNulloptThread)182 TEST(MetadataRecorderTest, Set_NulloptThreadAndNonNulloptThread) {
183   MetadataRecorder recorder;
184 
185   recorder.Set(10, std::nullopt, PlatformThread::CurrentId(), 20);
186   recorder.Set(10, std::nullopt, std::nullopt, 30);
187 
188   MetadataRecorder::ItemArray items;
189   size_t item_count =
190       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
191           .GetItems(&items);
192   ASSERT_EQ(2u, item_count);
193   EXPECT_EQ(10u, items[0].name_hash);
194   EXPECT_FALSE(items[0].key.has_value());
195   ASSERT_TRUE(items[0].thread_id.has_value());
196   EXPECT_EQ(PlatformThread::CurrentId(), *items[0].thread_id);
197   EXPECT_EQ(20, items[0].value);
198 
199   EXPECT_EQ(10u, items[1].name_hash);
200   EXPECT_FALSE(items[1].key.has_value());
201   EXPECT_FALSE(items[1].thread_id.has_value());
202   EXPECT_EQ(30, items[1].value);
203 }
204 
TEST(MetadataRecorderTest,Remove)205 TEST(MetadataRecorderTest, Remove) {
206   MetadataRecorder recorder;
207   recorder.Set(10, std::nullopt, std::nullopt, 20);
208   recorder.Set(30, std::nullopt, std::nullopt, 40);
209   recorder.Set(50, std::nullopt, std::nullopt, 60);
210   recorder.Remove(30, std::nullopt, std::nullopt);
211 
212   MetadataRecorder::ItemArray items;
213   size_t item_count =
214       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
215           .GetItems(&items);
216   ASSERT_EQ(2u, item_count);
217   EXPECT_EQ(10u, items[0].name_hash);
218   EXPECT_FALSE(items[0].key.has_value());
219   EXPECT_EQ(20, items[0].value);
220   EXPECT_EQ(50u, items[1].name_hash);
221   EXPECT_FALSE(items[1].key.has_value());
222   EXPECT_EQ(60, items[1].value);
223 }
224 
TEST(MetadataRecorderTest,Remove_DoesntExist)225 TEST(MetadataRecorderTest, Remove_DoesntExist) {
226   MetadataRecorder recorder;
227   recorder.Set(10, std::nullopt, std::nullopt, 20);
228   recorder.Remove(20, std::nullopt, std::nullopt);
229 
230   MetadataRecorder::ItemArray items;
231   size_t item_count =
232       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
233           .GetItems(&items);
234   ASSERT_EQ(1u, item_count);
235   EXPECT_EQ(10u, items[0].name_hash);
236   EXPECT_FALSE(items[0].key.has_value());
237   EXPECT_EQ(20, items[0].value);
238 }
239 
TEST(MetadataRecorderTest,Remove_NulloptKeyIsIndependentOfNonNulloptKey)240 TEST(MetadataRecorderTest, Remove_NulloptKeyIsIndependentOfNonNulloptKey) {
241   MetadataRecorder recorder;
242 
243   recorder.Set(10, 100, std::nullopt, 20);
244   recorder.Set(10, std::nullopt, std::nullopt, 30);
245 
246   recorder.Remove(10, std::nullopt, std::nullopt);
247 
248   MetadataRecorder::ItemArray items;
249   size_t item_count =
250       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
251           .GetItems(&items);
252   ASSERT_EQ(1u, item_count);
253   EXPECT_EQ(10u, items[0].name_hash);
254   ASSERT_TRUE(items[0].key.has_value());
255   EXPECT_EQ(100, *items[0].key);
256   EXPECT_EQ(20, items[0].value);
257 }
258 
TEST(MetadataRecorderTest,Remove_NulloptThreadIsIndependentOfNonNulloptThread)259 TEST(MetadataRecorderTest,
260      Remove_NulloptThreadIsIndependentOfNonNulloptThread) {
261   MetadataRecorder recorder;
262 
263   recorder.Set(10, std::nullopt, PlatformThread::CurrentId(), 20);
264   recorder.Set(10, std::nullopt, std::nullopt, 30);
265 
266   recorder.Remove(10, std::nullopt, std::nullopt);
267 
268   MetadataRecorder::ItemArray items;
269   size_t item_count =
270       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
271           .GetItems(&items);
272   ASSERT_EQ(1u, item_count);
273   EXPECT_EQ(10u, items[0].name_hash);
274   EXPECT_FALSE(items[0].key.has_value());
275   ASSERT_TRUE(items[0].thread_id.has_value());
276   EXPECT_EQ(PlatformThread::CurrentId(), *items[0].thread_id);
277   EXPECT_EQ(20, items[0].value);
278 }
279 
TEST(MetadataRecorderTest,ReclaimInactiveSlots)280 TEST(MetadataRecorderTest, ReclaimInactiveSlots) {
281   MetadataRecorder recorder;
282 
283   std::set<MetadataRecorder::Item> items_set;
284   // Fill up the metadata map.
285   for (size_t i = 0; i < MetadataRecorder::MAX_METADATA_COUNT; ++i) {
286     recorder.Set(i, std::nullopt, std::nullopt, i);
287     items_set.insert(MetadataRecorder::Item{i, std::nullopt, std::nullopt,
288                                             static_cast<int64_t>(i)});
289   }
290 
291   // Remove every fourth entry to fragment the data.
292   size_t entries_removed = 0;
293   for (size_t i = 3; i < MetadataRecorder::MAX_METADATA_COUNT; i += 4) {
294     recorder.Remove(i, std::nullopt, std::nullopt);
295     ++entries_removed;
296     items_set.erase(MetadataRecorder::Item{i, std::nullopt, std::nullopt,
297                                            static_cast<int64_t>(i)});
298   }
299 
300   // Ensure that the inactive slots are reclaimed to make room for more entries.
301   for (size_t i = 1; i <= entries_removed; ++i) {
302     recorder.Set(i * 100, std::nullopt, std::nullopt, i * 100);
303     items_set.insert(MetadataRecorder::Item{i * 100, std::nullopt, std::nullopt,
304                                             static_cast<int64_t>(i * 100)});
305   }
306 
307   MetadataRecorder::ItemArray items_arr;
308   ranges::copy(items_set, items_arr.begin());
309 
310   MetadataRecorder::ItemArray recorder_items;
311   size_t recorder_item_count =
312       MetadataRecorder::MetadataProvider(&recorder, PlatformThread::CurrentId())
313           .GetItems(&recorder_items);
314   EXPECT_EQ(recorder_item_count, MetadataRecorder::MAX_METADATA_COUNT);
315   EXPECT_THAT(recorder_items, ::testing::UnorderedElementsAreArray(items_arr));
316 }
317 
318 }  // namespace base
319