0

Add UMA for PresentationDelayForInteractiveFrames feature

This CL adds two histograms to help understand the percentage of
frames that can be swapped immediately and frames that need to
wait.

GPU.Presentation.FrameHandlesAnimationOrInteraction
GPU.Presentation.NonAnimatdOrInteractiveFrameWithPendingFrame

When VSyncAlignedPresent and kPresentationDelayForInteractiveFrames
are enabled, frames not handling interaction and animation can be
swapped immediately. However, they must wait in the queue for VSync
when there is a pending frame(s).

Bug: 330771325
Change-Id: I9a85b2c398c37c5e428dd8327f5e0a332f335b00
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6334447
Commit-Queue: Maggie Chen <magchen@chromium.org>
Reviewed-by: Colin Blundell <blundell@chromium.org>
Reviewed-by: Jonathan Ross <jonross@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1430521}
This commit is contained in:
Maggie Chen
2025-03-10 15:15:42 -07:00
committed by Chromium LUCI CQ
parent 6ab89ac2b4
commit 3bdab00d57
7 changed files with 105 additions and 12 deletions
components/viz/service/display
gpu/ipc/service
tools/metrics/histograms
ui/gfx

@ -121,7 +121,8 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
gfx::CALayerResult ca_layer_error_code = gfx::kCALayerSuccess;
#endif
bool is_handling_interaction_or_animation = false;
bool is_handling_interaction = false;
bool is_handling_animation = false;
std::optional<int64_t> choreographer_vsync_id;
int64_t swap_trace_id = -1;

