chromium/cc/metrics/compositor_frame_reporter.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "cc/metrics/compositor_frame_reporter.h"

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <deque>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>

#include "base/cpu_reduction_experiment.h"
#include "base/debug/alias.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_id_helper.h"
#include "base/trace_event/typed_macros.h"
#include "base/tracing/protos/chrome_track_event.pbzero.h"
#include "cc/base/rolling_time_delta_history.h"
#include "cc/metrics/dropped_frame_counter.h"
#include "cc/metrics/event_latency_tracing_recorder.h"
#include "cc/metrics/event_latency_tracker.h"
#include "cc/metrics/event_metrics.h"
#include "cc/metrics/frame_sequence_tracker.h"
#include "cc/metrics/latency_ukm_reporter.h"
#include "services/tracing/public/cpp/perfetto/macros.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_frame_reporter.pbzero.h"
#include "ui/events/types/event_type.h"

namespace cc {
namespace {

StageType;
FrameReportType;
BlinkBreakdown;
VizBreakdown;
FrameFinalState;

constexpr int kFrameReportTypeCount =;
constexpr int kStageTypeCount =;
constexpr int kAllBreakdownCount =;

constexpr int kVizBreakdownInitialIndex =;
constexpr int kBlinkBreakdownInitialIndex =;

// For each possible FrameSequenceTrackerType there will be a UMA histogram
// plus one for general case.
constexpr int kFrameSequenceTrackerTypeCount =;

// Maximum number of partial update dependents a reporter can own. When a
// reporter with too many dependents is terminated, it will terminate all its
// dependents which will block the pipeline for a long time. Too many dependents
// also means too much memory usage.
constexpr size_t kMaxOwnedPartialUpdateDependents =;

// Names for CompositorFrameReporter::FrameReportType, which should be
// updated in case of changes to the enum.
constexpr const char* kReportTypeNames[]{};

static_assert;

// This value should be recalculated in case of changes to the number of values
// in CompositorFrameReporter::DroppedFrameReportType or in
// CompositorFrameReporter::StageType
constexpr int kStagesWithBreakdownCount =;
constexpr int kMaxCompositorLatencyHistogramIndex =;

constexpr base::TimeDelta kCompositorLatencyHistogramMin =;
constexpr base::TimeDelta kCompositorLatencyHistogramMax =;
constexpr int kCompositorLatencyHistogramBucketCount =;

constexpr const char kEventLatencyBaseHistogramName[] =;
constexpr int kEventLatencyEventTypeCount =;
constexpr const char kGenerationToBrowserMainName[] =;

// Scroll and pinch events report a separate metrics for each input type. Scroll
// events also report an aggregate metric over all input types. Other event
// types just report one aggregate metric. So, maximum possible metrics for an
// event type is `max(scroll-types-count, pinch-types-count) + 1`.
constexpr int kEventLatencyScrollTypeCount =;
constexpr int kEventLatencyPinchTypeCount =;
constexpr int kEventLatencyGestureTypeCount =;

constexpr int kMaxEventLatencyHistogramIndex =;
constexpr base::TimeDelta kEventLatencyHistogramMin =;
constexpr base::TimeDelta kEventLatencyHistogramMax =;
constexpr int kEventLatencyHistogramBucketCount =;
constexpr base::TimeDelta kHighLatencyMin =;

// Number of breakdown stages of the current PipelineReporter
constexpr int kNumOfCompositorStages =;
// Number of breakdown stages of the blink
constexpr int kNumOfBlinkStages =;
// Number of breakdown stages of the viz
constexpr int kNumOfVizStages =;
// Number of dispatch stages of the current EventLatency
constexpr int kNumDispatchStages =;
// Stores the weight of the most recent data point used in percentage when
// predicting substages' latency. (It is stored and calculated in percentage
// since TimeDelta calculate based on microseconds instead of nanoseconds,
// therefore, decimals of stage durations in microseconds may be lost.)
constexpr double kWeightOfCurStageInPercent =;
// Used for comparing doubles
constexpr double kEpsilon =;

std::string GetCompositorLatencyHistogramName(
    FrameReportType report_type,
    FrameSequenceTrackerType frame_sequence_tracker_type,
    StageType stage_type,
    std::optional<VizBreakdown> viz_breakdown,
    std::optional<BlinkBreakdown> blink_breakdown) {}

// Helper function to record UMA histogram for an EventLatency metric. There
// should be a 1:1 mapping between `name` and `index` to allow the use of
// `STATIC_HISTOGRAM_POINTER_GROUP()` to cache histogram objects.
void ReportEventLatencyMetric(
    const std::string& name,
    int index,
    base::TimeDelta latency,
    const std::optional<EventMetrics::HistogramBucketing>& bucketing,
    bool guiding_metric = false) {}

constexpr char kTraceCategory[] =);

bool IsTracingEnabled() {}

base::TimeTicks ComputeSafeDeadlineForFrame(const viz::BeginFrameArgs& args) {}

// Returns the value of the exponentially weighted average for
// SetEventLatencyPredictions.
base::TimeDelta CalculateWeightedAverage(base::TimeDelta previous_value,
                                         base::TimeDelta current_value) {}

// Calculate new prediction of latency based on old prediction and current
// latency
base::TimeDelta PredictLatency(base::TimeDelta previous_prediction,
                               base::TimeDelta current_latency) {}

double DetermineHighestContribution(
    double contribution_change,
    double highest_contribution_change,
    const std::string& stage_name,
    std::vector<std::string>& high_latency_stages) {}

void TraceScrollJankMetrics(const EventMetrics::List& events_metrics,
                            int32_t fling_input_count,
                            int32_t normal_input_count,
                            perfetto::EventContext& ctx) {}

// For measuring the queuing issues with GenerationToBrowserMain we are only
// looking at scrolling events. So we will not create a histogram that
// encompasses all EventMetrics::EventType options.
constexpr int kMaxGestureScrollHistogramIndex =;
int GetGestureScrollIndex(EventMetrics::EventType type) {}

// For measuring the ratio of scrolling event generation, as well as arrival in
// the Renderer. Compared to the active VSync at the time of their arrival.
constexpr int kMaxVSyncRatioHistogramIndex =;
const char* GetVSyncRatioTypeName(
    CompositorFrameReporter::VSyncRatioType type) {}

void ReportVSyncRatioMetric(const std::string& base_histogram_name,
                            int gesture_scroll_index,
                            CompositorFrameReporter::VSyncRatioType type,
                            int percentage) {}

#if BUILDFLAG(IS_ANDROID)
constexpr const char kTopControlsMovedName[] = ".TopControlsMoved";
constexpr const char kTopControlsDidNotMoveName[] = ".TopControlsDidNotMove";
void ReportTopControlsMetric(
    const std::string& name,
    bool top_controls_moved,
    base::TimeDelta latency,
    EventMetrics::EventType type,
    const std::optional<EventMetrics::HistogramBucketing>& bucketing) {
  if (!bucketing) {
    return;
  }
  if (top_controls_moved) {
    std::string versioned_name = name + kTopControlsMovedName;
    STATIC_HISTOGRAM_POINTER_GROUP(
        versioned_name, GetGestureScrollIndex(type),
        kMaxGestureScrollHistogramIndex,
        AddTimeMicrosecondsGranularity(latency),
        base::Histogram::FactoryMicrosecondsTimeGet(
            versioned_name, bucketing->min, bucketing->max, bucketing->count,
            base::HistogramBase::kUmaTargetedHistogramFlag));
  } else if (base::ShouldLogHistogramForCpuReductionExperiment()) {
    // We want to sub-sample the reports with top controls not moving. As they
    // dominate in volume.
    std::string versioned_name = name + kTopControlsDidNotMoveName;
    STATIC_HISTOGRAM_POINTER_GROUP(
        versioned_name, GetGestureScrollIndex(type),
        kMaxGestureScrollHistogramIndex,
        AddTimeMicrosecondsGranularity(latency),
        base::Histogram::FactoryMicrosecondsTimeGet(
            versioned_name, bucketing->min, bucketing->max, bucketing->count,
            base::HistogramBase::kUmaTargetedHistogramFlag));
  }
}
#endif  // BUILDFLAG(IS_ANDROID)

}  // namespace

// CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator ==================

CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::Iterator(
    const ProcessedBlinkBreakdown* owner)
    :{}

CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::~Iterator() =
    default;

bool CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::IsValid()
    const {}

void CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::Advance() {}

BlinkBreakdown
CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::GetBreakdown()
    const {}

base::TimeDelta
CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::GetLatency() const {}

// CompositorFrameReporter::ProcessedBlinkBreakdown ============================

CompositorFrameReporter::ProcessedBlinkBreakdown::ProcessedBlinkBreakdown(
    base::TimeTicks blink_start_time,
    base::TimeTicks begin_main_frame_start,
    const BeginMainFrameMetrics& blink_breakdown) {}

CompositorFrameReporter::ProcessedBlinkBreakdown::~ProcessedBlinkBreakdown() =
    default;

CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator
CompositorFrameReporter::ProcessedBlinkBreakdown::CreateIterator() const {}

// CompositorFrameReporter::ProcessedVizBreakdown::Iterator ====================

CompositorFrameReporter::ProcessedVizBreakdown::Iterator::Iterator(
    const ProcessedVizBreakdown* owner,
    bool skip_swap_start_to_swap_end)
    :{}

CompositorFrameReporter::ProcessedVizBreakdown::Iterator::~Iterator() = default;

bool CompositorFrameReporter::ProcessedVizBreakdown::Iterator::IsValid() const {}

