123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- // Copyright 2019 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/performance_manager/public/graph/node_attached_data.h"
- #include <utility>
- #include "base/memory/raw_ptr.h"
- #include "base/test/gtest_util.h"
- #include "components/performance_manager/graph/frame_node_impl.h"
- #include "components/performance_manager/graph/graph_impl.h"
- #include "components/performance_manager/graph/node_attached_data_impl.h"
- #include "components/performance_manager/graph/node_base.h"
- #include "components/performance_manager/graph/page_node_impl.h"
- #include "components/performance_manager/graph/process_node_impl.h"
- #include "components/performance_manager/graph/system_node_impl.h"
- #include "components/performance_manager/public/graph/node.h"
- #include "components/performance_manager/test_support/graph_test_harness.h"
- #include "components/performance_manager/test_support/mock_graphs.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace performance_manager {
- namespace {
- // Note that a FooData basically has pointer size, because its an empty class
- // with a single vtable pointer.
- constexpr size_t kFooDataSize = sizeof(uintptr_t);
- // A dummy node type so that we can exercise node attached storage code paths.
- class DummyNode : public NodeBase, public Node {
- public:
- DummyNode() : NodeBase(NodeTypeEnum::kInvalidType) {}
- DummyNode(const DummyNode&) = delete;
- DummyNode& operator=(const DummyNode&) = delete;
- ~DummyNode() override = default;
- // NodeBase implementation:
- const Node* ToNode() const override { return static_cast<const Node*>(this); }
- void RemoveNodeAttachedData() override {}
- // Node implementation:
- Graph* GetGraph() const override { return graph(); }
- NodeState GetNodeState() const override { return NodeState::kActiveInGraph; }
- uintptr_t GetImplType() const override {
- static const uintptr_t kImplType = reinterpret_cast<uintptr_t>(&kImplType);
- return kImplType;
- }
- const void* GetImpl() const override {
- return static_cast<const NodeBase*>(this);
- }
- static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kInvalidType; }
- // Internal storage for DummyData and FooData types. These would normally be
- // protected and the data classes friended, but we also want to access these
- // in the tests.
- std::unique_ptr<NodeAttachedData> dummy_data_;
- InternalNodeAttachedDataStorage<kFooDataSize> foo_data_;
- };
- // A NodeAttachedData class that can only be attached to page and process nodes
- // using the map, and to DummyNodes using node owned storage.
- class DummyData : public NodeAttachedDataImpl<DummyData> {
- public:
- struct Traits : public NodeAttachedDataInMap<PageNodeImpl>,
- public NodeAttachedDataInMap<ProcessNodeImpl>,
- public NodeAttachedDataOwnedByNodeType<DummyNode> {};
- DummyData() = default;
- explicit DummyData(const PageNodeImpl* page_node) {}
- explicit DummyData(const ProcessNodeImpl* process_node) {}
- explicit DummyData(const DummyNode* dummy_node) {}
- DummyData(const DummyData&) = delete;
- DummyData& operator=(const DummyData&) = delete;
- ~DummyData() override = default;
- // Provides access to storage on DummyNodes.
- static std::unique_ptr<NodeAttachedData>* GetUniquePtrStorage(
- DummyNode* dummy_node) {
- return &dummy_node->dummy_data_;
- }
- };
- // Another NodeAttachedData class that can only be attached to page nodes in the
- // map, and to DummyNodes using node internal storage.
- class FooData : public NodeAttachedDataImpl<FooData> {
- public:
- struct Traits : public NodeAttachedDataInMap<PageNodeImpl>,
- public NodeAttachedDataInternalOnNodeType<DummyNode> {};
- FooData() = default;
- explicit FooData(const PageNodeImpl* page_node) {}
- explicit FooData(const DummyNode* dummy_node) {}
- FooData(const FooData&) = delete;
- FooData& operator=(const FooData&) = delete;
- ~FooData() override = default;
- // Provides access to storage on DummyNodes.
- static InternalNodeAttachedDataStorage<kFooDataSize>* GetInternalStorage(
- DummyNode* dummy_node) {
- return &dummy_node->foo_data_;
- }
- };
- // An implementation of map-stored user-data using the public interface.
- class BarData : public ExternalNodeAttachedDataImpl<BarData> {
- public:
- explicit BarData(const PageNode* page_node) : page_node_(page_node) {}
- ~BarData() override = default;
- raw_ptr<const PageNode> page_node_ = nullptr;
- };
- } // namespace
- class NodeAttachedDataTest : public GraphTestHarness {
- public:
- NodeAttachedDataTest() = default;
- ~NodeAttachedDataTest() override = default;
- static void AttachInMap(const Node* node,
- std::unique_ptr<NodeAttachedData> data) {
- return NodeAttachedDataMapHelper::AttachInMap(node, std::move(data));
- }
- // Retrieves the data associated with the provided |node| and |key|. This
- // returns nullptr if no data exists.
- static NodeAttachedData* GetFromMap(const Node* node, const void* key) {
- return NodeAttachedDataMapHelper::GetFromMap(node, key);
- }
- // Detaches the data associated with the provided |node| and |key|. It is
- // harmless to call this when no data exists.
- static std::unique_ptr<NodeAttachedData> DetachFromMap(const Node* node,
- const void* key) {
- return NodeAttachedDataMapHelper::DetachFromMap(node, key);
- }
- };
- TEST_F(NodeAttachedDataTest, UserDataKey) {
- std::unique_ptr<NodeAttachedData> data = std::make_unique<DummyData>();
- EXPECT_EQ(data->GetKey(), DummyData::UserDataKey());
- }
- TEST_F(NodeAttachedDataTest, RawAttachDetach) {
- MockSinglePageInSingleProcessGraph mock_graph(graph());
- auto* page_node = mock_graph.page.get();
- static constexpr NodeAttachedData* kNull = nullptr;
- std::unique_ptr<DummyData> data = std::make_unique<DummyData>();
- auto* raw_data = data.get();
- auto* raw_base = static_cast<NodeAttachedData*>(raw_data);
- // No data yet exists.
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(kNull, GetFromMap(page_node, raw_data->GetKey()));
- // Attach the data and look it up again.
- AttachInMap(page_node, std::move(data));
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(raw_base, GetFromMap(page_node, raw_data->GetKey()));
- // Detach the data.
- std::unique_ptr<NodeAttachedData> base_data =
- DetachFromMap(page_node, raw_data->GetKey());
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(raw_base, base_data.get());
- EXPECT_EQ(kNull, GetFromMap(page_node, raw_data->GetKey()));
- }
- TEST_F(NodeAttachedDataTest, TypedAttachDetach) {
- MockSinglePageInSingleProcessGraph mock_graph(graph());
- auto* page_node = mock_graph.page.get();
- static constexpr DummyData* kNull = nullptr;
- // Lookup non-existent data.
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(kNull, DummyData::Get(page_node));
- // Create the data and look it up again.
- auto* data = DummyData::GetOrCreate(page_node);
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_NE(kNull, data);
- EXPECT_EQ(data, DummyData::Get(page_node));
- // Destroy the data and expect it to no longer exist.
- EXPECT_TRUE(DummyData::Destroy(page_node));
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(kNull, DummyData::Get(page_node));
- }
- TEST_F(NodeAttachedDataTest, NodeDeathDestroysData) {
- MockSinglePageInSingleProcessGraph mock_graph(graph());
- auto* page_node = mock_graph.page.get();
- ProcessNodeImpl* proc_node = mock_graph.process.get();
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(
- page_node, DummyData::UserDataKey()));
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(
- proc_node, DummyData::UserDataKey()));
- // Add data to both the process and the page.
- DummyData::GetOrCreate(page_node);
- FooData::GetOrCreate(page_node);
- auto* proc_data = DummyData::GetOrCreate(proc_node);
- EXPECT_EQ(3u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(2u,
- graph()->GetNodeAttachedDataCountForTesting(page_node, nullptr));
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(
- proc_node, DummyData::UserDataKey()));
- // Release the page node and expect the node attached data to have been
- // cleaned up.
- mock_graph.frame.reset();
- mock_graph.page.reset();
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(0u,
- graph()->GetNodeAttachedDataCountForTesting(page_node, nullptr));
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(
- proc_node, DummyData::UserDataKey()));
- // The process data should still exist.
- EXPECT_EQ(proc_data, DummyData::Get(proc_node));
- }
- TEST_F(NodeAttachedDataTest, NodeOwnedStorage) {
- DummyNode dummy_node;
- // The storage in the dummy node should not be initialized.
- EXPECT_FALSE(dummy_node.dummy_data_.get());
- EXPECT_FALSE(DummyData::Get(&dummy_node));
- // Creating a DummyData on the DummyNode should not create storage in the map.
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- DummyData* dummy_data = DummyData::GetOrCreate(&dummy_node);
- NodeAttachedData* nad = static_cast<NodeAttachedData*>(dummy_data);
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- // The storage in the dummy node should now be initialized.
- EXPECT_EQ(nad, dummy_node.dummy_data_.get());
- EXPECT_EQ(dummy_data, DummyData::Get(&dummy_node));
- // Destroying the data should free up the storage.
- DummyData::Destroy(&dummy_node);
- EXPECT_FALSE(dummy_node.dummy_data_.get());
- EXPECT_FALSE(DummyData::Get(&dummy_node));
- }
- TEST_F(NodeAttachedDataTest, NodeInternalStorage) {
- DummyNode dummy_node;
- // The storage in the dummy node should not be initialized.
- EXPECT_FALSE(dummy_node.foo_data_.Get());
- EXPECT_FALSE(FooData::Get(&dummy_node));
- // Creating a FooData on the DummyNode should not create storage in the map.
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- FooData* foo_data = FooData::GetOrCreate(&dummy_node);
- NodeAttachedData* nad = static_cast<NodeAttachedData*>(foo_data);
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- // The storage in the dummy node should now be initialized.
- EXPECT_EQ(nad, dummy_node.foo_data_.Get());
- EXPECT_EQ(foo_data, FooData::Get(&dummy_node));
- // Destroying the data should free up the storage.
- FooData::Destroy(&dummy_node);
- EXPECT_FALSE(dummy_node.foo_data_.Get());
- EXPECT_FALSE(FooData::Get(&dummy_node));
- }
- TEST_F(NodeAttachedDataTest, PublicNodeAttachedData) {
- MockSinglePageInSingleProcessGraph mock_graph(graph());
- PageNodeImpl* page_node_impl = mock_graph.page.get();
- const PageNode* page_node = page_node_impl;
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- BarData* bar_data = BarData::Get(page_node);
- EXPECT_FALSE(bar_data);
- bar_data = BarData::GetOrCreate(page_node);
- EXPECT_TRUE(bar_data);
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(
- page_node_impl, bar_data->GetKey()));
- EXPECT_EQ(page_node, bar_data->page_node_);
- EXPECT_EQ(bar_data, BarData::Get(page_node));
- EXPECT_TRUE(BarData::Destroy(page_node));
- EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
- EXPECT_FALSE(BarData::Destroy(page_node));
- EXPECT_FALSE(BarData::Get(page_node));
- }
- } // namespace performance_manager
|