1 // Copyright 2018 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 "components/metrics/call_stacks/call_stack_profile_metadata.h"
6
7 #include <tuple>
8 #include <utility>
9
10 #include "base/ranges/algorithm.h"
11 #include "base/strings/strcat.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/metrics_proto/sampled_profile.pb.h"
15
16 namespace metrics {
17
18 namespace {
19
20 // Expects that |expected_item| was applied to |samples| at |sample_index| and
21 // |metadata_index|. Because of the "edge-triggered" metadata encoding, this
22 // expectation will be valid for the first sample seeing the item only.
ExpectMetadataApplied(const base::MetadataRecorder::Item & expected_item,const google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> & samples,int sample_index,int metadata_index,const google::protobuf::RepeatedField<uint64_t> & name_hashes)23 void ExpectMetadataApplied(
24 const base::MetadataRecorder::Item& expected_item,
25 const google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>&
26 samples,
27 int sample_index,
28 int metadata_index,
29 const google::protobuf::RepeatedField<uint64_t>& name_hashes) {
30 const std::string index_info =
31 base::StrCat({"at sample_index ", base::NumberToString(sample_index),
32 ", metadata_index ", base::NumberToString(metadata_index)});
33 const int name_hash_index =
34 base::ranges::find(name_hashes, expected_item.name_hash) -
35 name_hashes.begin();
36 ASSERT_NE(name_hash_index, name_hashes.size()) << index_info;
37
38 ASSERT_LT(sample_index, samples.size()) << index_info;
39 const CallStackProfile::StackSample& sample = samples[sample_index];
40 ASSERT_LT(metadata_index, sample.metadata_size()) << index_info;
41 const CallStackProfile::MetadataItem& item = sample.metadata(metadata_index);
42 EXPECT_EQ(name_hash_index, item.name_hash_index()) << index_info;
43
44 EXPECT_EQ(expected_item.key.has_value(), item.has_key()) << index_info;
45 if (expected_item.key.has_value())
46 EXPECT_EQ(*expected_item.key, item.key()) << index_info;
47 EXPECT_EQ(expected_item.value, item.value()) << index_info;
48 }
49
50 // Expects that the |item| was unapplied at |sample|. Because of the
51 // "edge-triggered" metadata encoding, this expectation will be valid for the
52 // sample following the last sample with the item only.
ExpectMetadataUnapplied(const base::MetadataRecorder::Item & expected_item,const google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> & samples,int sample_index,int metadata_index,const google::protobuf::RepeatedField<uint64_t> & name_hashes)53 void ExpectMetadataUnapplied(
54 const base::MetadataRecorder::Item& expected_item,
55 const google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>&
56 samples,
57 int sample_index,
58 int metadata_index,
59 const google::protobuf::RepeatedField<uint64_t>& name_hashes) {
60 const std::string index_info =
61 base::StrCat({"at sample_index ", base::NumberToString(sample_index),
62 ", metadata_index ", base::NumberToString(metadata_index)});
63 const int name_hash_index =
64 base::ranges::find(name_hashes, expected_item.name_hash) -
65 name_hashes.begin();
66 ASSERT_NE(name_hash_index, name_hashes.size()) << index_info;
67
68 ASSERT_LT(sample_index, samples.size()) << index_info;
69 const CallStackProfile::StackSample& sample = samples[sample_index];
70 ASSERT_LT(metadata_index, sample.metadata_size()) << index_info;
71 const CallStackProfile::MetadataItem& item = sample.metadata(metadata_index);
72 EXPECT_EQ(name_hash_index, item.name_hash_index()) << index_info;
73
74 EXPECT_EQ(expected_item.key.has_value(), item.has_key()) << index_info;
75 if (expected_item.key.has_value())
76 EXPECT_EQ(*expected_item.key, item.key()) << index_info;
77 EXPECT_FALSE(item.has_value()) << index_info;
78 }
79
80 } // namespace
81
TEST(CallStackProfileMetadataTest,MetadataRecorder_NoItems)82 TEST(CallStackProfileMetadataTest, MetadataRecorder_NoItems) {
83 base::MetadataRecorder metadata_recorder;
84 CallStackProfileMetadata metadata;
85 google::protobuf::RepeatedField<uint64_t> name_hashes;
86
87 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
88 &metadata_recorder, base::PlatformThread::CurrentId()));
89
90 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
91 metadata.CreateSampleMetadata(&name_hashes);
92
93 ASSERT_EQ(0, name_hashes.size());
94 ASSERT_EQ(0, items.size());
95 }
96
TEST(CallStackProfileMetadataTest,MetadataRecorder_SetItem)97 TEST(CallStackProfileMetadataTest, MetadataRecorder_SetItem) {
98 base::MetadataRecorder metadata_recorder;
99 CallStackProfileMetadata metadata;
100 google::protobuf::RepeatedField<uint64_t> name_hashes;
101
102 metadata_recorder.Set(100, std::nullopt, std::nullopt, 10);
103 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
104 &metadata_recorder, base::PlatformThread::CurrentId()));
105 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
106 metadata.CreateSampleMetadata(&name_hashes);
107
108 ASSERT_EQ(1, name_hashes.size());
109 EXPECT_EQ(100u, name_hashes[0]);
110
111 ASSERT_EQ(1, items.size());
112 EXPECT_EQ(0, items[0].name_hash_index());
113 EXPECT_FALSE(items[0].has_key());
114 EXPECT_EQ(10, items[0].value());
115 }
116
TEST(CallStackProfileMetadataTest,MetadataRecorder_SetKeyedItem)117 TEST(CallStackProfileMetadataTest, MetadataRecorder_SetKeyedItem) {
118 base::MetadataRecorder metadata_recorder;
119 CallStackProfileMetadata metadata;
120 google::protobuf::RepeatedField<uint64_t> name_hashes;
121
122 metadata_recorder.Set(100, 50, std::nullopt, 10);
123 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
124 &metadata_recorder, base::PlatformThread::CurrentId()));
125 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
126 metadata.CreateSampleMetadata(&name_hashes);
127
128 ASSERT_EQ(1, name_hashes.size());
129 EXPECT_EQ(100u, name_hashes[0]);
130
131 ASSERT_EQ(1, items.size());
132 EXPECT_EQ(0, items[0].name_hash_index());
133 EXPECT_TRUE(items[0].has_key());
134 EXPECT_EQ(50, items[0].key());
135 EXPECT_EQ(10, items[0].value());
136 }
137
TEST(CallStackProfileMetadataTest,MetadataRecorder_SetThreadItem)138 TEST(CallStackProfileMetadataTest, MetadataRecorder_SetThreadItem) {
139 base::MetadataRecorder metadata_recorder;
140 CallStackProfileMetadata metadata;
141 google::protobuf::RepeatedField<uint64_t> name_hashes;
142
143 metadata_recorder.Set(100, std::nullopt, base::PlatformThread::CurrentId(),
144 10);
145 metadata_recorder.Set(100, std::nullopt, base::kInvalidThreadId, 20);
146 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
147 &metadata_recorder, base::PlatformThread::CurrentId()));
148 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
149 metadata.CreateSampleMetadata(&name_hashes);
150
151 ASSERT_EQ(1, name_hashes.size());
152 EXPECT_EQ(100u, name_hashes[0]);
153
154 ASSERT_EQ(1, items.size());
155 EXPECT_EQ(0, items[0].name_hash_index());
156 EXPECT_FALSE(items[0].has_key());
157 EXPECT_EQ(10, items[0].value());
158 }
159
TEST(CallStackProfileMetadataTest,MetadataRecorder_RepeatItem)160 TEST(CallStackProfileMetadataTest, MetadataRecorder_RepeatItem) {
161 base::MetadataRecorder metadata_recorder;
162 CallStackProfileMetadata metadata;
163 google::protobuf::RepeatedField<uint64_t> name_hashes;
164
165 metadata_recorder.Set(100, std::nullopt, std::nullopt, 10);
166 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
167 &metadata_recorder, base::PlatformThread::CurrentId()));
168 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
169
170 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
171 &metadata_recorder, base::PlatformThread::CurrentId()));
172 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
173 metadata.CreateSampleMetadata(&name_hashes);
174
175 // The second sample shouldn't have any metadata because it's all the same
176 // as the last sample.
177 EXPECT_EQ(1, name_hashes.size());
178 EXPECT_TRUE(items.empty());
179 }
180
TEST(CallStackProfileMetadataTest,MetadataRecorder_RepeatKeyedItem)181 TEST(CallStackProfileMetadataTest, MetadataRecorder_RepeatKeyedItem) {
182 base::MetadataRecorder metadata_recorder;
183 CallStackProfileMetadata metadata;
184 google::protobuf::RepeatedField<uint64_t> name_hashes;
185
186 metadata_recorder.Set(100, 50, std::nullopt, 10);
187 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
188 &metadata_recorder, base::PlatformThread::CurrentId()));
189 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
190
191 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
192 &metadata_recorder, base::PlatformThread::CurrentId()));
193 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
194 metadata.CreateSampleMetadata(&name_hashes);
195
196 // The second sample shouldn't have any metadata because it's all the same
197 // as the last sample.
198 EXPECT_EQ(1, name_hashes.size());
199 EXPECT_TRUE(items.empty());
200 }
201
TEST(CallStackProfileMetadataTest,MetadataRecorder_ModifiedItem)202 TEST(CallStackProfileMetadataTest, MetadataRecorder_ModifiedItem) {
203 base::MetadataRecorder metadata_recorder;
204 CallStackProfileMetadata metadata;
205 google::protobuf::RepeatedField<uint64_t> name_hashes;
206
207 metadata_recorder.Set(100, std::nullopt, std::nullopt, 10);
208 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
209 &metadata_recorder, base::PlatformThread::CurrentId()));
210 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
211
212 metadata_recorder.Set(100, std::nullopt, std::nullopt, 11);
213 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
214 &metadata_recorder, base::PlatformThread::CurrentId()));
215 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
216 metadata.CreateSampleMetadata(&name_hashes);
217
218 EXPECT_EQ(1, name_hashes.size());
219
220 ASSERT_EQ(1, items.size());
221 EXPECT_EQ(0, items[0].name_hash_index());
222 EXPECT_FALSE(items[0].has_key());
223 EXPECT_EQ(11, items[0].value());
224 }
225
TEST(CallStackProfileMetadataTest,MetadataRecorder_ModifiedKeyedItem)226 TEST(CallStackProfileMetadataTest, MetadataRecorder_ModifiedKeyedItem) {
227 base::MetadataRecorder metadata_recorder;
228 CallStackProfileMetadata metadata;
229 google::protobuf::RepeatedField<uint64_t> name_hashes;
230
231 metadata_recorder.Set(100, 50, std::nullopt, 10);
232 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
233 &metadata_recorder, base::PlatformThread::CurrentId()));
234 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
235
236 metadata_recorder.Set(100, 50, std::nullopt, 11);
237 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
238 &metadata_recorder, base::PlatformThread::CurrentId()));
239 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
240 metadata.CreateSampleMetadata(&name_hashes);
241
242 EXPECT_EQ(1, name_hashes.size());
243
244 ASSERT_EQ(1, items.size());
245 EXPECT_EQ(0, items[0].name_hash_index());
246 EXPECT_TRUE(items[0].has_key());
247 EXPECT_EQ(50, items[0].key());
248 EXPECT_EQ(11, items[0].value());
249 }
250
TEST(CallStackProfileMetadataTest,MetadataRecorder_NewItem)251 TEST(CallStackProfileMetadataTest, MetadataRecorder_NewItem) {
252 base::MetadataRecorder metadata_recorder;
253 CallStackProfileMetadata metadata;
254 google::protobuf::RepeatedField<uint64_t> name_hashes;
255
256 metadata_recorder.Set(100, std::nullopt, std::nullopt, 10);
257 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
258 &metadata_recorder, base::PlatformThread::CurrentId()));
259 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
260
261 metadata_recorder.Set(101, std::nullopt, std::nullopt, 11);
262 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
263 &metadata_recorder, base::PlatformThread::CurrentId()));
264 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
265 metadata.CreateSampleMetadata(&name_hashes);
266
267 ASSERT_EQ(2, name_hashes.size());
268 EXPECT_EQ(101u, name_hashes[1]);
269
270 ASSERT_EQ(1, items.size());
271 EXPECT_EQ(1, items[0].name_hash_index());
272 EXPECT_FALSE(items[0].has_key());
273 EXPECT_EQ(11, items[0].value());
274 }
275
TEST(CallStackProfileMetadataTest,MetadataRecorder_NewKeyedItem)276 TEST(CallStackProfileMetadataTest, MetadataRecorder_NewKeyedItem) {
277 base::MetadataRecorder metadata_recorder;
278 CallStackProfileMetadata metadata;
279 google::protobuf::RepeatedField<uint64_t> name_hashes;
280
281 metadata_recorder.Set(100, 50, std::nullopt, 10);
282 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
283 &metadata_recorder, base::PlatformThread::CurrentId()));
284 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
285
286 metadata_recorder.Set(101, 50, std::nullopt, 11);
287 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
288 &metadata_recorder, base::PlatformThread::CurrentId()));
289 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
290 metadata.CreateSampleMetadata(&name_hashes);
291
292 ASSERT_EQ(2, name_hashes.size());
293 EXPECT_EQ(101u, name_hashes[1]);
294
295 ASSERT_EQ(1, items.size());
296 EXPECT_EQ(1, items[0].name_hash_index());
297 EXPECT_TRUE(items[0].has_key());
298 EXPECT_EQ(50, items[0].key());
299 EXPECT_EQ(11, items[0].value());
300 }
301
TEST(CallStackProfileMetadataTest,MetadataRecorder_RemovedItem)302 TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedItem) {
303 base::MetadataRecorder metadata_recorder;
304 CallStackProfileMetadata metadata;
305 google::protobuf::RepeatedField<uint64_t> name_hashes;
306
307 metadata_recorder.Set(100, std::nullopt, std::nullopt, 10);
308 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
309 &metadata_recorder, base::PlatformThread::CurrentId()));
310 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
311
312 metadata_recorder.Remove(100, std::nullopt, std::nullopt);
313 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
314 &metadata_recorder, base::PlatformThread::CurrentId()));
315 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
316 metadata.CreateSampleMetadata(&name_hashes);
317
318 EXPECT_EQ(1, name_hashes.size());
319
320 ASSERT_EQ(1, items.size());
321 EXPECT_EQ(0, items[0].name_hash_index());
322 EXPECT_FALSE(items[0].has_key());
323 EXPECT_FALSE(items[0].has_value());
324 }
325
TEST(CallStackProfileMetadataTest,MetadataRecorder_RemovedKeyedItem)326 TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedKeyedItem) {
327 base::MetadataRecorder metadata_recorder;
328 CallStackProfileMetadata metadata;
329 google::protobuf::RepeatedField<uint64_t> name_hashes;
330
331 metadata_recorder.Set(100, 50, std::nullopt, 10);
332 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
333 &metadata_recorder, base::PlatformThread::CurrentId()));
334 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
335
336 metadata_recorder.Remove(100, 50, std::nullopt);
337 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
338 &metadata_recorder, base::PlatformThread::CurrentId()));
339 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
340 metadata.CreateSampleMetadata(&name_hashes);
341
342 EXPECT_EQ(1, name_hashes.size());
343
344 ASSERT_EQ(1, items.size());
345 EXPECT_EQ(0, items[0].name_hash_index());
346 EXPECT_TRUE(items[0].has_key());
347 EXPECT_EQ(50, items[0].key());
348 EXPECT_FALSE(items[0].has_value());
349 }
350
TEST(CallStackProfileMetadataTest,MetadataRecorder_RemovedThreadItem)351 TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedThreadItem) {
352 base::MetadataRecorder metadata_recorder;
353 CallStackProfileMetadata metadata;
354 google::protobuf::RepeatedField<uint64_t> name_hashes;
355
356 metadata_recorder.Set(100, std::nullopt, base::PlatformThread::CurrentId(),
357 10);
358 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
359 &metadata_recorder, base::PlatformThread::CurrentId()));
360 (void)metadata.CreateSampleMetadata(&name_hashes);
361
362 metadata_recorder.Remove(100, std::nullopt,
363 base::PlatformThread::CurrentId());
364 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
365 &metadata_recorder, base::PlatformThread::CurrentId()));
366 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
367 metadata.CreateSampleMetadata(&name_hashes);
368
369 EXPECT_EQ(1, name_hashes.size());
370
371 ASSERT_EQ(1, items.size());
372 EXPECT_EQ(0, items[0].name_hash_index());
373 EXPECT_FALSE(items[0].has_key());
374 EXPECT_FALSE(items[0].has_value());
375 }
376
TEST(CallStackProfileMetadataTest,MetadataRecorder_SetMixedUnkeyedAndKeyedItems)377 TEST(CallStackProfileMetadataTest,
378 MetadataRecorder_SetMixedUnkeyedAndKeyedItems) {
379 base::MetadataRecorder metadata_recorder;
380 CallStackProfileMetadata metadata;
381 google::protobuf::RepeatedField<uint64_t> name_hashes;
382
383 metadata_recorder.Set(100, std::nullopt, std::nullopt, 20);
384 metadata_recorder.Set(100, 50, std::nullopt, 10);
385 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
386 &metadata_recorder, base::PlatformThread::CurrentId()));
387 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
388 metadata.CreateSampleMetadata(&name_hashes);
389
390 ASSERT_EQ(2, items.size());
391
392 EXPECT_EQ(0, items[0].name_hash_index());
393 EXPECT_FALSE(items[0].has_key());
394 EXPECT_EQ(20, items[0].value());
395
396 EXPECT_EQ(0, items[1].name_hash_index());
397 EXPECT_TRUE(items[1].has_key());
398 EXPECT_EQ(50, items[1].key());
399 EXPECT_EQ(10, items[1].value());
400 }
401
TEST(CallStackProfileMetadataTest,MetadataRecorder_RemoveMixedUnkeyedAndKeyedItems)402 TEST(CallStackProfileMetadataTest,
403 MetadataRecorder_RemoveMixedUnkeyedAndKeyedItems) {
404 base::MetadataRecorder metadata_recorder;
405 CallStackProfileMetadata metadata;
406 google::protobuf::RepeatedField<uint64_t> name_hashes;
407
408 metadata_recorder.Set(100, std::nullopt, std::nullopt, 20);
409 metadata_recorder.Set(100, 50, std::nullopt, 10);
410 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
411 &metadata_recorder, base::PlatformThread::CurrentId()));
412 std::ignore = metadata.CreateSampleMetadata(&name_hashes);
413
414 metadata_recorder.Remove(100, std::nullopt, std::nullopt);
415 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
416 &metadata_recorder, base::PlatformThread::CurrentId()));
417 google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items =
418 metadata.CreateSampleMetadata(&name_hashes);
419
420 ASSERT_EQ(1, items.size());
421 EXPECT_EQ(0, items[0].name_hash_index());
422 EXPECT_FALSE(items[0].has_key());
423 EXPECT_FALSE(items[0].has_value());
424 }
425
426 // Checks that applying metadata results in the expected application and removal
427 // of the metadata.
TEST(CallStackProfileMetadataTest,ApplyMetadata_Basic)428 TEST(CallStackProfileMetadataTest, ApplyMetadata_Basic) {
429 CallStackProfileMetadata metadata;
430 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
431 stack_samples;
432 google::protobuf::RepeatedField<uint64_t> name_hashes;
433
434 for (int i = 0; i < 5; i++)
435 stack_samples.Add();
436
437 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
438 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
439 stack_samples.begin() + 4, &stack_samples,
440 &name_hashes);
441
442 ASSERT_EQ(1, name_hashes.size());
443 EXPECT_EQ(3u, name_hashes[0]);
444
445 EXPECT_EQ(0, stack_samples[0].metadata_size());
446
447 // One metadata item should be recorded when the metadata starts.
448 EXPECT_EQ(1, stack_samples[1].metadata_size());
449 ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes);
450
451 EXPECT_EQ(0, stack_samples[2].metadata_size());
452 EXPECT_EQ(0, stack_samples[3].metadata_size());
453
454 // And one item should be recorded without value after the metadata ends.
455 EXPECT_EQ(1, stack_samples[4].metadata_size());
456 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
457 }
458
459 // Checks that metadata items with different name hashes are applied
460 // independently.
TEST(CallStackProfileMetadataTest,ApplyMetadata_DifferentNameHashes)461 TEST(CallStackProfileMetadataTest, ApplyMetadata_DifferentNameHashes) {
462 CallStackProfileMetadata metadata;
463 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
464 stack_samples;
465 google::protobuf::RepeatedField<uint64_t> name_hashes;
466
467 for (int i = 0; i < 5; i++)
468 stack_samples.Add();
469
470 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
471 const base::MetadataRecorder::Item item2(4, 30, std::nullopt, 300);
472 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
473 stack_samples.begin() + 4, &stack_samples,
474 &name_hashes);
475 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
476 stack_samples.begin() + 4, &stack_samples,
477 &name_hashes);
478
479 ASSERT_EQ(2, name_hashes.size());
480 EXPECT_EQ(3u, name_hashes[0]);
481 EXPECT_EQ(4u, name_hashes[1]);
482
483 EXPECT_EQ(0, stack_samples[0].metadata_size());
484
485 EXPECT_EQ(2, stack_samples[1].metadata_size());
486 ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes);
487 ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes);
488
489 EXPECT_EQ(0, stack_samples[2].metadata_size());
490 EXPECT_EQ(0, stack_samples[3].metadata_size());
491
492 EXPECT_EQ(2, stack_samples[4].metadata_size());
493 ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes);
494 ExpectMetadataUnapplied(item2, stack_samples, 4, 1, name_hashes);
495 }
496
497 // Checks that metadata items with different keys are applied independently.
TEST(CallStackProfileMetadataTest,ApplyMetadata_DifferentKeys)498 TEST(CallStackProfileMetadataTest, ApplyMetadata_DifferentKeys) {
499 CallStackProfileMetadata metadata;
500 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
501 stack_samples;
502 google::protobuf::RepeatedField<uint64_t> name_hashes;
503
504 for (int i = 0; i < 5; i++)
505 stack_samples.Add();
506
507 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
508 const base::MetadataRecorder::Item item2(3, 40, std::nullopt, 300);
509 const base::MetadataRecorder::Item item3(3, std::nullopt, std::nullopt, 300);
510 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
511 stack_samples.begin() + 4, &stack_samples,
512 &name_hashes);
513 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
514 stack_samples.begin() + 4, &stack_samples,
515 &name_hashes);
516 metadata.ApplyMetadata(item3, stack_samples.begin() + 1,
517 stack_samples.begin() + 4, &stack_samples,
518 &name_hashes);
519
520 ASSERT_EQ(1, name_hashes.size());
521 EXPECT_EQ(3u, name_hashes[0]);
522
523 EXPECT_EQ(0, stack_samples[0].metadata_size());
524
525 EXPECT_EQ(3, stack_samples[1].metadata_size());
526 ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes);
527 ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes);
528 ExpectMetadataApplied(item3, stack_samples, 1, 2, name_hashes);
529
530 EXPECT_EQ(0, stack_samples[2].metadata_size());
531 EXPECT_EQ(0, stack_samples[3].metadata_size());
532
533 EXPECT_EQ(3, stack_samples[4].metadata_size());
534 ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes);
535 ExpectMetadataUnapplied(item2, stack_samples, 4, 1, name_hashes);
536 ExpectMetadataUnapplied(item3, stack_samples, 4, 2, name_hashes);
537 }
538
539 // Checks that applying to an empty range has no effect.
TEST(CallStackProfileMetadataTest,ApplyMetadata_EmptyRange)540 TEST(CallStackProfileMetadataTest, ApplyMetadata_EmptyRange) {
541 CallStackProfileMetadata metadata;
542 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
543 stack_samples;
544 google::protobuf::RepeatedField<uint64_t> name_hashes;
545
546 for (int i = 0; i < 5; i++)
547 stack_samples.Add();
548
549 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
550 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
551 stack_samples.begin() + 1, &stack_samples,
552 &name_hashes);
553
554 EXPECT_EQ(0, name_hashes.size());
555
556 for (int i = 0; i < 5; i++)
557 EXPECT_EQ(0, stack_samples[i].metadata_size());
558 }
559
560 // Checks that applying metadata through the end is recorded as unapplied on the
561 // next sample taken.
TEST(CallStackProfileMetadataTest,ApplyMetadata_ThroughEnd)562 TEST(CallStackProfileMetadataTest, ApplyMetadata_ThroughEnd) {
563 CallStackProfileMetadata metadata;
564 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
565 stack_samples;
566 google::protobuf::RepeatedField<uint64_t> name_hashes;
567
568 for (int i = 0; i < 5; i++)
569 stack_samples.Add();
570
571 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
572 metadata.ApplyMetadata(item, stack_samples.begin() + 1, stack_samples.end(),
573 &stack_samples, &name_hashes);
574
575 ASSERT_EQ(1, name_hashes.size());
576 EXPECT_EQ(3u, name_hashes[0]);
577
578 EXPECT_EQ(0, stack_samples[0].metadata_size());
579
580 // One metadata item should be recorded when the metadata starts.
581 EXPECT_EQ(1, stack_samples[1].metadata_size());
582 ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes);
583
584 EXPECT_EQ(0, stack_samples[2].metadata_size());
585 EXPECT_EQ(0, stack_samples[3].metadata_size());
586 EXPECT_EQ(0, stack_samples[4].metadata_size());
587
588 base::MetadataRecorder metadata_recorder;
589 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
590 &metadata_recorder, base::PlatformThread::CurrentId()));
591 *stack_samples.Add()->mutable_metadata() =
592 metadata.CreateSampleMetadata(&name_hashes);
593
594 // And the following sample should have the metadata unapplied.
595 ExpectMetadataUnapplied(item, stack_samples, 5, 0, name_hashes);
596 }
597
598 // Checks that metadata is properly applied when mixing RecordMetadata and
599 // ApplyMetadata over the same samples.
TEST(CallStackProfileMetadataTest,ApplyMetadata_WithRecordMetadata)600 TEST(CallStackProfileMetadataTest, ApplyMetadata_WithRecordMetadata) {
601 base::MetadataRecorder metadata_recorder;
602 CallStackProfileMetadata metadata;
603 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
604 stack_samples;
605 google::protobuf::RepeatedField<uint64_t> name_hashes;
606
607 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
608 const base::MetadataRecorder::Item item2(5, 50, std::nullopt, 500);
609
610 stack_samples.Add();
611
612 // Apply then remove item1.
613 metadata_recorder.Set(item1.name_hash, *item1.key, item1.thread_id,
614 item1.value);
615 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
616 &metadata_recorder, base::PlatformThread::CurrentId()));
617 *stack_samples.Add()->mutable_metadata() =
618 metadata.CreateSampleMetadata(&name_hashes);
619
620 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
621 &metadata_recorder, base::PlatformThread::CurrentId()));
622 *stack_samples.Add()->mutable_metadata() =
623 metadata.CreateSampleMetadata(&name_hashes);
624
625 metadata_recorder.Remove(item1.name_hash, *item1.key, item1.thread_id);
626 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
627 &metadata_recorder, base::PlatformThread::CurrentId()));
628 *stack_samples.Add()->mutable_metadata() =
629 metadata.CreateSampleMetadata(&name_hashes);
630
631 stack_samples.Add();
632
633 ASSERT_EQ(5, stack_samples.size());
634
635 // Apply item2.
636 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
637 stack_samples.begin() + 4, &stack_samples,
638 &name_hashes);
639
640 ASSERT_EQ(2, name_hashes.size());
641 EXPECT_EQ(3u, name_hashes[0]);
642 EXPECT_EQ(5u, name_hashes[1]);
643
644 EXPECT_EQ(0, stack_samples[0].metadata_size());
645
646 // Each of the two items should be recorded when their metadata starts.
647 ASSERT_EQ(2, stack_samples[1].metadata_size());
648 ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes);
649 ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes);
650
651 EXPECT_EQ(0, stack_samples[2].metadata_size());
652
653 // The original item should still be present.
654 EXPECT_EQ(1, stack_samples[3].metadata_size());
655 ExpectMetadataUnapplied(item1, stack_samples, 3, 0, name_hashes);
656
657 // And one item should be recorded without value after the metadata ends.
658 EXPECT_EQ(1, stack_samples[4].metadata_size());
659 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
660 }
661
662 // Checks that metadata is properly applied when using ApplyMetadata while
663 // a RecordMetadata-applied value is active.
TEST(CallStackProfileMetadataTest,ApplyMetadata_WithActiveMetadata)664 TEST(CallStackProfileMetadataTest, ApplyMetadata_WithActiveMetadata) {
665 base::MetadataRecorder metadata_recorder;
666 CallStackProfileMetadata metadata;
667 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
668 stack_samples;
669 google::protobuf::RepeatedField<uint64_t> name_hashes;
670
671 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
672 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
673
674 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
675 &metadata_recorder, base::PlatformThread::CurrentId()));
676 *stack_samples.Add()->mutable_metadata() =
677 metadata.CreateSampleMetadata(&name_hashes);
678
679 // Record item1 on an ongoing basis via RecordMetadata.
680 metadata_recorder.Set(item1.name_hash, *item1.key, item1.thread_id,
681 item1.value);
682 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
683 &metadata_recorder, base::PlatformThread::CurrentId()));
684 *stack_samples.Add()->mutable_metadata() =
685 metadata.CreateSampleMetadata(&name_hashes);
686
687 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
688 &metadata_recorder, base::PlatformThread::CurrentId()));
689 *stack_samples.Add()->mutable_metadata() =
690 metadata.CreateSampleMetadata(&name_hashes);
691
692 ASSERT_EQ(3, stack_samples.size());
693
694 // Apply item2 via ApplyMetadata up to the last sample.
695 metadata.ApplyMetadata(item2, stack_samples.begin(), stack_samples.end(),
696 &stack_samples, &name_hashes);
697
698 ASSERT_EQ(1, name_hashes.size());
699 EXPECT_EQ(3u, name_hashes[0]);
700
701 EXPECT_EQ(1, stack_samples[0].metadata_size());
702 ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes);
703
704 EXPECT_EQ(0, stack_samples[1].metadata_size());
705 EXPECT_EQ(0, stack_samples[2].metadata_size());
706
707 // The next recorded sample should have item1 applied since it's still active.
708 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
709 &metadata_recorder, base::PlatformThread::CurrentId()));
710 *stack_samples.Add()->mutable_metadata() =
711 metadata.CreateSampleMetadata(&name_hashes);
712
713 EXPECT_EQ(1, stack_samples[3].metadata_size());
714 ExpectMetadataApplied(item1, stack_samples, 3, 0, name_hashes);
715 }
716
717 // Checks application of the same item across non-overlapping ranges.
TEST(CallStackProfileMetadataTest,ApplyMetadata_IndependentRanges)718 TEST(CallStackProfileMetadataTest, ApplyMetadata_IndependentRanges) {
719 CallStackProfileMetadata metadata;
720 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
721 stack_samples;
722 google::protobuf::RepeatedField<uint64_t> name_hashes;
723
724 for (int i = 0; i < 5; i++)
725 stack_samples.Add();
726
727 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
728
729 // Apply metadata over two non-overlapping ranges.
730 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
731 &stack_samples, &name_hashes);
732
733 metadata.ApplyMetadata(item, stack_samples.begin() + 3,
734 stack_samples.begin() + 4, &stack_samples,
735 &name_hashes);
736
737 ASSERT_EQ(1, name_hashes.size());
738 EXPECT_EQ(3u, name_hashes[0]);
739
740 EXPECT_EQ(1, stack_samples[0].metadata_size());
741 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
742
743 EXPECT_EQ(0, stack_samples[1].metadata_size());
744
745 EXPECT_EQ(1, stack_samples[2].metadata_size());
746 ExpectMetadataUnapplied(item, stack_samples, 2, 0, name_hashes);
747
748 EXPECT_EQ(1, stack_samples[3].metadata_size());
749 ExpectMetadataApplied(item, stack_samples, 3, 0, name_hashes);
750
751 EXPECT_EQ(1, stack_samples[4].metadata_size());
752 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
753 }
754
755 // Checks application of the same item across back-to-back ranges. The common
756 // sample should not have a metadata item set because it's unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_BackToBackRanges)757 TEST(CallStackProfileMetadataTest, ApplyMetadata_BackToBackRanges) {
758 CallStackProfileMetadata metadata;
759 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
760 stack_samples;
761 google::protobuf::RepeatedField<uint64_t> name_hashes;
762
763 for (int i = 0; i < 5; i++)
764 stack_samples.Add();
765
766 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
767
768 // Apply metadata over two ranges where the second starts on the same sample
769 // that the first ends. This should result in one range covering both.
770 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
771 &stack_samples, &name_hashes);
772
773 metadata.ApplyMetadata(item, stack_samples.begin() + 2,
774 stack_samples.begin() + 4, &stack_samples,
775 &name_hashes);
776
777 ASSERT_EQ(1, name_hashes.size());
778 EXPECT_EQ(3u, name_hashes[0]);
779
780 EXPECT_EQ(1, stack_samples[0].metadata_size());
781 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
782
783 EXPECT_EQ(0, stack_samples[1].metadata_size());
784 EXPECT_EQ(0, stack_samples[2].metadata_size());
785 EXPECT_EQ(0, stack_samples[3].metadata_size());
786
787 EXPECT_EQ(1, stack_samples[4].metadata_size());
788 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
789 }
790
791 // Checks application of different values across back-to-back ranges. The common
792 // sample must have the second metadata value set.
TEST(CallStackProfileMetadataTest,ApplyMetadata_BackToBackRangesWithDifferentValues)793 TEST(CallStackProfileMetadataTest,
794 ApplyMetadata_BackToBackRangesWithDifferentValues) {
795 CallStackProfileMetadata metadata;
796 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
797 stack_samples;
798 google::protobuf::RepeatedField<uint64_t> name_hashes;
799
800 for (int i = 0; i < 5; i++)
801 stack_samples.Add();
802
803 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
804 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
805
806 metadata.ApplyMetadata(item1, stack_samples.begin(),
807 stack_samples.begin() + 2, &stack_samples,
808 &name_hashes);
809
810 metadata.ApplyMetadata(item2, stack_samples.begin() + 2,
811 stack_samples.begin() + 4, &stack_samples,
812 &name_hashes);
813
814 ASSERT_EQ(1, name_hashes.size());
815 EXPECT_EQ(3u, name_hashes[0]);
816
817 EXPECT_EQ(1, stack_samples[0].metadata_size());
818 ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes);
819
820 EXPECT_EQ(0, stack_samples[1].metadata_size());
821
822 EXPECT_EQ(1, stack_samples[2].metadata_size());
823 ExpectMetadataApplied(item2, stack_samples, 2, 0, name_hashes);
824
825 EXPECT_EQ(0, stack_samples[3].metadata_size());
826
827 EXPECT_EQ(1, stack_samples[4].metadata_size());
828 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
829 }
830
831 // Checks application of the same item over a range within a range where the
832 // item was already set. No metadata changes should be recorded on the interior
833 // range because they are unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateWithinExistingRange)834 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateWithinExistingRange) {
835 CallStackProfileMetadata metadata;
836 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
837 stack_samples;
838 google::protobuf::RepeatedField<uint64_t> name_hashes;
839
840 for (int i = 0; i < 5; i++)
841 stack_samples.Add();
842
843 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
844
845 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 4,
846 &stack_samples, &name_hashes);
847
848 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
849 stack_samples.begin() + 3, &stack_samples,
850 &name_hashes);
851
852 ASSERT_EQ(1, name_hashes.size());
853 EXPECT_EQ(3u, name_hashes[0]);
854
855 EXPECT_EQ(1, stack_samples[0].metadata_size());
856 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
857
858 EXPECT_EQ(0, stack_samples[1].metadata_size());
859 EXPECT_EQ(0, stack_samples[2].metadata_size());
860 EXPECT_EQ(0, stack_samples[3].metadata_size());
861
862 EXPECT_EQ(1, stack_samples[4].metadata_size());
863 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
864 }
865
866 // Checks application of a second value over a range within a range where the
867 // first value was already set. Metadata changes for the second value must be
868 // recorded on the interior range.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateWithinExistingRangeWithDifferentValues)869 TEST(CallStackProfileMetadataTest,
870 ApplyMetadata_UpdateWithinExistingRangeWithDifferentValues) {
871 CallStackProfileMetadata metadata;
872 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
873 stack_samples;
874 google::protobuf::RepeatedField<uint64_t> name_hashes;
875
876 for (int i = 0; i < 5; i++)
877 stack_samples.Add();
878
879 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
880 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
881
882 // Apply metadata over a range, then over a range fully enclosed within the
883 // first one.
884 metadata.ApplyMetadata(item1, stack_samples.begin(),
885 stack_samples.begin() + 4, &stack_samples,
886 &name_hashes);
887
888 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
889 stack_samples.begin() + 3, &stack_samples,
890 &name_hashes);
891
892 ASSERT_EQ(1, name_hashes.size());
893 EXPECT_EQ(3u, name_hashes[0]);
894
895 EXPECT_EQ(1, stack_samples[0].metadata_size());
896 ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes);
897
898 EXPECT_EQ(1, stack_samples[1].metadata_size());
899 ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes);
900
901 EXPECT_EQ(0, stack_samples[2].metadata_size());
902
903 EXPECT_EQ(1, stack_samples[3].metadata_size());
904 ExpectMetadataApplied(item1, stack_samples, 3, 0, name_hashes);
905
906 EXPECT_EQ(1, stack_samples[4].metadata_size());
907 ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes);
908 }
909
910 // Checks application of the same item over a range enclosing a range where the
911 // item was already set. No metadata changes should be recorded on the interior
912 // range because they are unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateEnclosesExistingRange)913 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateEnclosesExistingRange) {
914 CallStackProfileMetadata metadata;
915 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
916 stack_samples;
917 google::protobuf::RepeatedField<uint64_t> name_hashes;
918
919 for (int i = 0; i < 5; i++)
920 stack_samples.Add();
921
922 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
923
924 // Apply metadata over a range, then over a range that fully encloses the
925 // first one.
926 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
927 stack_samples.begin() + 3, &stack_samples,
928 &name_hashes);
929
930 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 4,
931 &stack_samples, &name_hashes);
932
933 ASSERT_EQ(1, name_hashes.size());
934 EXPECT_EQ(3u, name_hashes[0]);
935
936 EXPECT_EQ(1, stack_samples[0].metadata_size());
937 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
938
939 EXPECT_EQ(0, stack_samples[1].metadata_size());
940 EXPECT_EQ(0, stack_samples[2].metadata_size());
941 EXPECT_EQ(0, stack_samples[3].metadata_size());
942
943 EXPECT_EQ(1, stack_samples[4].metadata_size());
944 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
945 }
946
947 // Checks application of a second value over a range enclosing a range where the
948 // first value was already set. Metadata changes for both values must be
949 // recorded.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateEnclosesExistingRangeWithDifferentValues)950 TEST(CallStackProfileMetadataTest,
951 ApplyMetadata_UpdateEnclosesExistingRangeWithDifferentValues) {
952 CallStackProfileMetadata metadata;
953 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
954 stack_samples;
955 google::protobuf::RepeatedField<uint64_t> name_hashes;
956
957 for (int i = 0; i < 5; i++)
958 stack_samples.Add();
959
960 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
961 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
962
963 // Apply metadata over a range, then over a range that fully encloses the
964 // first one.
965 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
966 stack_samples.begin() + 3, &stack_samples,
967 &name_hashes);
968
969 metadata.ApplyMetadata(item2, stack_samples.begin(),
970 stack_samples.begin() + 4, &stack_samples,
971 &name_hashes);
972
973 ASSERT_EQ(1, name_hashes.size());
974 EXPECT_EQ(3u, name_hashes[0]);
975
976 EXPECT_EQ(1, stack_samples[0].metadata_size());
977 ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes);
978
979 EXPECT_EQ(0, stack_samples[1].metadata_size());
980 EXPECT_EQ(0, stack_samples[2].metadata_size());
981 EXPECT_EQ(0, stack_samples[3].metadata_size());
982
983 EXPECT_EQ(1, stack_samples[4].metadata_size());
984 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
985 }
986
987 // Checks application of an item over a range overlapping the start (but not
988 // end) of a range where the item was already set. No metadata changes should be
989 // recorded on the interior application because it is unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsBegin)990 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateOverlapsBegin) {
991 CallStackProfileMetadata metadata;
992 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
993 stack_samples;
994 google::protobuf::RepeatedField<uint64_t> name_hashes;
995
996 for (int i = 0; i < 5; i++)
997 stack_samples.Add();
998
999 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
1000
1001 // Apply metadata over a range, then over a range that overlaps the beginning
1002 // (but not the end) of first one.
1003 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1004 stack_samples.begin() + 3, &stack_samples,
1005 &name_hashes);
1006
1007 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
1008 &stack_samples, &name_hashes);
1009
1010 ASSERT_EQ(1, name_hashes.size());
1011 EXPECT_EQ(3u, name_hashes[0]);
1012
1013 EXPECT_EQ(1, stack_samples[0].metadata_size());
1014 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
1015
1016 EXPECT_EQ(0, stack_samples[1].metadata_size());
1017 EXPECT_EQ(0, stack_samples[2].metadata_size());
1018
1019 EXPECT_EQ(1, stack_samples[3].metadata_size());
1020 ExpectMetadataUnapplied(item, stack_samples, 3, 0, name_hashes);
1021
1022 EXPECT_EQ(0, stack_samples[4].metadata_size());
1023 }
1024
1025 // Checks application of a second different value over a range overlapping the
1026 // start (but not end) of a range where the first value was already
1027 // set. Metadata changes must be recorded on the interior application.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsBeginWithDifferentValues)1028 TEST(CallStackProfileMetadataTest,
1029 ApplyMetadata_UpdateOverlapsBeginWithDifferentValues) {
1030 CallStackProfileMetadata metadata;
1031 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1032 stack_samples;
1033 google::protobuf::RepeatedField<uint64_t> name_hashes;
1034
1035 for (int i = 0; i < 5; i++)
1036 stack_samples.Add();
1037
1038 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
1039 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
1040
1041 // Apply metadata over a range, then over a range that overlaps the beginning
1042 // (but not the end) of first one.
1043 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
1044 stack_samples.begin() + 3, &stack_samples,
1045 &name_hashes);
1046
1047 metadata.ApplyMetadata(item2, stack_samples.begin(),
1048 stack_samples.begin() + 2, &stack_samples,
1049 &name_hashes);
1050
1051 ASSERT_EQ(1, name_hashes.size());
1052 EXPECT_EQ(3u, name_hashes[0]);
1053
1054 EXPECT_EQ(1, stack_samples[0].metadata_size());
1055 ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes);
1056
1057 EXPECT_EQ(0, stack_samples[1].metadata_size());
1058 EXPECT_EQ(1, stack_samples[2].metadata_size());
1059 ExpectMetadataApplied(item1, stack_samples, 2, 0, name_hashes);
1060
1061 EXPECT_EQ(1, stack_samples[3].metadata_size());
1062 ExpectMetadataUnapplied(item1, stack_samples, 3, 0, name_hashes);
1063
1064 EXPECT_EQ(0, stack_samples[4].metadata_size());
1065 }
1066
1067 // Checks application of an item over a range overlapping the end (but not
1068 // start) of a range where the item was already set. No metadata changes should
1069 // be recorded on the interior application because it is unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsEnd)1070 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateOverlapsEnd) {
1071 CallStackProfileMetadata metadata;
1072 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1073 stack_samples;
1074 google::protobuf::RepeatedField<uint64_t> name_hashes;
1075
1076 for (int i = 0; i < 5; i++)
1077 stack_samples.Add();
1078
1079 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
1080
1081 // Apply metadata over a range, then over a range that overlaps the beginning
1082 // (but not the end) of first one.
1083 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
1084 &stack_samples, &name_hashes);
1085
1086 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1087 stack_samples.begin() + 4, &stack_samples,
1088 &name_hashes);
1089
1090 ASSERT_EQ(1, name_hashes.size());
1091 EXPECT_EQ(3u, name_hashes[0]);
1092
1093 EXPECT_EQ(1, stack_samples[0].metadata_size());
1094 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
1095
1096 EXPECT_EQ(0, stack_samples[1].metadata_size());
1097 EXPECT_EQ(0, stack_samples[2].metadata_size());
1098 EXPECT_EQ(0, stack_samples[3].metadata_size());
1099
1100 EXPECT_EQ(1, stack_samples[4].metadata_size());
1101 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
1102 }
1103
1104 // Checks application of a second different value over a range overlapping the
1105 // end (but not start) of a range where the first value was already
1106 // set. Metadata changes must be recorded on the interior application.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsEndWithDifferentValues)1107 TEST(CallStackProfileMetadataTest,
1108 ApplyMetadata_UpdateOverlapsEndWithDifferentValues) {
1109 CallStackProfileMetadata metadata;
1110 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1111 stack_samples;
1112 google::protobuf::RepeatedField<uint64_t> name_hashes;
1113
1114 for (int i = 0; i < 5; i++)
1115 stack_samples.Add();
1116
1117 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
1118 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
1119
1120 // Apply metadata over a range, then over a range that overlaps the beginning
1121 // (but not the end) of first one.
1122 metadata.ApplyMetadata(item1, stack_samples.begin(),
1123 stack_samples.begin() + 2, &stack_samples,
1124 &name_hashes);
1125
1126 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
1127 stack_samples.begin() + 4, &stack_samples,
1128 &name_hashes);
1129
1130 ASSERT_EQ(1, name_hashes.size());
1131 EXPECT_EQ(3u, name_hashes[0]);
1132
1133 EXPECT_EQ(1, stack_samples[0].metadata_size());
1134 ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes);
1135
1136 EXPECT_EQ(1, stack_samples[1].metadata_size());
1137 ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes);
1138
1139 EXPECT_EQ(0, stack_samples[2].metadata_size());
1140 EXPECT_EQ(0, stack_samples[3].metadata_size());
1141
1142 EXPECT_EQ(1, stack_samples[4].metadata_size());
1143 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
1144 }
1145
1146 // Checks that updating the same range multiple times with the same item
1147 // produces the same result as what we'd expect with just one update.
TEST(CallStackProfileMetadataTest,ApplyMetadata_Update)1148 TEST(CallStackProfileMetadataTest, ApplyMetadata_Update) {
1149 CallStackProfileMetadata metadata;
1150 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1151 stack_samples;
1152 google::protobuf::RepeatedField<uint64_t> name_hashes;
1153
1154 for (int i = 0; i < 5; i++)
1155 stack_samples.Add();
1156
1157 const base::MetadataRecorder::Item item(3, 30, std::nullopt, 300);
1158
1159 // Apply metadata over the same range with one value, then a different value.
1160 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1161 stack_samples.begin() + 4, &stack_samples,
1162 &name_hashes);
1163
1164 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1165 stack_samples.begin() + 4, &stack_samples,
1166 &name_hashes);
1167
1168 ASSERT_EQ(1, name_hashes.size());
1169 EXPECT_EQ(3u, name_hashes[0]);
1170
1171 EXPECT_EQ(0, stack_samples[0].metadata_size());
1172
1173 EXPECT_EQ(1, stack_samples[1].metadata_size());
1174 ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes);
1175
1176 EXPECT_EQ(0, stack_samples[2].metadata_size());
1177 EXPECT_EQ(0, stack_samples[3].metadata_size());
1178
1179 EXPECT_EQ(1, stack_samples[4].metadata_size());
1180 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
1181 }
1182
1183 // Checks that applying to the same range with a different value overwrites the
1184 // initial value.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateWithDifferentValues)1185 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateWithDifferentValues) {
1186 CallStackProfileMetadata metadata;
1187 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1188 stack_samples;
1189 google::protobuf::RepeatedField<uint64_t> name_hashes;
1190
1191 for (int i = 0; i < 5; i++)
1192 stack_samples.Add();
1193
1194 const base::MetadataRecorder::Item item1(3, 30, std::nullopt, 300);
1195 const base::MetadataRecorder::Item item2(3, 30, std::nullopt, 400);
1196
1197 // Apply metadata over the same range with one value, then a different value.
1198 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
1199 stack_samples.begin() + 4, &stack_samples,
1200 &name_hashes);
1201
1202 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
1203 stack_samples.begin() + 4, &stack_samples,
1204 &name_hashes);
1205
1206 ASSERT_EQ(1, name_hashes.size());
1207 EXPECT_EQ(3u, name_hashes[0]);
1208
1209 EXPECT_EQ(0, stack_samples[0].metadata_size());
1210
1211 EXPECT_EQ(1, stack_samples[1].metadata_size());
1212 ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes);
1213
1214 EXPECT_EQ(0, stack_samples[2].metadata_size());
1215 EXPECT_EQ(0, stack_samples[3].metadata_size());
1216
1217 EXPECT_EQ(1, stack_samples[4].metadata_size());
1218 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
1219 }
1220
1221 } // namespace metrics
1222