Commit ab73cc04 authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

Add kCustom type FrameSequenceTracker

- Add FrameSequenceTrackerType::kCustom;
- Add FrameSequenceTrackerCollection::StartCustomSequence to create
  a kCustom typed tracker to represent a sequence;
- Add FrameSequenceTrackerCollection::StopCustomSequence to schedule
  termination of a tracker for a sequence;
- Data collected by custom trackers are reported via the return
  value of FrameSequenceTrackerCollection::TakeCustomTrackerResults;

Bug: 1021774
Change-Id: I62d9c2eb833e1d40e01b3b452d515ce361233a64
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2007937
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754680}
parent 1808574c
......@@ -53,6 +53,8 @@ const char* FrameSequenceTracker::GetFrameSequenceTrackerTypeName(
return "WheelScroll";
case FrameSequenceTrackerType::kScrollbarScroll:
return "ScrollbarScroll";
case FrameSequenceTrackerType::kCustom:
return "Custom";
case FrameSequenceTrackerType::kMaxType:
return "";
}
......@@ -178,6 +180,7 @@ FrameSequenceMetrics::ThreadType FrameSequenceMetrics::GetEffectiveThread()
case FrameSequenceTrackerType::kUniversal:
return ThreadType::kSlower;
case FrameSequenceTrackerType::kCustom:
case FrameSequenceTrackerType::kMaxType:
NOTREACHED();
}
......@@ -230,6 +233,11 @@ void FrameSequenceMetrics::ReportMetrics() {
ThroughputData::ToTracedValue(impl_throughput_, main_throughput_),
"checkerboard", frames_checkerboarded_);
// Data for kCustom typed tracker is handled by caller instead being
// reported here.
if (type_ == FrameSequenceTrackerType::kCustom)
return;
ComputeAggregatedThroughput();
// Report the throughput metrics.
......@@ -337,6 +345,8 @@ FrameSequenceTrackerCollection::~FrameSequenceTrackerCollection() {
FrameSequenceMetrics* FrameSequenceTrackerCollection::StartSequence(
FrameSequenceTrackerType type) {
DCHECK_NE(FrameSequenceTrackerType::kCustom, type);
if (is_single_threaded_)
return nullptr;
if (frame_trackers_.contains(type))
......@@ -352,6 +362,8 @@ FrameSequenceMetrics* FrameSequenceTrackerCollection::StartSequence(
void FrameSequenceTrackerCollection::StopSequence(
FrameSequenceTrackerType type) {
DCHECK_NE(FrameSequenceTrackerType::kCustom, type);
if (!frame_trackers_.contains(type))
return;
......@@ -366,8 +378,30 @@ void FrameSequenceTrackerCollection::StopSequence(
removal_trackers_.push_back(std::move(tracker));
}
void FrameSequenceTrackerCollection::StartCustomSequence(int sequence_id) {
DCHECK(!base::Contains(custom_frame_trackers_, sequence_id));
custom_frame_trackers_[sequence_id] = base::WrapUnique(
new FrameSequenceTracker(FrameSequenceTrackerType::kCustom,
/*throughput_ukm_reporter=*/nullptr,
/*custom_sequence_id=*/sequence_id));
}
void FrameSequenceTrackerCollection::StopCustomSequence(int sequence_id) {
auto it = custom_frame_trackers_.find(sequence_id);
// This happens when an animation is aborted before starting.
if (it == custom_frame_trackers_.end())
return;
std::unique_ptr<FrameSequenceTracker> tracker = std::move(it->second);
custom_frame_trackers_.erase(it);
tracker->ScheduleTerminate();
removal_trackers_.push_back(std::move(tracker));
}
void FrameSequenceTrackerCollection::ClearAll() {
frame_trackers_.clear();
custom_frame_trackers_.clear();
removal_trackers_.clear();
}
......@@ -376,37 +410,47 @@ void FrameSequenceTrackerCollection::NotifyBeginImplFrame(
RecreateTrackers(args);
for (auto& tracker : frame_trackers_)
tracker.second->ReportBeginImplFrame(args);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportBeginImplFrame(args);
}
void FrameSequenceTrackerCollection::NotifyBeginMainFrame(
const viz::BeginFrameArgs& args) {
for (auto& tracker : frame_trackers_)
tracker.second->ReportBeginMainFrame(args);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportBeginMainFrame(args);
}
void FrameSequenceTrackerCollection::NotifyMainFrameProcessed(
const viz::BeginFrameArgs& args) {
for (auto& tracker : frame_trackers_)
tracker.second->ReportMainFrameProcessed(args);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportMainFrameProcessed(args);
}
void FrameSequenceTrackerCollection::NotifyImplFrameCausedNoDamage(
const viz::BeginFrameAck& ack) {
for (auto& tracker : frame_trackers_) {
for (auto& tracker : frame_trackers_)
tracker.second->ReportImplFrameCausedNoDamage(ack);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportImplFrameCausedNoDamage(ack);
}
}
void FrameSequenceTrackerCollection::NotifyMainFrameCausedNoDamage(
const viz::BeginFrameArgs& args) {
for (auto& tracker : frame_trackers_) {
for (auto& tracker : frame_trackers_)
tracker.second->ReportMainFrameCausedNoDamage(args);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportMainFrameCausedNoDamage(args);
}
}
void FrameSequenceTrackerCollection::NotifyPauseFrameProduction() {
for (auto& tracker : frame_trackers_)
tracker.second->PauseFrameProduction();
for (auto& tracker : custom_frame_trackers_)
tracker.second->PauseFrameProduction();
}
void FrameSequenceTrackerCollection::NotifySubmitFrame(
......@@ -418,14 +462,19 @@ void FrameSequenceTrackerCollection::NotifySubmitFrame(
tracker.second->ReportSubmitFrame(frame_token, has_missing_content, ack,
origin_args);
}
for (auto& tracker : custom_frame_trackers_) {
tracker.second->ReportSubmitFrame(frame_token, has_missing_content, ack,
origin_args);
}
}
void FrameSequenceTrackerCollection::NotifyFrameEnd(
const viz::BeginFrameArgs& args,
const viz::BeginFrameArgs& main_args) {
for (auto& tracker : frame_trackers_) {
for (auto& tracker : frame_trackers_)
tracker.second->ReportFrameEnd(args, main_args);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportFrameEnd(args, main_args);
}
}
void FrameSequenceTrackerCollection::NotifyFramePresented(
......@@ -433,6 +482,8 @@ void FrameSequenceTrackerCollection::NotifyFramePresented(
const gfx::PresentationFeedback& feedback) {
for (auto& tracker : frame_trackers_)
tracker.second->ReportFramePresented(frame_token, feedback);
for (auto& tracker : custom_frame_trackers_)
tracker.second->ReportFramePresented(frame_token, feedback);
for (auto& tracker : removal_trackers_)
tracker->ReportFramePresented(frame_token, feedback);
......@@ -440,12 +491,23 @@ void FrameSequenceTrackerCollection::NotifyFramePresented(
for (auto& tracker : removal_trackers_) {
if (tracker->termination_status() ==
FrameSequenceTracker::TerminationStatus::kReadyForTermination) {
// The tracker is ready to be terminated. Take the metrics from the
// tracker, merge with any outstanding metrics from previous trackers of
// the same type. If there are enough frames to report the metrics, then
// report the metrics and destroy it. Otherwise, retain it to be merged
// with follow-up sequences.
// The tracker is ready to be terminated.
// For non kCustom typed trackers, take the metrics from the tracker.
// merge with any outstanding metrics from previous trackers of the same
// type. If there are enough frames to report the metrics, then report the
// metrics and destroy it. Otherwise, retain it to be merged with
// follow-up sequences.
// For kCustom typed trackers, put its result in |custom_tracker_results_|
// to be picked up by caller.
auto metrics = tracker->TakeMetrics();
if (tracker->type() == FrameSequenceTrackerType::kCustom) {
custom_tracker_results_[tracker->custom_sequence_id()] =
metrics->main_throughput();
// |custom_tracker_results_| should be picked up timely.
DCHECK_LT(custom_tracker_results_.size(), 500u);
continue;
}
auto key = std::make_pair(tracker->type(), metrics->GetEffectiveThread());
if (accumulated_metrics_.contains(key)) {
metrics->Merge(std::move(accumulated_metrics_[key]));
......@@ -514,6 +576,11 @@ FrameSequenceTrackerCollection::FrameSequenceTrackerActiveTypes() {
return encoded_types;
}
CustomTrackerResults
FrameSequenceTrackerCollection::TakeCustomTrackerResults() {
return std::move(custom_tracker_results_);
}
FrameSequenceTracker* FrameSequenceTrackerCollection::GetTrackerForTesting(
FrameSequenceTrackerType type) {
if (!frame_trackers_.contains(type))
......@@ -534,16 +601,19 @@ void FrameSequenceTrackerCollection::SetUkmManager(UkmManager* manager) {
FrameSequenceTracker::FrameSequenceTracker(
FrameSequenceTrackerType type,
ThroughputUkmReporter* throughput_ukm_reporter)
ThroughputUkmReporter* throughput_ukm_reporter,
int custom_sequence_id)
: type_(type),
custom_sequence_id_(custom_sequence_id),
metrics_(std::make_unique<FrameSequenceMetrics>(type,
throughput_ukm_reporter)),
trace_data_(metrics_.get()) {
DCHECK_LT(type_, FrameSequenceTrackerType::kMaxType);
DCHECK(type_ != FrameSequenceTrackerType::kCustom ||
custom_sequence_id_ >= 0);
}
FrameSequenceTracker::~FrameSequenceTracker() {
}
FrameSequenceTracker::~FrameSequenceTracker() = default;
void FrameSequenceTracker::ScheduleTerminate() {
termination_status_ = TerminationStatus::kScheduledForTermination;
......
......@@ -48,6 +48,8 @@ enum class FrameSequenceTrackerType {
kVideo = 6,
kWheelScroll = 7,
kScrollbarScroll = 8,
kCustom = 9, // Note that the metrics for kCustom are not reported on UMA,
// and instead are dispatched back to the LayerTreeHostClient.
kMaxType
};
......@@ -150,6 +152,10 @@ class CC_EXPORT FrameSequenceMetrics {
uint32_t frames_checkerboarded_ = 0;
};
// Map of kCustom tracker results keyed by a sequence id.
using CustomTrackerResults =
base::flat_map<int, FrameSequenceMetrics::ThroughputData>;
// Used for notifying attached FrameSequenceTracker's of begin-frames and
// submitted frames.
class CC_EXPORT FrameSequenceTrackerCollection {
......@@ -173,6 +179,16 @@ class CC_EXPORT FrameSequenceTrackerCollection {
// for all submitted frames.
void StopSequence(FrameSequenceTrackerType type);
// Creates a kCustom tracker for the given sequence id. It is an error and
// DCHECKs if there is already a tracker associated with the sequence id.
void StartCustomSequence(int sequence_id);
// Schedules the kCustom tracker representing |sequence_id| for destruction.
// It is a no-op if there is no tracker associated with the sequence id.
// Similar to StopSequence above, the tracker instance is destroyed *after*
// the presentation feedbacks have been received for all submitted frames.
void StopCustomSequence(int sequence_id);
// Removes all trackers. This also immediately destroys all trackers that had
// been scheduled for destruction, even if there are pending
// presentation-feedbacks. This is typically used if the client no longer
......@@ -196,7 +212,9 @@ class CC_EXPORT FrameSequenceTrackerCollection {
// Note that this notifies the trackers of the presentation-feedbacks, and
// destroys any tracker that had been scheduled for destruction (using
// |ScheduleRemoval()|) if it has no more pending frames.
// |ScheduleRemoval()|) if it has no more pending frames. Data from non
// kCustom typed trackers are reported to UMA. Data from kCustom typed
// trackers are added to |custom_tracker_results_| for caller to pick up.
void NotifyFramePresented(uint32_t frame_token,
const gfx::PresentationFeedback& feedback);
......@@ -205,6 +223,9 @@ class CC_EXPORT FrameSequenceTrackerCollection {
// each type.
ActiveFrameSequenceTrackers FrameSequenceTrackerActiveTypes();
// Reports the accumulated kCustom tracker results and clears it.
CustomTrackerResults TakeCustomTrackerResults();
FrameSequenceTracker* GetTrackerForTesting(FrameSequenceTrackerType type);
void SetUkmManager(UkmManager* manager);
......@@ -219,6 +240,12 @@ class CC_EXPORT FrameSequenceTrackerCollection {
base::flat_map<FrameSequenceTrackerType,
std::unique_ptr<FrameSequenceTracker>>
frame_trackers_;
// Custom trackers are keyed by a custom sequence id.
base::flat_map<int, std::unique_ptr<FrameSequenceTracker>>
custom_frame_trackers_;
CustomTrackerResults custom_tracker_results_;
std::vector<std::unique_ptr<FrameSequenceTracker>> removal_trackers_;
CompositorFrameReportingController* const
compositor_frame_reporting_controller_;
......@@ -304,6 +331,7 @@ class CC_EXPORT FrameSequenceTracker {
FrameSequenceMetrics* metrics() { return metrics_.get(); }
FrameSequenceTrackerType type() const { return type_; }
int custom_sequence_id() const { return custom_sequence_id_; }
std::unique_ptr<FrameSequenceMetrics> TakeMetrics();
......@@ -312,7 +340,8 @@ class CC_EXPORT FrameSequenceTracker {
friend class FrameSequenceTrackerTest;
FrameSequenceTracker(FrameSequenceTrackerType type,
ThroughputUkmReporter* throughput_ukm_reporter);
ThroughputUkmReporter* throughput_ukm_reporter,
int custom_sequence_id = -1);
FrameSequenceMetrics::ThroughputData& impl_throughput() {
return metrics_->impl_throughput();
......@@ -361,6 +390,7 @@ class CC_EXPORT FrameSequenceTracker {
bool ShouldIgnoreSequence(uint64_t sequence_number) const;
const FrameSequenceTrackerType type_;
const int custom_sequence_id_;
TerminationStatus termination_status_ = TerminationStatus::kActive;
......
......@@ -233,6 +233,9 @@ class FrameSequenceTrackerTest : public testing::Test {
unsigned NumberOfTrackers() const {
return collection_.frame_trackers_.size();
}
unsigned NumberOfCustomTrackers() const {
return collection_.custom_frame_trackers_.size();
}
unsigned NumberOfRemovalTrackers() const {
return collection_.removal_trackers_.size();
}
......@@ -1223,4 +1226,54 @@ TEST_F(FrameSequenceTrackerTest, TrackerTypeEncoding) {
EXPECT_EQ(active_encoded, 16); // 1 << 4
}
TEST_F(FrameSequenceTrackerTest, CustomTrackers) {
// Start custom tracker 1.
collection_.StartCustomSequence(1);
EXPECT_EQ(1u, NumberOfCustomTrackers());
// No reports.
uint32_t frame_token = 1u;
collection_.NotifyFramePresented(frame_token, {});
auto results = collection_.TakeCustomTrackerResults();
EXPECT_EQ(0u, results.size());
// Start custom tracker 2 and 3 in addition to 1.
collection_.StartCustomSequence(2);
collection_.StartCustomSequence(3);
EXPECT_EQ(3u, NumberOfCustomTrackers());
// All custom trackers are running. No reports.
collection_.NotifyFramePresented(frame_token, {});
results = collection_.TakeCustomTrackerResults();
EXPECT_EQ(0u, results.size());
// Tracker 2 is stopped and scheduled to terminate.
collection_.StopCustomSequence(2);
EXPECT_EQ(2u, NumberOfCustomTrackers());
// Tracker 2 should report with no data.
collection_.NotifyFramePresented(frame_token, {});
results = collection_.TakeCustomTrackerResults();
EXPECT_EQ(1u, results.size());
EXPECT_EQ(0u, results[2].frames_expected);
// Simple sequence of one frame.
const char sequence[] = "b(1)B(0,1)s(1)S(1)e(1,0)P(1)";
GenerateSequence(sequence);
// Stop all custom trackers.
collection_.StopCustomSequence(1);
collection_.StopCustomSequence(3);
EXPECT_EQ(0u, NumberOfCustomTrackers());
// Tracker 1 and 3 and should report.
collection_.NotifyFramePresented(frame_token, {});
results = collection_.TakeCustomTrackerResults();
EXPECT_EQ(2u, results.size());
EXPECT_EQ(1u, results[1].frames_produced);
EXPECT_EQ(1u, results[1].frames_expected);
EXPECT_EQ(1u, results[3].frames_produced);
EXPECT_EQ(1u, results[3].frames_expected);
}
} // namespace cc
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment