cc: Use FrameMetrics in LTHI.
Tracks throughput, latency, and smoothness of the
compositor thread.
Will output a trace that includes a summary of the
stats every time a frame is displayed.
Bug: 790759
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I85c68bf28e6ce72be8c0b84eca25b839d2126198
Reviewed-on: https://chromium-review.googlesource.com/1074192
Commit-Queue: Brian Anderson <brianderson@chromium.org>
Reviewed-by: Timothy Dresser <tdresser@chromium.org>
Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
Cr-Commit-Position: refs/heads/master@{#566141}diff --git a/cc/DEPS b/cc/DEPS
index cd44e0c..7b0e07a0 100644
--- a/cc/DEPS
+++ b/cc/DEPS
@@ -29,7 +29,7 @@
"+third_party/libyuv",
"+third_party/skia/include",
"+third_party/skia/src/core/SkRemoteGlyphCache.h",
- "+ui/latency/latency_info.h",
+ "+ui/latency",
"+ui/gfx",
"+ui/gl",
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 228a230d..97135f3 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -229,6 +229,25 @@
}
}
+ui::FrameMetricsSettings LTHI_FrameMetricsSettings(
+ const LayerTreeSettings& settings) {
+ ui::FrameMetricsSource source =
+ settings.commit_to_active_tree
+ ? ui::FrameMetricsSource::UiCompositor
+ : ui::FrameMetricsSource::RendererCompositor;
+ ui::FrameMetricsSourceThread source_thread =
+ settings.commit_to_active_tree
+ ? ui::FrameMetricsSourceThread::UiCompositor
+ : ui::FrameMetricsSourceThread::RendererCompositor;
+ ui::FrameMetricsCompileTarget compile_target =
+ settings.using_synchronous_renderer_compositor
+ ? ui::FrameMetricsCompileTarget::SynchronousCompositor
+ : settings.wait_for_all_pipeline_stages_before_draw
+ ? ui::FrameMetricsCompileTarget::Headless
+ : ui::FrameMetricsCompileTarget::Chromium;
+ return ui::FrameMetricsSettings(source, source_thread, compile_target);
+}
+
} // namespace
DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeDurationHistogramTimer,
@@ -304,7 +323,9 @@
base::BindRepeating(
&LayerTreeHostImpl::RequestInvalidationForAnimatedImages,
base::Unretained(this)),
- settings_.enable_image_animation_resync) {
+ settings_.enable_image_animation_resync),
+ frame_metrics_(LTHI_FrameMetricsSettings(settings_)),
+ skipped_frame_tracker_(&frame_metrics_) {
DCHECK(mutator_host_);
mutator_host_->SetMutatorHostClient(this);
@@ -1236,6 +1257,8 @@
void LayerTreeHostImpl::InvalidateLayerTreeFrameSink() {
DCHECK(layer_tree_frame_sink());
layer_tree_frame_sink()->Invalidate();
+
+ skipped_frame_tracker_.DidProduceFrame();
}
DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
@@ -1714,27 +1737,46 @@
client_->DidReceiveCompositorFrameAckOnImplThread();
}
+LayerTreeHostImpl::FrameTokenInfo::FrameTokenInfo(
+ uint32_t token,
+ base::TimeTicks cc_frame_time,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks)
+ : token(token),
+ cc_frame_time(cc_frame_time),
+ callbacks(std::move(callbacks)) {}
+
+LayerTreeHostImpl::FrameTokenInfo::FrameTokenInfo(FrameTokenInfo&&) = default;
+LayerTreeHostImpl::FrameTokenInfo::~FrameTokenInfo() = default;
+
void LayerTreeHostImpl::DidPresentCompositorFrame(
uint32_t frame_token,
const gfx::PresentationFeedback& feedback) {
TRACE_EVENT_MARK_WITH_TIMESTAMP0("cc,benchmark", "FramePresented",
feedback.timestamp);
std::vector<LayerTreeHost::PresentationTimeCallback> all_callbacks;
- while (!presentation_callbacks_.empty()) {
- auto iter = presentation_callbacks_.begin();
- if (PresentationTokenGT(iter->first, frame_token))
+ while (!frame_token_infos_.empty()) {
+ auto info = frame_token_infos_.begin();
+ if (PresentationTokenGT(info->token, frame_token))
break;
- auto& callbacks = iter->second;
- std::copy(std::make_move_iterator(callbacks.begin()),
- std::make_move_iterator(callbacks.end()),
+
+ // Update compositor frame latency and smoothness stats only for frames
+ // that caused on-screen damage.
+ if (info->token == frame_token)
+ frame_metrics_.AddFrameDisplayed(info->cc_frame_time, feedback.timestamp);
+
+ std::copy(std::make_move_iterator(info->callbacks.begin()),
+ std::make_move_iterator(info->callbacks.end()),
std::back_inserter(all_callbacks));
- presentation_callbacks_.erase(iter);
+ frame_token_infos_.erase(info);
}
client_->DidPresentCompositorFrameOnImplThread(
frame_token, std::move(all_callbacks), feedback);
}
-void LayerTreeHostImpl::DidDiscardCompositorFrame(uint32_t frame_token) {}
+void LayerTreeHostImpl::DidDiscardCompositorFrame(uint32_t frame_token) {
+ TRACE_EVENT_INSTANT0("cc,benchmark", "FrameDiscarded",
+ TRACE_EVENT_SCOPE_THREAD);
+}
void LayerTreeHostImpl::ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) {
@@ -1815,8 +1857,6 @@
metadata.frame_token = next_frame_token_++;
if (!next_frame_token_)
next_frame_token_ = 1u;
- if (active_tree_->has_presentation_callbacks())
- metadata.request_presentation_feedback = true;
metadata.device_scale_factor = active_tree_->painted_device_scale_factor() *
active_tree_->device_scale_factor();
@@ -1838,10 +1878,15 @@
metadata.content_source_id = active_tree_->content_source_id();
active_tree_->GetViewportSelection(&metadata.selection);
- if (active_tree_->has_presentation_callbacks()) {
- presentation_callbacks_.push_back(
- {metadata.frame_token, active_tree_->TakePresentationCallbacks()});
- DCHECK_LE(presentation_callbacks_.size(), 25u);
+
+ if (active_tree_->has_presentation_callbacks() ||
+ settings_.always_request_presentation_time) {
+ metadata.request_presentation_feedback = true;
+ frame_token_infos_.emplace_back(metadata.frame_token,
+ CurrentBeginFrameArgs().frame_time,
+ active_tree_->TakePresentationCallbacks());
+
+ DCHECK_LE(frame_token_infos_.size(), 25u);
}
if (const auto* outer_viewport_scroll_node = OuterViewportScrollNode()) {
@@ -1924,6 +1969,7 @@
TRACE_EVENT0("cc,benchmark", "LayerTreeHostImpl::DrawLayers");
ResetRequiresHighResToDraw();
+ skipped_frame_tracker_.DidProduceFrame();
if (frame->has_no_damage) {
DCHECK(!resourceless_software_draw_);
@@ -2271,6 +2317,7 @@
}
bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
+ impl_thread_phase_ = ImplThreadPhase::INSIDE_IMPL_FRAME;
current_begin_frame_tracker_.Start(args);
if (is_likely_to_require_a_draw_) {
@@ -2288,7 +2335,7 @@
for (auto* it : video_frame_controllers_)
it->OnBeginFrame(args);
- impl_thread_phase_ = ImplThreadPhase::INSIDE_IMPL_FRAME;
+ skipped_frame_tracker_.BeginFrame(args.frame_time, args.interval);
bool recent_frame_had_no_damage =
consecutive_frame_with_damage_count_ < settings_.damaged_frame_limit;
@@ -2313,6 +2360,7 @@
}
void LayerTreeHostImpl::DidFinishImplFrame() {
+ skipped_frame_tracker_.FinishFrame();
impl_thread_phase_ = ImplThreadPhase::IDLE;
current_begin_frame_tracker_.Finish();
tile_manager_.decoded_image_tracker().NotifyFrameFinished();
@@ -2747,6 +2795,7 @@
void LayerTreeHostImpl::SetNeedsRedraw() {
NotifySwapPromiseMonitorsOfSetNeedsRedraw();
client_->SetNeedsRedrawOnImplThread();
+ skipped_frame_tracker_.WillProduceFrame();
}
ManagedMemoryPolicy LayerTreeHostImpl::ActualManagedMemoryPolicy() const {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 20f6818..015bd1d9 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -53,6 +53,7 @@
#include "components/viz/common/surfaces/local_surface_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/latency/frame_metrics.h"
namespace gfx {
class ScrollOffset;
@@ -1076,9 +1077,30 @@
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
- base::circular_deque<
- std::pair<uint32_t, std::vector<LayerTreeHost::PresentationTimeCallback>>>
- presentation_callbacks_;
+ // Stores information needed once we get a response for a particular
+ // presentation token.
+ struct FrameTokenInfo {
+ FrameTokenInfo(
+ uint32_t token,
+ base::TimeTicks cc_frame_time,
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks);
+ FrameTokenInfo(FrameTokenInfo&&);
+ ~FrameTokenInfo();
+
+ uint32_t token;
+
+ // The compositor frame time used to produce the frame.
+ base::TimeTicks cc_frame_time;
+
+ // The callbacks to send back to the main thread.
+ std::vector<LayerTreeHost::PresentationTimeCallback> callbacks;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameTokenInfo);
+ };
+
+ base::circular_deque<FrameTokenInfo> frame_token_infos_;
+ ui::FrameMetrics frame_metrics_;
+ ui::SkippedFrameTracker skipped_frame_tracker_;
DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
};
diff --git a/ui/latency/frame_metrics.cc b/ui/latency/frame_metrics.cc
index 6bf4afa..7a1c5ed 100644
--- a/ui/latency/frame_metrics.cc
+++ b/ui/latency/frame_metrics.cc
@@ -121,8 +121,10 @@
switch (source) {
case FrameMetricsSource::UnitTest:
return "UnitTest";
- case FrameMetricsSource::Thread:
- return "Thread";
+ case FrameMetricsSource::RendererCompositor:
+ return "RendererCompositor";
+ case FrameMetricsSource::UiCompositor:
+ return "UiCompositor";
case FrameMetricsSource::Unknown:
break;
};
diff --git a/ui/latency/frame_metrics.h b/ui/latency/frame_metrics.h
index d9dbaf0..d680541 100644
--- a/ui/latency/frame_metrics.h
+++ b/ui/latency/frame_metrics.h
@@ -39,7 +39,8 @@
enum class FrameMetricsSource {
Unknown = 0,
UnitTest = 1,
- Thread = 2,
+ RendererCompositor = 2,
+ UiCompositor = 3,
};
enum class FrameMetricsSourceThread {