| // 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 "base/strings/stringprintf.h" |
| #include "base/timer/lap_timer.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/perf/perf_result_reporter.h" |
| #include "ui/accessibility/ax_node_position.h" |
| #include "ui/accessibility/ax_serializable_tree.h" |
| #include "ui/accessibility/ax_tree_serializer.h" |
| #include "ui/accessibility/ax_tree_update.h" |
| |
| namespace ui { |
| |
| using TestPositionType = std::unique_ptr<AXPosition<AXNodePosition, AXNode>>; |
| |
| namespace { |
| |
| constexpr int kLaps = 5000; |
| constexpr int kWarmupLaps = 5; |
| constexpr char kMetricCallsPerSecondRunsPerS[] = "calls_per_second"; |
| |
| class AXPositionPerfTest : public testing::Test { |
| public: |
| AXPositionPerfTest() = default; |
| ~AXPositionPerfTest() override = default; |
| |
| protected: |
| void SetUp() override; |
| void TearDown() override; |
| |
| perf_test::PerfResultReporter SetUpReporter(const std::string& story) { |
| perf_test::PerfResultReporter reporter("AXPositionPerfTest.", story); |
| reporter.RegisterImportantMetric(kMetricCallsPerSecondRunsPerS, "runs/s"); |
| return reporter; |
| } |
| |
| AXTree tree_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AXPositionPerfTest); |
| }; |
| |
| void AXPositionPerfTest::SetUp() { |
| // Setup a root with 5 child kGenericContainer with 5 kStaticText each. |
| // Each kStaticText contains 5 characters of text. |
| // |
| // +------------------------+--------------+ |
| // | Tree Hierarchy + Role | anchor_id(s) | |
| // +------------------------+--------------+ |
| // | ++kRootWebArea | 1 | |
| // | ++++kGenericContainer | 2 | |
| // | ++++++kStaticText | 7 - 11 | |
| // | ++++kGenericContainer | 3 | |
| // | ++++++kStaticText | 12 - 16 | |
| // | ++++kGenericContainer | 4 | |
| // | ++++++kStaticText | 17 - 21 | |
| // | ++++kGenericContainer | 5 | |
| // | ++++++kStaticText | 22 - 26 | |
| // | ++++kGenericContainer | 6 | |
| // | ++++++kStaticText | 27 - 31 | |
| // +------------------------+--------------+ |
| |
| constexpr int kNumberOfGroups = 5; |
| constexpr int kStaticTextNodesPerGroup = 5; |
| constexpr int kNumberOfStaticTextNodes = |
| kNumberOfGroups * kStaticTextNodesPerGroup; |
| |
| constexpr int kGroupNodesStartIndex = 1; |
| constexpr int kStaticTextNodesStartIndex = |
| kGroupNodesStartIndex + kNumberOfGroups; |
| |
| AXNode::AXID current_id = 0; |
| std::vector<AXNodeData> nodes; |
| nodes.resize(1 + kNumberOfGroups + kNumberOfStaticTextNodes); |
| |
| AXNodeData& root_data = nodes[0]; |
| root_data.id = ++current_id; |
| root_data.role = ax::mojom::Role::kRootWebArea; |
| |
| for (int group_index = 0; group_index < kNumberOfGroups; ++group_index) { |
| AXNodeData& group = nodes[kGroupNodesStartIndex + group_index]; |
| group.id = ++current_id; |
| group.role = ax::mojom::Role::kGenericContainer; |
| root_data.child_ids.push_back(group.id); |
| } |
| |
| for (int text_index = 0; text_index < kNumberOfStaticTextNodes; |
| ++text_index) { |
| const int group_index = text_index / kStaticTextNodesPerGroup; |
| AXNodeData& group = nodes[kGroupNodesStartIndex + group_index]; |
| AXNodeData& static_text = nodes[kStaticTextNodesStartIndex + text_index]; |
| static_text.id = ++current_id; |
| static_text.role = ax::mojom::Role::kStaticText; |
| static_text.SetName(base::StringPrintf("id_%02X", static_text.id)); |
| group.child_ids.push_back(static_text.id); |
| } |
| |
| AXTreeUpdate initial_state; |
| initial_state.root_id = nodes[0].id; |
| initial_state.nodes = nodes; |
| initial_state.has_tree_data = true; |
| initial_state.tree_data.tree_id = AXTreeID::CreateNewAXTreeID(); |
| initial_state.tree_data.title = "Perftest title"; |
| AXSerializableTree src_tree(initial_state); |
| |
| std::unique_ptr<AXTreeSource<const AXNode*, AXNodeData, AXTreeData>> |
| tree_source(src_tree.CreateTreeSource()); |
| AXTreeSerializer<const AXNode*, AXNodeData, AXTreeData> serializer( |
| tree_source.get()); |
| AXTreeUpdate update; |
| serializer.SerializeChanges(src_tree.root(), &update); |
| ASSERT_TRUE(tree_.Unserialize(update)); |
| AXNodePosition::SetTree(&tree_); |
| } |
| |
| void AXPositionPerfTest::TearDown() { |
| AXNodePosition::SetTree(nullptr); |
| } |
| |
| } // namespace |
| |
| TEST_F(AXPositionPerfTest, AsTreePositionFromTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, /*anchor_id=*/1, /*text_offset=*/103, |
| ax::mojom::TextAffinity::kDownstream); |
| |
| // The time limit is unused. Use kLaps for the check interval so the time is |
| // only measured once. |
| base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps); |
| for (int i = 0; i < kLaps + kWarmupLaps; ++i) { |
| TestPositionType as_tree_position = text_position->AsTreePosition(); |
| timer.NextLap(); |
| } |
| |
| auto reporter = SetUpReporter("AsTreePositionFromTextPosition"); |
| reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond()); |
| } |
| |
| TEST_F(AXPositionPerfTest, AsLeafTextPositionFromTextPosition) { |
| TestPositionType text_position = AXNodePosition::CreateTextPosition( |
| tree_.data().tree_id, /*anchor_id=*/1, /*text_offset=*/103, |
| ax::mojom::TextAffinity::kDownstream); |
| |
| // The time limit is unused. Use kLaps for the check interval so the time is |
| // only measured once. |
| base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps); |
| for (int i = 0; i < kLaps + kWarmupLaps; ++i) { |
| TestPositionType as_tree_position = text_position->AsLeafTextPosition(); |
| timer.NextLap(); |
| } |
| |
| auto reporter = SetUpReporter("AsLeafTextPositionFromTextPosition"); |
| reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond()); |
| } |
| |
| TEST_F(AXPositionPerfTest, AsLeafTextPositionFromTreePosition) { |
| TestPositionType tree_position = AXNodePosition::CreateTreePosition( |
| tree_.data().tree_id, /*anchor_id=*/1, /*child_index=*/4); |
| |
| base::LapTimer timer(kWarmupLaps, base::TimeDelta(), kLaps); |
| for (int i = 0; i < kLaps + kWarmupLaps; ++i) { |
| TestPositionType as_tree_position = tree_position->AsLeafTextPosition(); |
| timer.NextLap(); |
| } |
| |
| auto reporter = SetUpReporter("AsLeafTextPositionFromTreePosition"); |
| reporter.AddResult(kMetricCallsPerSecondRunsPerS, timer.LapsPerSecond()); |
| } |
| |
| } // namespace ui |