@ -1115,7 +1115,8 @@ bool Display::DrawAndSwap(const DrawAndSwapParams& params) {
std::move(animation_thread_ids), std::move(renderer_main_thread_ids),
boost_type);
bool has_interactive_or_animated_frame = false;
bool has_interactive_frame = false;
bool has_animated_frame = false;
for (const auto& surface_id : aggregator_->previous_contained_surfaces()) {
surface = surface_manager_->GetSurfaceForId(surface_id);
if (surface) {
@ -1125,10 +1126,12 @@ bool Display::DrawAndSwap(const DrawAndSwapParams& params) {
presentation_group_timing.AddPresentationHelper(std::move(helper));
}
has_interactive_or_animated_frame |=
has_interactive_frame |=
surface->HasActiveFrame() &&
(surface->GetActiveFrameMetadata().is_handling_interaction ||
surface->GetActiveFrameMetadata().is_handling_animation);
surface->GetActiveFrameMetadata().is_handling_interaction;
has_animated_frame |=
surface->HasActiveFrame() &&
surface->GetActiveFrameMetadata().is_handling_animation;
}
}
@ -1164,8 +1167,8 @@ bool Display::DrawAndSwap(const DrawAndSwapParams& params) {
swap_frame_data.ca_layer_error_code =
overlay_processor_->GetCALayerErrorCode();
#endif
swap_frame_data.is_handling_interaction_or_animation =
has_interactive_or_animated_frame;
swap_frame_data.is_handling_interaction = has_interactive_frame;
swap_frame_data.is_handling_animation = has_animated_frame;
// We must notify scheduler and increase |pending_swaps_| before calling
// SwapBuffers() as it can call DidReceiveSwapBuffersAck synchronously.

@ -1197,8 +1197,10 @@ void SkiaRenderer::SwapBuffers(SwapFrameData swap_frame_data) {
#endif
#if BUILDFLAG(IS_MAC)
output_frame.data.is_handling_interaction_or_animation =
swap_frame_data.is_handling_interaction_or_animation;
output_frame.data.is_handling_interaction =
swap_frame_data.is_handling_interaction;
output_frame.data.is_handling_animation =
swap_frame_data.is_handling_animation;
#endif
if (buffer_queue_) {

@ -63,6 +63,48 @@ void RecordVSyncCallbackDelay(base::TimeDelta delay) {
/*min=*/base::Microseconds(10),
/*max=*/base::Milliseconds(33), /*bucket_count=*/50);
}
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
//
// LINT.IfChange(AnimationOrInteractionType)
enum class AnimationOrInteractionType {
kNone = 0,
kInteractionOnly = 1,
kAnimationOnly = 2,
kAnimationAndInteraction = 3,
kMaxValue = kAnimationAndInteraction,
};
// LINT.ThenChange(//tools/metrics/histograms/enums.xml:FrameHandlingType)
void RecordFrameTypes(bool is_handling_interaction,
bool is_handling_animation,
int num_pending_frames) {
AnimationOrInteractionType type;
if (is_handling_interaction && is_handling_animation) {
type = AnimationOrInteractionType::kAnimationAndInteraction;
} else if (is_handling_interaction) {
type = AnimationOrInteractionType::kInteractionOnly;
} else if (is_handling_animation) {
type = AnimationOrInteractionType::kAnimationOnly;
} else {
type = AnimationOrInteractionType::kNone;
}
UMA_HISTOGRAM_ENUMERATION(
"GPU.Presentation.FrameHandlesAnimationOrInteraction", type);
// Although the current frame is free of interation and animation, the pending
// frame blocks the current frame from being swapped immediately when
// VSyncAlignedPresent and kPresentationDelayForInteractiveFrames are enabled.
// Note: |num_pending_frames| is always 0 when VSyncAlignedPresent is
// disabled.
if (type == AnimationOrInteractionType::kNone) {
UMA_HISTOGRAM_BOOLEAN(
"GPU.Presentation.NonAnimatedOrInteractiveFrameWithPendingFrame",
!!num_pending_frames);
}
}
#endif // BUILDFLAG(IS_MAC)
} // namespace
@ -129,7 +171,7 @@ void ImageTransportSurfaceOverlayMacEGL::Present(
// Commit the first pending frame before adding one more in Present() if there
// are more than supported .
if (ca_layer_tree_coordinator_->NumPendingSwaps() >= cap_max_pending_swaps_) {
TRACE_EVENT0("gpu", "Commit now. Exceeds the max pending swaps.");
TRACE_EVENT0("gpu", "Exceeds the max pending swaps. Commit now.");
CommitPresentedFrameToCA();
}
@ -185,10 +227,16 @@ void ImageTransportSurfaceOverlayMacEGL::Present(
if (base::FeatureList::IsEnabled(kPresentationDelayForInteractiveFrames) &&
!ca_layer_tree_coordinator_->NumPendingSwaps() &&
!data.is_handling_interaction_or_animation) {
!data.is_handling_interaction && !data.is_handling_animation) {
delay_presenetation_until_next_vsync = false;
}
if (features::IsVSyncAlignedPresentEnabled() &&
base::FeatureList::IsEnabled(kPresentationDelayForInteractiveFrames)) {
RecordFrameTypes(data.is_handling_interaction, data.is_handling_animation,
ca_layer_tree_coordinator_->NumPendingSwaps());
}
if (vsync_callback_mac_) {
vsync_callback_mac_keep_alive_counter_ = kMaxKeepAliveCounter;
if (delay_presenetation_until_next_vsync) {

@ -5388,6 +5388,17 @@ to ensure that the crash string is shown properly on the user-facing crash UI.
<int value="3" label="Start on NTP"/>
</enum>
<!-- LINT.IfChange(FrameHandlingType) -->
<enum name="FrameHandlingType">
<int value="0" label="None"/>
<int value="1" label="InteractionOnly"/>
<int value="2" label="AnimationOnly"/>
<int value="3" label="InteractionAndAnimation"/>
</enum>
<!-- LINT.ThenChange(//gpu/ipc/service/image_transport_surface_overlay_mac.mm:AnimationOrInteractionType) -->
<enum name="FsckResult">
<summary>
These correspond to e2fsck exit codes. Note that 0 differs from e2fsck's man

@ -1199,6 +1199,33 @@ chromium-metrics-reviews@google.com.
</summary>
</histogram>
<histogram name="GPU.Presentation.FrameHandlesAnimationOrInteraction"
enum="FrameHandlingType" expires_after="2025-09-07">
<owner>magchen@chromium.org</owner>
<owner>vmiura@chromium.org</owner>
<owner>chrome-gpu-metric-alerts@chromium.org</owner>
<summary>
Recorded on Mac when a frame is ready to present and GPU Present() is
called. It records whether the current frame is handling interaction,
animation, both, or none.
</summary>
</histogram>
<histogram
name="GPU.Presentation.NonAnimatedOrInteractiveFrameWithPendingFrame"
enum="Boolean" expires_after="2025-09-07">
<owner>magchen@chromium.org</owner>
<owner>vmiura@chromium.org</owner>
<owner>chrome-gpu-metric-alerts@chromium.org</owner>
<summary>
Recorded on Mac for frames that are not handling interaction and animation
at the time when they are ready to present and GPU Present() is called . If
VSyncAlignedPresent and kPresentationDelayForInteractiveFrames are enabled,
this type of frames can be swapped immediately. However, they must wait in
the queue for VSync when there is a pending frame(s).
</summary>
</histogram>
<histogram name="GPU.Presentation.VSyncCallbackDelay" units="microseconds"
expires_after="2025-08-10">
<owner>magchen@chromium.org</owner>

@ -40,7 +40,8 @@ struct FrameData {
#endif
#if BUILDFLAG(IS_MAC)
bool is_handling_interaction_or_animation = false;
bool is_handling_interaction = false;
bool is_handling_animation = false;
#endif
};