void CompositorFrameReporter::ProcessedVizBreakdown::Iterator::Advance() {}

VizBreakdown
CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetBreakdown() const {}

base::TimeTicks
CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetStartTime() const {}

base::TimeTicks
CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetEndTime() const {}

base::TimeDelta
CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetDuration() const {}

bool CompositorFrameReporter::ProcessedVizBreakdown::Iterator::HasValue()
    const {}

void CompositorFrameReporter::ProcessedVizBreakdown::Iterator::
    SkipBreakdownsIfNecessary() {}

// CompositorFrameReporter::ProcessedVizBreakdown ==============================

CompositorFrameReporter::ProcessedVizBreakdown::ProcessedVizBreakdown(
    base::TimeTicks viz_start_time,
    const viz::FrameTimingDetails& viz_breakdown) {}

CompositorFrameReporter::ProcessedVizBreakdown::~ProcessedVizBreakdown() =
    default;

CompositorFrameReporter::ProcessedVizBreakdown::Iterator
CompositorFrameReporter::ProcessedVizBreakdown::CreateIterator(
    bool skip_swap_start_to_swap_end_if_breakdown_available) const {}

// CompositorFrameReporter::CompositorLatencyInfo ==============================

CompositorFrameReporter::CompositorLatencyInfo::CompositorLatencyInfo() =
    default;
CompositorFrameReporter::CompositorLatencyInfo::CompositorLatencyInfo(
    base::TimeDelta init_value)
    :{}
CompositorFrameReporter::CompositorLatencyInfo::~CompositorLatencyInfo() =
    default;

// CompositorFrameReporter =====================================================

CompositorFrameReporter::CompositorFrameReporter(
    const ActiveTrackers& active_trackers,
    const viz::BeginFrameArgs& args,
    bool should_report_histograms,
    SmoothThread smooth_thread,
    FrameInfo::SmoothEffectDrivingThread scrolling_thread,
    int layer_tree_host_id,
    const GlobalMetricsTrackers& trackers)
    :{}

// static
const char* CompositorFrameReporter::GetStageName(
    StageType stage_type,
    std::optional<VizBreakdown> viz_breakdown,
    std::optional<BlinkBreakdown> blink_breakdown,
    bool impl_only) {}

// static
const char* CompositorFrameReporter::GetVizBreakdownName(
    VizBreakdown breakdown) {}

std::unique_ptr<CompositorFrameReporter>
CompositorFrameReporter::CopyReporterAtBeginImplStage() {}

CompositorFrameReporter::~CompositorFrameReporter() {}

CompositorFrameReporter::StageData::StageData() = default;
CompositorFrameReporter::StageData::StageData(StageType stage_type,
                                              base::TimeTicks start_time,
                                              base::TimeTicks end_time)
    :{}
CompositorFrameReporter::StageData::StageData(const StageData&) = default;
CompositorFrameReporter::StageData::~StageData() = default;

CompositorFrameReporter::EventLatencyInfo::EventLatencyInfo(
    const int num_dispatch_stages,
    const int num_compositor_stages)
    :{}
