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, absl::nullopt, absl::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, absl::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, absl::nullopt, base::PlatformThread::CurrentId(),
144 10);
145 metadata_recorder.Set(100, absl::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, absl::nullopt, absl::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, absl::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, absl::nullopt, absl::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, absl::nullopt, absl::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, absl::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, absl::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, absl::nullopt, absl::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, absl::nullopt, absl::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, absl::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, absl::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, absl::nullopt, absl::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, absl::nullopt, absl::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, absl::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, absl::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, absl::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, absl::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, absl::nullopt, absl::nullopt, 20);
384 metadata_recorder.Set(100, 50, absl::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, absl::nullopt, absl::nullopt, 20);
409 metadata_recorder.Set(100, 50, absl::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, absl::nullopt, absl::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, absl::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, absl::nullopt, 300);
471 const base::MetadataRecorder::Item item2(4, 30, absl::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, absl::nullopt, 300);
508 const base::MetadataRecorder::Item item2(3, 40, absl::nullopt, 300);
509 const base::MetadataRecorder::Item item3(3, absl::nullopt, absl::nullopt,
510 300);
511 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
512 stack_samples.begin() + 4, &stack_samples,
513 &name_hashes);
514 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
515 stack_samples.begin() + 4, &stack_samples,
516 &name_hashes);
517 metadata.ApplyMetadata(item3, stack_samples.begin() + 1,
518 stack_samples.begin() + 4, &stack_samples,
519 &name_hashes);
520
521 ASSERT_EQ(1, name_hashes.size());
522 EXPECT_EQ(3u, name_hashes[0]);
523
524 EXPECT_EQ(0, stack_samples[0].metadata_size());
525
526 EXPECT_EQ(3, stack_samples[1].metadata_size());
527 ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes);
528 ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes);
529 ExpectMetadataApplied(item3, stack_samples, 1, 2, name_hashes);
530
531 EXPECT_EQ(0, stack_samples[2].metadata_size());
532 EXPECT_EQ(0, stack_samples[3].metadata_size());
533
534 EXPECT_EQ(3, stack_samples[4].metadata_size());
535 ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes);
536 ExpectMetadataUnapplied(item2, stack_samples, 4, 1, name_hashes);
537 ExpectMetadataUnapplied(item3, stack_samples, 4, 2, name_hashes);
538 }
539
540 // Checks that applying to an empty range has no effect.
TEST(CallStackProfileMetadataTest,ApplyMetadata_EmptyRange)541 TEST(CallStackProfileMetadataTest, ApplyMetadata_EmptyRange) {
542 CallStackProfileMetadata metadata;
543 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
544 stack_samples;
545 google::protobuf::RepeatedField<uint64_t> name_hashes;
546
547 for (int i = 0; i < 5; i++)
548 stack_samples.Add();
549
550 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
551 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
552 stack_samples.begin() + 1, &stack_samples,
553 &name_hashes);
554
555 EXPECT_EQ(0, name_hashes.size());
556
557 for (int i = 0; i < 5; i++)
558 EXPECT_EQ(0, stack_samples[i].metadata_size());
559 }
560
561 // Checks that applying metadata through the end is recorded as unapplied on the
562 // next sample taken.
TEST(CallStackProfileMetadataTest,ApplyMetadata_ThroughEnd)563 TEST(CallStackProfileMetadataTest, ApplyMetadata_ThroughEnd) {
564 CallStackProfileMetadata metadata;
565 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
566 stack_samples;
567 google::protobuf::RepeatedField<uint64_t> name_hashes;
568
569 for (int i = 0; i < 5; i++)
570 stack_samples.Add();
571
572 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
573 metadata.ApplyMetadata(item, stack_samples.begin() + 1, stack_samples.end(),
574 &stack_samples, &name_hashes);
575
576 ASSERT_EQ(1, name_hashes.size());
577 EXPECT_EQ(3u, name_hashes[0]);
578
579 EXPECT_EQ(0, stack_samples[0].metadata_size());
580
581 // One metadata item should be recorded when the metadata starts.
582 EXPECT_EQ(1, stack_samples[1].metadata_size());
583 ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes);
584
585 EXPECT_EQ(0, stack_samples[2].metadata_size());
586 EXPECT_EQ(0, stack_samples[3].metadata_size());
587 EXPECT_EQ(0, stack_samples[4].metadata_size());
588
589 base::MetadataRecorder metadata_recorder;
590 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
591 &metadata_recorder, base::PlatformThread::CurrentId()));
592 *stack_samples.Add()->mutable_metadata() =
593 metadata.CreateSampleMetadata(&name_hashes);
594
595 // And the following sample should have the metadata unapplied.
596 ExpectMetadataUnapplied(item, stack_samples, 5, 0, name_hashes);
597 }
598
599 // Checks that metadata is properly applied when mixing RecordMetadata and
600 // ApplyMetadata over the same samples.
TEST(CallStackProfileMetadataTest,ApplyMetadata_WithRecordMetadata)601 TEST(CallStackProfileMetadataTest, ApplyMetadata_WithRecordMetadata) {
602 base::MetadataRecorder metadata_recorder;
603 CallStackProfileMetadata metadata;
604 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
605 stack_samples;
606 google::protobuf::RepeatedField<uint64_t> name_hashes;
607
608 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
609 const base::MetadataRecorder::Item item2(5, 50, absl::nullopt, 500);
610
611 stack_samples.Add();
612
613 // Apply then remove item1.
614 metadata_recorder.Set(item1.name_hash, *item1.key, item1.thread_id,
615 item1.value);
616 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
617 &metadata_recorder, base::PlatformThread::CurrentId()));
618 *stack_samples.Add()->mutable_metadata() =
619 metadata.CreateSampleMetadata(&name_hashes);
620
621 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
622 &metadata_recorder, base::PlatformThread::CurrentId()));
623 *stack_samples.Add()->mutable_metadata() =
624 metadata.CreateSampleMetadata(&name_hashes);
625
626 metadata_recorder.Remove(item1.name_hash, *item1.key, item1.thread_id);
627 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
628 &metadata_recorder, base::PlatformThread::CurrentId()));
629 *stack_samples.Add()->mutable_metadata() =
630 metadata.CreateSampleMetadata(&name_hashes);
631
632 stack_samples.Add();
633
634 ASSERT_EQ(5, stack_samples.size());
635
636 // Apply item2.
637 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
638 stack_samples.begin() + 4, &stack_samples,
639 &name_hashes);
640
641 ASSERT_EQ(2, name_hashes.size());
642 EXPECT_EQ(3u, name_hashes[0]);
643 EXPECT_EQ(5u, name_hashes[1]);
644
645 EXPECT_EQ(0, stack_samples[0].metadata_size());
646
647 // Each of the two items should be recorded when their metadata starts.
648 ASSERT_EQ(2, stack_samples[1].metadata_size());
649 ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes);
650 ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes);
651
652 EXPECT_EQ(0, stack_samples[2].metadata_size());
653
654 // The original item should still be present.
655 EXPECT_EQ(1, stack_samples[3].metadata_size());
656 ExpectMetadataUnapplied(item1, stack_samples, 3, 0, name_hashes);
657
658 // And one item should be recorded without value after the metadata ends.
659 EXPECT_EQ(1, stack_samples[4].metadata_size());
660 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
661 }
662
663 // Checks that metadata is properly applied when using ApplyMetadata while
664 // a RecordMetadata-applied value is active.
TEST(CallStackProfileMetadataTest,ApplyMetadata_WithActiveMetadata)665 TEST(CallStackProfileMetadataTest, ApplyMetadata_WithActiveMetadata) {
666 base::MetadataRecorder metadata_recorder;
667 CallStackProfileMetadata metadata;
668 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
669 stack_samples;
670 google::protobuf::RepeatedField<uint64_t> name_hashes;
671
672 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
673 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
674
675 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
676 &metadata_recorder, base::PlatformThread::CurrentId()));
677 *stack_samples.Add()->mutable_metadata() =
678 metadata.CreateSampleMetadata(&name_hashes);
679
680 // Record item1 on an ongoing basis via RecordMetadata.
681 metadata_recorder.Set(item1.name_hash, *item1.key, item1.thread_id,
682 item1.value);
683 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
684 &metadata_recorder, base::PlatformThread::CurrentId()));
685 *stack_samples.Add()->mutable_metadata() =
686 metadata.CreateSampleMetadata(&name_hashes);
687
688 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
689 &metadata_recorder, base::PlatformThread::CurrentId()));
690 *stack_samples.Add()->mutable_metadata() =
691 metadata.CreateSampleMetadata(&name_hashes);
692
693 ASSERT_EQ(3, stack_samples.size());
694
695 // Apply item2 via ApplyMetadata up to the last sample.
696 metadata.ApplyMetadata(item2, stack_samples.begin(), stack_samples.end(),
697 &stack_samples, &name_hashes);
698
699 ASSERT_EQ(1, name_hashes.size());
700 EXPECT_EQ(3u, name_hashes[0]);
701
702 EXPECT_EQ(1, stack_samples[0].metadata_size());
703 ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes);
704
705 EXPECT_EQ(0, stack_samples[1].metadata_size());
706 EXPECT_EQ(0, stack_samples[2].metadata_size());
707
708 // The next recorded sample should have item1 applied since it's still active.
709 metadata.RecordMetadata(base::MetadataRecorder::MetadataProvider(
710 &metadata_recorder, base::PlatformThread::CurrentId()));
711 *stack_samples.Add()->mutable_metadata() =
712 metadata.CreateSampleMetadata(&name_hashes);
713
714 EXPECT_EQ(1, stack_samples[3].metadata_size());
715 ExpectMetadataApplied(item1, stack_samples, 3, 0, name_hashes);
716 }
717
718 // Checks application of the same item across non-overlapping ranges.
TEST(CallStackProfileMetadataTest,ApplyMetadata_IndependentRanges)719 TEST(CallStackProfileMetadataTest, ApplyMetadata_IndependentRanges) {
720 CallStackProfileMetadata metadata;
721 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
722 stack_samples;
723 google::protobuf::RepeatedField<uint64_t> name_hashes;
724
725 for (int i = 0; i < 5; i++)
726 stack_samples.Add();
727
728 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
729
730 // Apply metadata over two non-overlapping ranges.
731 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
732 &stack_samples, &name_hashes);
733
734 metadata.ApplyMetadata(item, stack_samples.begin() + 3,
735 stack_samples.begin() + 4, &stack_samples,
736 &name_hashes);
737
738 ASSERT_EQ(1, name_hashes.size());
739 EXPECT_EQ(3u, name_hashes[0]);
740
741 EXPECT_EQ(1, stack_samples[0].metadata_size());
742 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
743
744 EXPECT_EQ(0, stack_samples[1].metadata_size());
745
746 EXPECT_EQ(1, stack_samples[2].metadata_size());
747 ExpectMetadataUnapplied(item, stack_samples, 2, 0, name_hashes);
748
749 EXPECT_EQ(1, stack_samples[3].metadata_size());
750 ExpectMetadataApplied(item, stack_samples, 3, 0, name_hashes);
751
752 EXPECT_EQ(1, stack_samples[4].metadata_size());
753 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
754 }
755
756 // Checks application of the same item across back-to-back ranges. The common
757 // sample should not have a metadata item set because it's unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_BackToBackRanges)758 TEST(CallStackProfileMetadataTest, ApplyMetadata_BackToBackRanges) {
759 CallStackProfileMetadata metadata;
760 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
761 stack_samples;
762 google::protobuf::RepeatedField<uint64_t> name_hashes;
763
764 for (int i = 0; i < 5; i++)
765 stack_samples.Add();
766
767 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
768
769 // Apply metadata over two ranges where the second starts on the same sample
770 // that the first ends. This should result in one range covering both.
771 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
772 &stack_samples, &name_hashes);
773
774 metadata.ApplyMetadata(item, stack_samples.begin() + 2,
775 stack_samples.begin() + 4, &stack_samples,
776 &name_hashes);
777
778 ASSERT_EQ(1, name_hashes.size());
779 EXPECT_EQ(3u, name_hashes[0]);
780
781 EXPECT_EQ(1, stack_samples[0].metadata_size());
782 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
783
784 EXPECT_EQ(0, stack_samples[1].metadata_size());
785 EXPECT_EQ(0, stack_samples[2].metadata_size());
786 EXPECT_EQ(0, stack_samples[3].metadata_size());
787
788 EXPECT_EQ(1, stack_samples[4].metadata_size());
789 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
790 }
791
792 // Checks application of different values across back-to-back ranges. The common
793 // sample must have the second metadata value set.
TEST(CallStackProfileMetadataTest,ApplyMetadata_BackToBackRangesWithDifferentValues)794 TEST(CallStackProfileMetadataTest,
795 ApplyMetadata_BackToBackRangesWithDifferentValues) {
796 CallStackProfileMetadata metadata;
797 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
798 stack_samples;
799 google::protobuf::RepeatedField<uint64_t> name_hashes;
800
801 for (int i = 0; i < 5; i++)
802 stack_samples.Add();
803
804 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
805 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
806
807 metadata.ApplyMetadata(item1, stack_samples.begin(),
808 stack_samples.begin() + 2, &stack_samples,
809 &name_hashes);
810
811 metadata.ApplyMetadata(item2, stack_samples.begin() + 2,
812 stack_samples.begin() + 4, &stack_samples,
813 &name_hashes);
814
815 ASSERT_EQ(1, name_hashes.size());
816 EXPECT_EQ(3u, name_hashes[0]);
817
818 EXPECT_EQ(1, stack_samples[0].metadata_size());
819 ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes);
820
821 EXPECT_EQ(0, stack_samples[1].metadata_size());
822
823 EXPECT_EQ(1, stack_samples[2].metadata_size());
824 ExpectMetadataApplied(item2, stack_samples, 2, 0, name_hashes);
825
826 EXPECT_EQ(0, stack_samples[3].metadata_size());
827
828 EXPECT_EQ(1, stack_samples[4].metadata_size());
829 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
830 }
831
832 // Checks application of the same item over a range within a range where the
833 // item was already set. No metadata changes should be recorded on the interior
834 // range because they are unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateWithinExistingRange)835 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateWithinExistingRange) {
836 CallStackProfileMetadata metadata;
837 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
838 stack_samples;
839 google::protobuf::RepeatedField<uint64_t> name_hashes;
840
841 for (int i = 0; i < 5; i++)
842 stack_samples.Add();
843
844 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
845
846 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 4,
847 &stack_samples, &name_hashes);
848
849 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
850 stack_samples.begin() + 3, &stack_samples,
851 &name_hashes);
852
853 ASSERT_EQ(1, name_hashes.size());
854 EXPECT_EQ(3u, name_hashes[0]);
855
856 EXPECT_EQ(1, stack_samples[0].metadata_size());
857 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
858
859 EXPECT_EQ(0, stack_samples[1].metadata_size());
860 EXPECT_EQ(0, stack_samples[2].metadata_size());
861 EXPECT_EQ(0, stack_samples[3].metadata_size());
862
863 EXPECT_EQ(1, stack_samples[4].metadata_size());
864 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
865 }
866
867 // Checks application of a second value over a range within a range where the
868 // first value was already set. Metadata changes for the second value must be
869 // recorded on the interior range.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateWithinExistingRangeWithDifferentValues)870 TEST(CallStackProfileMetadataTest,
871 ApplyMetadata_UpdateWithinExistingRangeWithDifferentValues) {
872 CallStackProfileMetadata metadata;
873 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
874 stack_samples;
875 google::protobuf::RepeatedField<uint64_t> name_hashes;
876
877 for (int i = 0; i < 5; i++)
878 stack_samples.Add();
879
880 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
881 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
882
883 // Apply metadata over a range, then over a range fully enclosed within the
884 // first one.
885 metadata.ApplyMetadata(item1, stack_samples.begin(),
886 stack_samples.begin() + 4, &stack_samples,
887 &name_hashes);
888
889 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
890 stack_samples.begin() + 3, &stack_samples,
891 &name_hashes);
892
893 ASSERT_EQ(1, name_hashes.size());
894 EXPECT_EQ(3u, name_hashes[0]);
895
896 EXPECT_EQ(1, stack_samples[0].metadata_size());
897 ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes);
898
899 EXPECT_EQ(1, stack_samples[1].metadata_size());
900 ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes);
901
902 EXPECT_EQ(0, stack_samples[2].metadata_size());
903
904 EXPECT_EQ(1, stack_samples[3].metadata_size());
905 ExpectMetadataApplied(item1, stack_samples, 3, 0, name_hashes);
906
907 EXPECT_EQ(1, stack_samples[4].metadata_size());
908 ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes);
909 }
910
911 // Checks application of the same item over a range enclosing a range where the
912 // item was already set. No metadata changes should be recorded on the interior
913 // range because they are unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateEnclosesExistingRange)914 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateEnclosesExistingRange) {
915 CallStackProfileMetadata metadata;
916 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
917 stack_samples;
918 google::protobuf::RepeatedField<uint64_t> name_hashes;
919
920 for (int i = 0; i < 5; i++)
921 stack_samples.Add();
922
923 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
924
925 // Apply metadata over a range, then over a range that fully encloses the
926 // first one.
927 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
928 stack_samples.begin() + 3, &stack_samples,
929 &name_hashes);
930
931 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 4,
932 &stack_samples, &name_hashes);
933
934 ASSERT_EQ(1, name_hashes.size());
935 EXPECT_EQ(3u, name_hashes[0]);
936
937 EXPECT_EQ(1, stack_samples[0].metadata_size());
938 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
939
940 EXPECT_EQ(0, stack_samples[1].metadata_size());
941 EXPECT_EQ(0, stack_samples[2].metadata_size());
942 EXPECT_EQ(0, stack_samples[3].metadata_size());
943
944 EXPECT_EQ(1, stack_samples[4].metadata_size());
945 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
946 }
947
948 // Checks application of a second value over a range enclosing a range where the
949 // first value was already set. Metadata changes for both values must be
950 // recorded.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateEnclosesExistingRangeWithDifferentValues)951 TEST(CallStackProfileMetadataTest,
952 ApplyMetadata_UpdateEnclosesExistingRangeWithDifferentValues) {
953 CallStackProfileMetadata metadata;
954 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
955 stack_samples;
956 google::protobuf::RepeatedField<uint64_t> name_hashes;
957
958 for (int i = 0; i < 5; i++)
959 stack_samples.Add();
960
961 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
962 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
963
964 // Apply metadata over a range, then over a range that fully encloses the
965 // first one.
966 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
967 stack_samples.begin() + 3, &stack_samples,
968 &name_hashes);
969
970 metadata.ApplyMetadata(item2, stack_samples.begin(),
971 stack_samples.begin() + 4, &stack_samples,
972 &name_hashes);
973
974 ASSERT_EQ(1, name_hashes.size());
975 EXPECT_EQ(3u, name_hashes[0]);
976
977 EXPECT_EQ(1, stack_samples[0].metadata_size());
978 ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes);
979
980 EXPECT_EQ(0, stack_samples[1].metadata_size());
981 EXPECT_EQ(0, stack_samples[2].metadata_size());
982 EXPECT_EQ(0, stack_samples[3].metadata_size());
983
984 EXPECT_EQ(1, stack_samples[4].metadata_size());
985 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
986 }
987
988 // Checks application of an item over a range overlapping the start (but not
989 // end) of a range where the item was already set. No metadata changes should be
990 // recorded on the interior application because it is unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsBegin)991 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateOverlapsBegin) {
992 CallStackProfileMetadata metadata;
993 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
994 stack_samples;
995 google::protobuf::RepeatedField<uint64_t> name_hashes;
996
997 for (int i = 0; i < 5; i++)
998 stack_samples.Add();
999
1000 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
1001
1002 // Apply metadata over a range, then over a range that overlaps the beginning
1003 // (but not the end) of first one.
1004 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1005 stack_samples.begin() + 3, &stack_samples,
1006 &name_hashes);
1007
1008 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
1009 &stack_samples, &name_hashes);
1010
1011 ASSERT_EQ(1, name_hashes.size());
1012 EXPECT_EQ(3u, name_hashes[0]);
1013
1014 EXPECT_EQ(1, stack_samples[0].metadata_size());
1015 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
1016
1017 EXPECT_EQ(0, stack_samples[1].metadata_size());
1018 EXPECT_EQ(0, stack_samples[2].metadata_size());
1019
1020 EXPECT_EQ(1, stack_samples[3].metadata_size());
1021 ExpectMetadataUnapplied(item, stack_samples, 3, 0, name_hashes);
1022
1023 EXPECT_EQ(0, stack_samples[4].metadata_size());
1024 }
1025
1026 // Checks application of a second different value over a range overlapping the
1027 // start (but not end) of a range where the first value was already
1028 // set. Metadata changes must be recorded on the interior application.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsBeginWithDifferentValues)1029 TEST(CallStackProfileMetadataTest,
1030 ApplyMetadata_UpdateOverlapsBeginWithDifferentValues) {
1031 CallStackProfileMetadata metadata;
1032 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1033 stack_samples;
1034 google::protobuf::RepeatedField<uint64_t> name_hashes;
1035
1036 for (int i = 0; i < 5; i++)
1037 stack_samples.Add();
1038
1039 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
1040 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
1041
1042 // Apply metadata over a range, then over a range that overlaps the beginning
1043 // (but not the end) of first one.
1044 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
1045 stack_samples.begin() + 3, &stack_samples,
1046 &name_hashes);
1047
1048 metadata.ApplyMetadata(item2, stack_samples.begin(),
1049 stack_samples.begin() + 2, &stack_samples,
1050 &name_hashes);
1051
1052 ASSERT_EQ(1, name_hashes.size());
1053 EXPECT_EQ(3u, name_hashes[0]);
1054
1055 EXPECT_EQ(1, stack_samples[0].metadata_size());
1056 ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes);
1057
1058 EXPECT_EQ(0, stack_samples[1].metadata_size());
1059 EXPECT_EQ(1, stack_samples[2].metadata_size());
1060 ExpectMetadataApplied(item1, stack_samples, 2, 0, name_hashes);
1061
1062 EXPECT_EQ(1, stack_samples[3].metadata_size());
1063 ExpectMetadataUnapplied(item1, stack_samples, 3, 0, name_hashes);
1064
1065 EXPECT_EQ(0, stack_samples[4].metadata_size());
1066 }
1067
1068 // Checks application of an item over a range overlapping the end (but not
1069 // start) of a range where the item was already set. No metadata changes should
1070 // be recorded on the interior application because it is unnecessary.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsEnd)1071 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateOverlapsEnd) {
1072 CallStackProfileMetadata metadata;
1073 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1074 stack_samples;
1075 google::protobuf::RepeatedField<uint64_t> name_hashes;
1076
1077 for (int i = 0; i < 5; i++)
1078 stack_samples.Add();
1079
1080 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
1081
1082 // Apply metadata over a range, then over a range that overlaps the beginning
1083 // (but not the end) of first one.
1084 metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2,
1085 &stack_samples, &name_hashes);
1086
1087 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1088 stack_samples.begin() + 4, &stack_samples,
1089 &name_hashes);
1090
1091 ASSERT_EQ(1, name_hashes.size());
1092 EXPECT_EQ(3u, name_hashes[0]);
1093
1094 EXPECT_EQ(1, stack_samples[0].metadata_size());
1095 ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes);
1096
1097 EXPECT_EQ(0, stack_samples[1].metadata_size());
1098 EXPECT_EQ(0, stack_samples[2].metadata_size());
1099 EXPECT_EQ(0, stack_samples[3].metadata_size());
1100
1101 EXPECT_EQ(1, stack_samples[4].metadata_size());
1102 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
1103 }
1104
1105 // Checks application of a second different value over a range overlapping the
1106 // end (but not start) of a range where the first value was already
1107 // set. Metadata changes must be recorded on the interior application.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateOverlapsEndWithDifferentValues)1108 TEST(CallStackProfileMetadataTest,
1109 ApplyMetadata_UpdateOverlapsEndWithDifferentValues) {
1110 CallStackProfileMetadata metadata;
1111 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1112 stack_samples;
1113 google::protobuf::RepeatedField<uint64_t> name_hashes;
1114
1115 for (int i = 0; i < 5; i++)
1116 stack_samples.Add();
1117
1118 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
1119 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
1120
1121 // Apply metadata over a range, then over a range that overlaps the beginning
1122 // (but not the end) of first one.
1123 metadata.ApplyMetadata(item1, stack_samples.begin(),
1124 stack_samples.begin() + 2, &stack_samples,
1125 &name_hashes);
1126
1127 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
1128 stack_samples.begin() + 4, &stack_samples,
1129 &name_hashes);
1130
1131 ASSERT_EQ(1, name_hashes.size());
1132 EXPECT_EQ(3u, name_hashes[0]);
1133
1134 EXPECT_EQ(1, stack_samples[0].metadata_size());
1135 ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes);
1136
1137 EXPECT_EQ(1, stack_samples[1].metadata_size());
1138 ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes);
1139
1140 EXPECT_EQ(0, stack_samples[2].metadata_size());
1141 EXPECT_EQ(0, stack_samples[3].metadata_size());
1142
1143 EXPECT_EQ(1, stack_samples[4].metadata_size());
1144 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
1145 }
1146
1147 // Checks that updating the same range multiple times with the same item
1148 // produces the same result as what we'd expect with just one update.
TEST(CallStackProfileMetadataTest,ApplyMetadata_Update)1149 TEST(CallStackProfileMetadataTest, ApplyMetadata_Update) {
1150 CallStackProfileMetadata metadata;
1151 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1152 stack_samples;
1153 google::protobuf::RepeatedField<uint64_t> name_hashes;
1154
1155 for (int i = 0; i < 5; i++)
1156 stack_samples.Add();
1157
1158 const base::MetadataRecorder::Item item(3, 30, absl::nullopt, 300);
1159
1160 // Apply metadata over the same range with one value, then a different value.
1161 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1162 stack_samples.begin() + 4, &stack_samples,
1163 &name_hashes);
1164
1165 metadata.ApplyMetadata(item, stack_samples.begin() + 1,
1166 stack_samples.begin() + 4, &stack_samples,
1167 &name_hashes);
1168
1169 ASSERT_EQ(1, name_hashes.size());
1170 EXPECT_EQ(3u, name_hashes[0]);
1171
1172 EXPECT_EQ(0, stack_samples[0].metadata_size());
1173
1174 EXPECT_EQ(1, stack_samples[1].metadata_size());
1175 ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes);
1176
1177 EXPECT_EQ(0, stack_samples[2].metadata_size());
1178 EXPECT_EQ(0, stack_samples[3].metadata_size());
1179
1180 EXPECT_EQ(1, stack_samples[4].metadata_size());
1181 ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes);
1182 }
1183
1184 // Checks that applying to the same range with a different value overwrites the
1185 // initial value.
TEST(CallStackProfileMetadataTest,ApplyMetadata_UpdateWithDifferentValues)1186 TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateWithDifferentValues) {
1187 CallStackProfileMetadata metadata;
1188 google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>
1189 stack_samples;
1190 google::protobuf::RepeatedField<uint64_t> name_hashes;
1191
1192 for (int i = 0; i < 5; i++)
1193 stack_samples.Add();
1194
1195 const base::MetadataRecorder::Item item1(3, 30, absl::nullopt, 300);
1196 const base::MetadataRecorder::Item item2(3, 30, absl::nullopt, 400);
1197
1198 // Apply metadata over the same range with one value, then a different value.
1199 metadata.ApplyMetadata(item1, stack_samples.begin() + 1,
1200 stack_samples.begin() + 4, &stack_samples,
1201 &name_hashes);
1202
1203 metadata.ApplyMetadata(item2, stack_samples.begin() + 1,
1204 stack_samples.begin() + 4, &stack_samples,
1205 &name_hashes);
1206
1207 ASSERT_EQ(1, name_hashes.size());
1208 EXPECT_EQ(3u, name_hashes[0]);
1209
1210 EXPECT_EQ(0, stack_samples[0].metadata_size());
1211
1212 EXPECT_EQ(1, stack_samples[1].metadata_size());
1213 ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes);
1214
1215 EXPECT_EQ(0, stack_samples[2].metadata_size());
1216 EXPECT_EQ(0, stack_samples[3].metadata_size());
1217
1218 EXPECT_EQ(1, stack_samples[4].metadata_size());
1219 ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes);
1220 }
1221
1222 } // namespace metrics
1223