| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/metrics/call_stack_profile_metadata.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/metrics_proto/sampled_profile.pb.h" |
| |
| namespace metrics { |
| |
| namespace { |
| |
| // Expects that |expected_item| was applied to |samples| at |sample_index| and |
| // |metadata_index|. Because of the "edge-triggered" metadata encoding, this |
| // expectation will be valid for the first sample seeing the item only. |
| void ExpectMetadataApplied( |
| const base::ProfileBuilder::MetadataItem& expected_item, |
| const google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>& |
| samples, |
| int sample_index, |
| int metadata_index, |
| const google::protobuf::RepeatedField<uint64_t>& name_hashes) { |
| const std::string index_info = |
| base::StrCat({"at sample_index ", base::NumberToString(sample_index), |
| ", metadata_index ", base::NumberToString(metadata_index)}); |
| const int name_hash_index = std::find(name_hashes.begin(), name_hashes.end(), |
| expected_item.name_hash) - |
| name_hashes.begin(); |
| ASSERT_NE(name_hash_index, name_hashes.size()) << index_info; |
| |
| ASSERT_LT(sample_index, samples.size()) << index_info; |
| const CallStackProfile::StackSample& sample = samples[sample_index]; |
| ASSERT_LT(metadata_index, sample.metadata_size()) << index_info; |
| const CallStackProfile::MetadataItem& item = sample.metadata(metadata_index); |
| EXPECT_EQ(name_hash_index, item.name_hash_index()) << index_info; |
| |
| EXPECT_EQ(expected_item.key.has_value(), item.has_key()) << index_info; |
| if (expected_item.key.has_value()) |
| EXPECT_EQ(*expected_item.key, item.key()) << index_info; |
| EXPECT_EQ(expected_item.value, item.value()) << index_info; |
| } |
| |
| // Expects that the |item| was unapplied at |sample|. Because of the |
| // "edge-triggered" metadata encoding, this expectation will be valid for the |
| // sample following the last sample with the item only. |
| void ExpectMetadataUnapplied( |
| const base::ProfileBuilder::MetadataItem& expected_item, |
| const google::protobuf::RepeatedPtrField<CallStackProfile::StackSample>& |
| samples, |
| int sample_index, |
| int metadata_index, |
| const google::protobuf::RepeatedField<uint64_t>& name_hashes) { |
| const std::string index_info = |
| base::StrCat({"at sample_index ", base::NumberToString(sample_index), |
| ", metadata_index ", base::NumberToString(metadata_index)}); |
| const int name_hash_index = std::find(name_hashes.begin(), name_hashes.end(), |
| expected_item.name_hash) - |
| name_hashes.begin(); |
| ASSERT_NE(name_hash_index, name_hashes.size()) << index_info; |
| |
| ASSERT_LT(sample_index, samples.size()) << index_info; |
| const CallStackProfile::StackSample& sample = samples[sample_index]; |
| ASSERT_LT(metadata_index, sample.metadata_size()) << index_info; |
| const CallStackProfile::MetadataItem& item = sample.metadata(metadata_index); |
| EXPECT_EQ(name_hash_index, item.name_hash_index()) << index_info; |
| |
| EXPECT_EQ(expected_item.key.has_value(), item.has_key()) << index_info; |
| if (expected_item.key.has_value()) |
| EXPECT_EQ(*expected_item.key, item.key()) << index_info; |
| EXPECT_FALSE(item.has_value()) << index_info; |
| } |
| |
| } // namespace |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_NoItems) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(0, name_hashes.size()); |
| ASSERT_EQ(0, items.size()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_SetItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(100u, name_hashes[0]); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_FALSE(items[0].has_key()); |
| EXPECT_EQ(10, items[0].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_SetKeyedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(100u, name_hashes[0]); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_TRUE(items[0].has_key()); |
| EXPECT_EQ(50, items[0].key()); |
| EXPECT_EQ(10, items[0].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_RepeatItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| // The second sample shouldn't have any metadata because it's all the same |
| // as the last sample. |
| EXPECT_EQ(1, name_hashes.size()); |
| EXPECT_TRUE(items.empty()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_RepeatKeyedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| // The second sample shouldn't have any metadata because it's all the same |
| // as the last sample. |
| EXPECT_EQ(1, name_hashes.size()); |
| EXPECT_TRUE(items.empty()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_ModifiedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Set(100, base::nullopt, 11); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| EXPECT_EQ(1, name_hashes.size()); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_FALSE(items[0].has_key()); |
| EXPECT_EQ(11, items[0].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_ModifiedKeyedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Set(100, 50, 11); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| EXPECT_EQ(1, name_hashes.size()); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_TRUE(items[0].has_key()); |
| EXPECT_EQ(50, items[0].key()); |
| EXPECT_EQ(11, items[0].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_NewItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Set(101, base::nullopt, 11); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(2, name_hashes.size()); |
| EXPECT_EQ(101u, name_hashes[1]); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(1, items[0].name_hash_index()); |
| EXPECT_FALSE(items[0].has_key()); |
| EXPECT_EQ(11, items[0].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_NewKeyedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Set(101, 50, 11); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(2, name_hashes.size()); |
| EXPECT_EQ(101u, name_hashes[1]); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(1, items[0].name_hash_index()); |
| EXPECT_TRUE(items[0].has_key()); |
| EXPECT_EQ(50, items[0].key()); |
| EXPECT_EQ(11, items[0].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Remove(100, base::nullopt); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| EXPECT_EQ(1, name_hashes.size()); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_FALSE(items[0].has_key()); |
| EXPECT_FALSE(items[0].has_value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, MetadataRecorder_RemovedKeyedItem) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Remove(100, 50); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| EXPECT_EQ(1, name_hashes.size()); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_TRUE(items[0].has_key()); |
| EXPECT_EQ(50, items[0].key()); |
| EXPECT_FALSE(items[0].has_value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, |
| MetadataRecorder_SetMixedUnkeyedAndKeyedItems) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 20); |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(2, items.size()); |
| |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_FALSE(items[0].has_key()); |
| EXPECT_EQ(20, items[0].value()); |
| |
| EXPECT_EQ(0, items[1].name_hash_index()); |
| EXPECT_TRUE(items[1].has_key()); |
| EXPECT_EQ(50, items[1].key()); |
| EXPECT_EQ(10, items[1].value()); |
| } |
| |
| TEST(CallStackProfileMetadataTest, |
| MetadataRecorder_RemoveMixedUnkeyedAndKeyedItems) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| metadata_recorder.Set(100, base::nullopt, 20); |
| metadata_recorder.Set(100, 50, 10); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| (void)metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Remove(100, base::nullopt); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| google::protobuf::RepeatedPtrField<CallStackProfile::MetadataItem> items = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(1, items.size()); |
| EXPECT_EQ(0, items[0].name_hash_index()); |
| EXPECT_FALSE(items[0].has_key()); |
| EXPECT_FALSE(items[0].has_value()); |
| } |
| |
| // Checks that applying metadata results in the expected application and removal |
| // of the metadata. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_Basic) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| // One metadata item should be recorded when the metadata starts. |
| EXPECT_EQ(1, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| // And one item should be recorded without value after the metadata ends. |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks that metadata items with different name hashes are applied |
| // independently. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_DifferentNameHashes) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(4, 30, 300); |
| metadata.ApplyMetadata(item1, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(2, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| EXPECT_EQ(4u, name_hashes[1]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| EXPECT_EQ(2, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes); |
| ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(2, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 1, name_hashes); |
| } |
| |
| // Checks that metadata items with different keys are applied independently. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_DifferentKeys) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 40, 300); |
| const base::ProfileBuilder::MetadataItem item3(3, base::nullopt, 300); |
| metadata.ApplyMetadata(item1, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| metadata.ApplyMetadata(item3, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| EXPECT_EQ(3, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes); |
| ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes); |
| ExpectMetadataApplied(item3, stack_samples, 1, 2, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(3, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 1, name_hashes); |
| ExpectMetadataUnapplied(item3, stack_samples, 4, 2, name_hashes); |
| } |
| |
| // Checks that applying to an empty range has no effect. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_EmptyRange) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 1, &stack_samples, |
| &name_hashes); |
| |
| EXPECT_EQ(0, name_hashes.size()); |
| |
| for (int i = 0; i < 5; i++) |
| EXPECT_EQ(0, stack_samples[i].metadata_size()); |
| } |
| |
| // Checks that applying metadata through the end is recorded as unapplied on the |
| // next sample taken. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_ThroughEnd) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, stack_samples.end(), |
| &stack_samples, &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| // One metadata item should be recorded when the metadata starts. |
| EXPECT_EQ(1, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| EXPECT_EQ(0, stack_samples[4].metadata_size()); |
| |
| base::MetadataRecorder metadata_recorder; |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| // And the following sample should have the metadata unapplied. |
| ExpectMetadataUnapplied(item, stack_samples, 5, 0, name_hashes); |
| } |
| |
| // Checks that metadata is properly applied when mixing RecordMetadata and |
| // ApplyMetadata over the same samples. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_WithRecordMetadata) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(5, 50, 500); |
| |
| stack_samples.Add(); |
| |
| // Apply then remove item1. |
| metadata_recorder.Set(item1.name_hash, *item1.key, item1.value); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata_recorder.Remove(item1.name_hash, *item1.key); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| stack_samples.Add(); |
| |
| ASSERT_EQ(5, stack_samples.size()); |
| |
| // Apply item2. |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(2, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| EXPECT_EQ(5u, name_hashes[1]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| // Each of the two items should be recorded when their metadata starts. |
| ASSERT_EQ(2, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 1, 0, name_hashes); |
| ExpectMetadataApplied(item2, stack_samples, 1, 1, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| |
| // The original item should still be present. |
| EXPECT_EQ(1, stack_samples[3].metadata_size()); |
| ExpectMetadataUnapplied(item1, stack_samples, 3, 0, name_hashes); |
| |
| // And one item should be recorded without value after the metadata ends. |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks that metadata is properly applied when using ApplyMetadata while |
| // a RecordMetadata-applied value is active. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_WithActiveMetadata) { |
| base::MetadataRecorder metadata_recorder; |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| // Record item1 on an ongoing basis via RecordMetadata. |
| metadata_recorder.Set(item1.name_hash, *item1.key, item1.value); |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| ASSERT_EQ(3, stack_samples.size()); |
| |
| // Apply item2 via ApplyMetadata up to the last sample. |
| metadata.ApplyMetadata(item2, stack_samples.begin(), stack_samples.end(), |
| &stack_samples, &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| |
| // The next recorded sample should have item1 applied since it's still active. |
| metadata.RecordMetadata(metadata_recorder.CreateMetadataProvider().get()); |
| *stack_samples.Add()->mutable_metadata() = |
| metadata.CreateSampleMetadata(&name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[3].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 3, 0, name_hashes); |
| } |
| |
| // Checks application of the same item across non-overlapping ranges. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_IndependentRanges) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| // Apply metadata over two non-overlapping ranges. |
| metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2, |
| &stack_samples, &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin() + 3, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[2].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 2, 0, name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[3].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 3, 0, name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of the same item across back-to-back ranges. The common |
| // sample should not have a metadata item set because it's unnecessary. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_BackToBackRanges) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| // Apply metadata over two ranges where the second starts on the same sample |
| // that the first ends. This should result in one range covering both. |
| metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2, |
| &stack_samples, &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin() + 2, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of different values across back-to-back ranges. The common |
| // sample must have the second metadata value set. |
| TEST(CallStackProfileMetadataTest, |
| ApplyMetadata_BackToBackRangesWithDifferentValues) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| metadata.ApplyMetadata(item1, stack_samples.begin(), |
| stack_samples.begin() + 2, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 2, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[2].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 2, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of the same item over a range within a range where the |
| // item was already set. No metadata changes should be recorded on the interior |
| // range because they are unnecessary. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateWithinExistingRange) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 4, |
| &stack_samples, &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 3, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of a second value over a range within a range where the |
| // first value was already set. Metadata changes for the second value must be |
| // recorded on the interior range. |
| TEST(CallStackProfileMetadataTest, |
| ApplyMetadata_UpdateWithinExistingRangeWithDifferentValues) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| // Apply metadata over a range, then over a range fully enclosed within the |
| // first one. |
| metadata.ApplyMetadata(item1, stack_samples.begin(), |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 1, |
| stack_samples.begin() + 3, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[3].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 3, 0, name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item1, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of the same item over a range enclosing a range where the |
| // item was already set. No metadata changes should be recorded on the interior |
| // range because they are unnecessary. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateEnclosesExistingRange) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| // Apply metadata over a range, then over a range that fully encloses the |
| // first one. |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 3, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 4, |
| &stack_samples, &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of a second value over a range enclosing a range where the |
| // first value was already set. Metadata changes for both values must be |
| // recorded. |
| TEST(CallStackProfileMetadataTest, |
| ApplyMetadata_UpdateEnclosesExistingRangeWithDifferentValues) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| // Apply metadata over a range, then over a range that fully encloses the |
| // first one. |
| metadata.ApplyMetadata(item1, stack_samples.begin() + 1, |
| stack_samples.begin() + 3, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item2, stack_samples.begin(), |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of an item over a range overlapping the start (but not |
| // end) of a range where the item was already set. No metadata changes should be |
| // recorded on the interior application because it is unnecessary. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateOverlapsBegin) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| // Apply metadata over a range, then over a range that overlaps the beginning |
| // (but not the end) of first one. |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 3, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2, |
| &stack_samples, &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[3].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 3, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[4].metadata_size()); |
| } |
| |
| // Checks application of a second different value over a range overlapping the |
| // start (but not end) of a range where the first value was already |
| // set. Metadata changes must be recorded on the interior application. |
| TEST(CallStackProfileMetadataTest, |
| ApplyMetadata_UpdateOverlapsBeginWithDifferentValues) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| // Apply metadata over a range, then over a range that overlaps the beginning |
| // (but not the end) of first one. |
| metadata.ApplyMetadata(item1, stack_samples.begin() + 1, |
| stack_samples.begin() + 3, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item2, stack_samples.begin(), |
| stack_samples.begin() + 2, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(1, stack_samples[2].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 2, 0, name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[3].metadata_size()); |
| ExpectMetadataUnapplied(item1, stack_samples, 3, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[4].metadata_size()); |
| } |
| |
| // Checks application of an item over a range overlapping the end (but not |
| // start) of a range where the item was already set. No metadata changes should |
| // be recorded on the interior application because it is unnecessary. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateOverlapsEnd) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| // Apply metadata over a range, then over a range that overlaps the beginning |
| // (but not the end) of first one. |
| metadata.ApplyMetadata(item, stack_samples.begin(), stack_samples.begin() + 2, |
| &stack_samples, &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[1].metadata_size()); |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks application of a second different value over a range overlapping the |
| // end (but not start) of a range where the first value was already |
| // set. Metadata changes must be recorded on the interior application. |
| TEST(CallStackProfileMetadataTest, |
| ApplyMetadata_UpdateOverlapsEndWithDifferentValues) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| // Apply metadata over a range, then over a range that overlaps the beginning |
| // (but not the end) of first one. |
| metadata.ApplyMetadata(item1, stack_samples.begin(), |
| stack_samples.begin() + 2, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(1, stack_samples[0].metadata_size()); |
| ExpectMetadataApplied(item1, stack_samples, 0, 0, name_hashes); |
| |
| EXPECT_EQ(1, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks that updating the same range multiple times with the same item |
| // produces the same result as what we'd expect with just one update. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_Update) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item(3, 30, 300); |
| |
| // Apply metadata over the same range with one value, then a different value. |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item, stack_samples, 1, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item, stack_samples, 4, 0, name_hashes); |
| } |
| |
| // Checks that applying to the same range with a different value overwrites the |
| // initial value. |
| TEST(CallStackProfileMetadataTest, ApplyMetadata_UpdateWithDifferentValues) { |
| CallStackProfileMetadata metadata; |
| google::protobuf::RepeatedPtrField<CallStackProfile::StackSample> |
| stack_samples; |
| google::protobuf::RepeatedField<uint64_t> name_hashes; |
| |
| for (int i = 0; i < 5; i++) |
| stack_samples.Add(); |
| |
| const base::ProfileBuilder::MetadataItem item1(3, 30, 300); |
| const base::ProfileBuilder::MetadataItem item2(3, 30, 400); |
| |
| // Apply metadata over the same range with one value, then a different value. |
| metadata.ApplyMetadata(item1, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| metadata.ApplyMetadata(item2, stack_samples.begin() + 1, |
| stack_samples.begin() + 4, &stack_samples, |
| &name_hashes); |
| |
| ASSERT_EQ(1, name_hashes.size()); |
| EXPECT_EQ(3u, name_hashes[0]); |
| |
| EXPECT_EQ(0, stack_samples[0].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[1].metadata_size()); |
| ExpectMetadataApplied(item2, stack_samples, 1, 0, name_hashes); |
| |
| EXPECT_EQ(0, stack_samples[2].metadata_size()); |
| EXPECT_EQ(0, stack_samples[3].metadata_size()); |
| |
| EXPECT_EQ(1, stack_samples[4].metadata_size()); |
| ExpectMetadataUnapplied(item2, stack_samples, 4, 0, name_hashes); |
| } |
| |
| } // namespace metrics |