CompositorFrameReporter::EventLatencyInfo::~EventLatencyInfo() = default;

void CompositorFrameReporter::StartStage(
    CompositorFrameReporter::StageType stage_type,
    base::TimeTicks start_time) {}

void CompositorFrameReporter::TerminateFrame(
    FrameTerminationStatus termination_status,
    base::TimeTicks termination_time) {}

void CompositorFrameReporter::OnFinishImplFrame(base::TimeTicks timestamp) {}

void CompositorFrameReporter::OnAbortBeginMainFrame(base::TimeTicks timestamp) {}

void CompositorFrameReporter::OnDidNotProduceFrame(
    FrameSkippedReason skip_reason) {}

void CompositorFrameReporter::EnableCompositorOnlyReporting() {}

void CompositorFrameReporter::SetBlinkBreakdown(
    std::unique_ptr<BeginMainFrameMetrics> blink_breakdown,
    base::TimeTicks begin_main_start) {}

void CompositorFrameReporter::SetVizBreakdown(
    const viz::FrameTimingDetails& viz_breakdown) {}

void CompositorFrameReporter::AddEventsMetrics(
    EventMetrics::List events_metrics) {}

EventMetrics::List CompositorFrameReporter::TakeEventsMetrics() {}

EventMetrics::List CompositorFrameReporter::TakeMainBlockedEventsMetrics() {}

void CompositorFrameReporter::DidSuccessfullyPresentFrame() {}

void CompositorFrameReporter::TerminateReporter() {}

void CompositorFrameReporter::EndCurrentStage(base::TimeTicks end_time) {}

void CompositorFrameReporter::ReportCompositorLatencyMetrics() const {}

void CompositorFrameReporter::ReportStageHistogramWithBreakdown(
    const CompositorFrameReporter::StageData& stage,
    FrameSequenceTrackerType frame_sequence_tracker_type) const {}

void CompositorFrameReporter::ReportCompositorLatencyBlinkBreakdowns(
    FrameSequenceTrackerType frame_sequence_tracker_type) const {}

void CompositorFrameReporter::ReportCompositorLatencyVizBreakdowns(
    FrameSequenceTrackerType frame_sequence_tracker_type) const {}

void CompositorFrameReporter::ReportCompositorLatencyHistogram(
    FrameSequenceTrackerType frame_sequence_tracker_type,
    StageType stage_type,
    std::optional<VizBreakdown> viz_breakdown,
    std::optional<BlinkBreakdown> blink_breakdown,
    base::TimeDelta time_delta) const {}

void CompositorFrameReporter::ReportEventLatencyMetrics() const {}

void CompositorFrameReporter::ReportCompositorLatencyTraceEvents(
    const FrameInfo& info) const {}

void CompositorFrameReporter::ReportScrollJankMetrics() const {}

void CompositorFrameReporter::ReportEventLatencyTraceEvents() const {}

base::TimeDelta CompositorFrameReporter::SumOfStageHistory() const {}

base::TimeTicks CompositorFrameReporter::Now() const {}

void CompositorFrameReporter::AdoptReporter(
    std::unique_ptr<CompositorFrameReporter> reporter) {}

void CompositorFrameReporter::CalculateCompositorLatencyPrediction(
    CompositorLatencyInfo& previous_predictions,
    base::TimeDelta prediction_deviation_threshold) {}

void CompositorFrameReporter::CalculateEventLatencyPrediction(
    CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
    base::TimeDelta prediction_deviation_threshold) {}

void CompositorFrameReporter::SetPartialUpdateDecider(
    CompositorFrameReporter* decider) {}

void CompositorFrameReporter::DiscardOldPartialUpdateReporters() {}

base::WeakPtr<CompositorFrameReporter> CompositorFrameReporter::GetWeakPtr() {}

FrameInfo CompositorFrameReporter::GenerateFrameInfo() const {}

void CompositorFrameReporter::FindHighLatencyAttribution(
    CompositorLatencyInfo& previous_predictions,
    CompositorLatencyInfo& current_stage_durations) {}

void CompositorFrameReporter::FindEventLatencyAttribution(
    EventMetrics* event_metrics,
    CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
    CompositorFrameReporter::EventLatencyInfo& actual_event_latency) {}

}  // namespace cc