#ifndef CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
#define CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
#include <array>
#include <bitset>
#include <deque>
#include <memory>
#include <optional>
#include <queue>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/cc_export.h"
#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/metrics/event_metrics.h"
#include "cc/metrics/frame_info.h"
#include "cc/metrics/frame_sequence_metrics.h"
#include "cc/metrics/frame_sequence_tracker_collection.h"
#include "cc/metrics/predictor_jank_tracker.h"
#include "cc/metrics/scroll_jank_dropped_frame_tracker.h"
#include "cc/metrics/scroll_jank_v4_processor.h"
#include "cc/scheduler/scheduler.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_timing_details.h"
namespace viz {
class FrameTimingDetails;
}
namespace cc {
class EventLatencyTracker;
class FrameSorter;
class LatencyUkmReporter;
struct GlobalMetricsTrackers {
RAW_PTR_EXCLUSION LatencyUkmReporter* latency_ukm_reporter = nullptr;
RAW_PTR_EXCLUSION FrameSequenceTrackerCollection* frame_sequence_trackers =
nullptr;
RAW_PTR_EXCLUSION EventLatencyTracker* event_latency_tracker = nullptr;
RAW_PTR_EXCLUSION PredictorJankTracker* predictor_jank_tracker = nullptr;
RAW_PTR_EXCLUSION ScrollJankDroppedFrameTracker*
scroll_jank_dropped_frame_tracker = nullptr;
RAW_PTR_EXCLUSION ScrollJankUkmReporter* scroll_jank_ukm_reporter = nullptr;
RAW_PTR_EXCLUSION ScrollJankV4Processor* scroll_jank_v4_processor = nullptr;
RAW_PTR_EXCLUSION FrameSorter* frame_sorter = nullptr;
};
class CC_EXPORT CompositorFrameReporter {
public:
enum class FrameTerminationStatus {
kPresentedFrame,
kDidNotPresentFrame,
kReplacedByNewReporter,
kDidNotProduceFrame,
kUnknown
};
enum class FrameReportType {
kNonDroppedFrame = 0,
kMissedDeadlineFrame = 1,
kDroppedFrame = 2,
kCompositorOnlyFrame = 3,
kMaxValue = kCompositorOnlyFrame
};
enum class StageType {
kBeginImplFrameToSendBeginMainFrame = 0,
kSendBeginMainFrameToCommit = 1,
kCommit = 2,
kEndCommitToActivation = 3,
kActivation = 4,
kEndActivateToSubmitCompositorFrame = 5,
kSubmitCompositorFrameToPresentationCompositorFrame = 6,
kEndActivateToSubmitUpdateDisplayTree = 7,
kSubmitUpdateDisplayTreeToPresentationCompositorFrame = 8,
kTotalLatency = 9,
kStageTypeCount
};
enum class TreesInVizBreakdown {
kEndActivateToDrawLayers = 0,
kDrawLayersToSubmitUpdateDisplayTree = 1,
kSendUpdateDisplayTreeToReceiveUpdateDisplayTree = 2,
kReceiveUpdateDisplayTreeToStartPrepareToDraw = 3,
kStartPrepareToDrawToStartDrawLayers = 4,
kStartDrawLayersToSubmitCompositorFrame = 5,
kTreesInVizBreakdownCount
};
enum class VizBreakdown {
kSubmitToReceiveCompositorFrame = 0,
kReceivedCompositorFrameToStartDraw = 1,
kStartDrawToSwapStart = 2,
kSwapStartToSwapEnd = 3,
kSwapStartToBufferAvailable = 4,
kBufferAvailableToBufferReady = 5,
kBufferReadyToLatch = 6,
kLatchToSwapEnd = 7,
kSwapEndToPresentationCompositorFrame = 8,
kBreakdownCount,
kMaxValue = kBreakdownCount
};
enum class BlinkBreakdown {
kHandleInputEvents = 0,
kAnimate = 1,
kStyleUpdate = 2,
kLayoutUpdate = 3,
kAccessibility = 4,
kPrepaint = 5,
kCompositingInputs = 6,
kPaint = 7,
kCompositeCommit = 8,
kUpdateLayers = 9,
kBeginMainSentToStarted = 10,
kBreakdownCount
};
enum class ReporterType { kImpl = 0, kMain = 1 };
struct CC_EXPORT StageData {
StageType stage_type;
base::TimeTicks start_time;
base::TimeTicks end_time;
StageData();
StageData(StageType stage_type,
base::TimeTicks start_time,
base::TimeTicks end_time);
StageData(const StageData&);
~StageData();
};
using SmoothThread = FrameInfo::SmoothThread;
using SmoothEffectDrivingThread = FrameInfo::SmoothEffectDrivingThread;
class CC_EXPORT ProcessedBlinkBreakdown {
public:
class Iterator {
public:
explicit Iterator(const ProcessedBlinkBreakdown* owner);
~Iterator();
bool IsValid() const;
void Advance();
BlinkBreakdown GetBreakdown() const;
base::TimeDelta GetLatency() const;
private:
RAW_PTR_EXCLUSION const ProcessedBlinkBreakdown* owner_;
size_t index_ = 0;
};
ProcessedBlinkBreakdown(base::TimeTicks blink_start_time,
base::TimeTicks begin_main_frame_start,
const BeginMainFrameMetrics& blink_breakdown);
~ProcessedBlinkBreakdown();
ProcessedBlinkBreakdown(const ProcessedBlinkBreakdown&) = delete;
ProcessedBlinkBreakdown& operator=(const ProcessedBlinkBreakdown&) = delete;
Iterator CreateIterator() const;
private:
std::array<base::TimeDelta,
static_cast<size_t>(BlinkBreakdown::kBreakdownCount)>
list_;
};
class CC_EXPORT ProcessedVizBreakdown {
public:
class Iterator {
public:
Iterator(const ProcessedVizBreakdown* owner,
bool skip_swap_start_to_swap_end);
~Iterator();
bool IsValid() const;
void Advance();
VizBreakdown GetBreakdown() const;
base::TimeTicks GetStartTime() const;
base::TimeTicks GetEndTime() const;
base::TimeDelta GetDuration() const;
private:
bool HasValue() const;
void SkipBreakdownsIfNecessary();
RAW_PTR_EXCLUSION const ProcessedVizBreakdown* owner_;
const bool skip_swap_start_to_swap_end_;
size_t index_ = 0;
};
ProcessedVizBreakdown(base::TimeTicks viz_start_time,
const viz::FrameTimingDetails& viz_breakdown);
~ProcessedVizBreakdown();
ProcessedVizBreakdown(const ProcessedVizBreakdown&) = delete;
ProcessedVizBreakdown& operator=(const ProcessedVizBreakdown&) = delete;
Iterator CreateIterator(
bool skip_swap_start_to_swap_end_if_breakdown_available) const;
base::TimeTicks swap_start() const { return swap_start_; }
private:
std::array<std::optional<std::pair<base::TimeTicks, base::TimeTicks>>,
static_cast<size_t>(VizBreakdown::kBreakdownCount)>
list_;
bool buffer_ready_available_ = false;
base::TimeTicks swap_start_;
};
class CC_EXPORT ProcessedTreesInVizBreakdown {
public:
class Iterator {
public:
explicit Iterator(const ProcessedTreesInVizBreakdown* owner);
~Iterator();
bool IsValid() const;
void Advance();
TreesInVizBreakdown GetBreakdown() const;
base::TimeTicks GetStartTime() const;
base::TimeTicks GetEndTime() const;
base::TimeDelta GetDuration() const;
private:
bool HasValue() const;
void SkipBreakdownsIfNecessary();
RAW_PTR_EXCLUSION const ProcessedTreesInVizBreakdown* owner_;
size_t index_ = 0;
};
explicit ProcessedTreesInVizBreakdown(
base::TimeTicks trees_in_viz_branch_time,
base::TimeTicks start_draw_layers,
base::TimeTicks viz_start_time,
const viz::FrameTimingDetails& viz_breakdown);
~ProcessedTreesInVizBreakdown();
ProcessedTreesInVizBreakdown(const ProcessedTreesInVizBreakdown&) = delete;
ProcessedTreesInVizBreakdown& operator=(
const ProcessedTreesInVizBreakdown&) = delete;
Iterator CreateIterator() const;
private:
std::array<std::optional<std::pair<base::TimeTicks, base::TimeTicks>>,
static_cast<size_t>(
TreesInVizBreakdown::kTreesInVizBreakdownCount)>
list_;
};
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);
~CompositorFrameReporter();
CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
delete;
static const char* GetStageName(
StageType stage_type,
std::optional<VizBreakdown> viz_breakdown = std::nullopt,
std::optional<BlinkBreakdown> blink_breakdown = std::nullopt,
std::optional<TreesInVizBreakdown> trees_in_viz_breakdown = std::nullopt);
static const char* GetVizBreakdownName(VizBreakdown breakdown);
static const char* GetTreesInVizBreakdownName(TreesInVizBreakdown breakdown);
std::unique_ptr<CompositorFrameReporter> CopyReporterAtBeginImplStage();
void StartStage(StageType stage_type, base::TimeTicks start_time);
void StartStageUpdateDisplayTree(SubmitInfo& submit_info);
void StartStagePresentationCompositorFrame(SubmitInfo& submit_info);
void TerminateFrame(FrameTerminationStatus termination_status,
base::TimeTicks termination_time);
void SetBlinkBreakdown(std::unique_ptr<BeginMainFrameMetrics> blink_breakdown,
base::TimeTicks begin_main_start);
void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown);
void AddEventsMetrics(EventMetrics::List events_metrics);
void SetTreesInVizBranchTime(base::TimeTicks timestamp);
EventMetrics::List TakeEventsMetrics();
void set_normalized_invalidated_area(
std::optional<float> normalized_invalidated_area);
size_t stage_history_size_for_testing() const {
return stage_history_.size();
}
void OnFinishImplFrame(base::TimeTicks timestamp, bool waiting_for_main);
void OnAbortBeginMainFrame(base::TimeTicks timestamp);
void OnDidNotProduceFrame(FrameSkippedReason skip_reason);
void EnableCompositorOnlyReporting();
bool did_finish_impl_frame() const { return did_finish_impl_frame_; }
base::TimeTicks impl_frame_finish_time() const {
return impl_frame_finish_time_;
}
bool did_not_produce_frame() const {
return did_not_produce_frame_time_.has_value();
}
base::TimeTicks did_not_produce_frame_time() const {
return *did_not_produce_frame_time_;
}
bool did_abort_main_frame() const {
return main_frame_abort_time_.has_value();
}
base::TimeTicks main_frame_abort_time() const {
return *main_frame_abort_time_;
}
bool has_frame_skip_reason() const { return frame_skip_reason_.has_value(); }
FrameSkippedReason frame_skip_reason() const { return *frame_skip_reason_; }
void set_tick_clock(const base::TickClock* tick_clock) {
DCHECK(tick_clock);
tick_clock_ = tick_clock;
}
void set_checkerboarded_needs_raster(bool checkerboarded_needs_raster) {
checkerboarded_needs_raster_ = checkerboarded_needs_raster;
}
void set_checkerboarded_needs_record(bool checkerboarded_needs_record) {
checkerboarded_needs_record_ = checkerboarded_needs_record;
}
void set_top_controls_moved(bool top_controls_moved) {
top_controls_moved_ = top_controls_moved;
}
void SetPartialUpdateDecider(CompositorFrameReporter* decider);
size_t partial_update_dependents_size_for_testing() const {
return partial_update_dependents_.size();
}
size_t owned_partial_update_dependents_size_for_testing() const {
return owned_partial_update_dependents_.size();
}
void set_is_accompanied_by_main_thread_update(
bool is_accompanied_by_main_thread_update) {
is_accompanied_by_main_thread_update_ =
is_accompanied_by_main_thread_update;
}
void set_is_forked(bool is_forked) { is_forked_ = is_forked; }
void set_is_backfill(bool is_backfill) { is_backfill_ = is_backfill; }
void set_created_new_tree(bool new_tree) { created_new_tree_ = new_tree; }
void set_want_new_tree(bool want_new_tree) { want_new_tree_ = want_new_tree; }
void set_invalidate_raster_scroll(bool invalidate_raster_scroll) {
invalidate_raster_scroll_ = invalidate_raster_scroll;
}
const viz::BeginFrameId& frame_id() const { return args_.frame_id; }
void AdoptReporter(std::unique_ptr<CompositorFrameReporter> cloned_reporter);
void DidSuccessfullyPresentFrame();
CompositorFrameReporter* partial_update_decider() const {
return partial_update_decider_.get();
}
using FrameReportTypes =
std::bitset<static_cast<size_t>(FrameReportType::kMaxValue) + 1>;
ReporterType get_reporter_type() { return reporter_type_; }
void set_reporter_type_to_impl() { reporter_type_ = ReporterType::kImpl; }
void set_reporter_type_to_main() { reporter_type_ = ReporterType::kMain; }
std::vector<std::unique_ptr<EventMetrics>>& events_metrics_for_testing() {
return events_metrics_;
}
EventMetrics::List TakeMainBlockedEventsMetrics();
bool will_throttle_main() const { return will_throttle_main_; }
void set_will_throttle_main(bool will_throttle_main) {
will_throttle_main_ = will_throttle_main;
}
bool waiting_for_main() const { return waiting_for_main_; }
void waiting_for_main(bool waiting_for_main) {
waiting_for_main_ = waiting_for_main;
}
void set_active_tree_staleness(bool active_tree_staleness) {
active_tree_staleness_ = active_tree_staleness;
}
void set_frame_skipped_reason_v4(std::optional<FrameSkippedReason> reason) {
frame_skipped_reason_v4_ = reason;
}
protected:
void set_has_partial_update(bool has_partial_update) {
has_partial_update_ = has_partial_update;
}
private:
void TerminateReporter();
void EndCurrentStage(base::TimeTicks end_time);
void ReportCompositorLatencyMetrics() const;
void ReportStageHistogramWithBreakdown(
const StageData& stage,
FrameSequenceTrackerType frame_sequence_tracker_type =
FrameSequenceTrackerType::kMaxType) const;
void ReportCompositorLatencyBlinkBreakdowns(
FrameSequenceTrackerType frame_sequence_tracker_type) const;
void ReportCompositorLatencyVizBreakdowns(
FrameSequenceTrackerType frame_sequence_tracker_type,
StageType stage_type) const;
void ReportCompositorLatencyTreesInVizBreakdowns(
FrameSequenceTrackerType frame_sequence_tracker_type) const;
void ReportCompositorLatencyHistogram(
FrameSequenceTrackerType intraction_type,
StageType stage_type,
std::optional<VizBreakdown> viz_breakdown,
std::optional<BlinkBreakdown> blink_breakdown,
std::optional<TreesInVizBreakdown> trees_in_viz_breakdown,
base::TimeDelta time_delta) const;
void DropEventMetricsWhichDidNotCauseFrameUpdate();
void ReportEventLatencyMetrics() const;
void ReportCompositorLatencyTraceEvents(const FrameInfo& info) const;
void ReportEventLatencyTraceEvents() const;
void ReportScrollJankMetrics();
void ReportScrollJankV1Metrics();
void ReportScrollJankV4Metrics();
void ReportPaintMetric() const;
void EnableReportType(FrameReportType report_type) {
report_types_.set(static_cast<size_t>(report_type));
}
bool TestReportType(FrameReportType report_type) const {
return report_types_.test(static_cast<size_t>(report_type));
}
base::TimeDelta SumOfStageHistory() const;
void DiscardOldPartialUpdateReporters();
base::TimeTicks Now() const;
FrameInfo GenerateFrameInfo() const;
base::WeakPtr<CompositorFrameReporter> GetWeakPtr();
const bool should_report_histograms_;
const viz::BeginFrameArgs args_;
StageData current_stage_;
BeginMainFrameMetrics blink_breakdown_;
base::TimeTicks blink_start_time_;
std::unique_ptr<ProcessedBlinkBreakdown> processed_blink_breakdown_;
viz::FrameTimingDetails viz_breakdown_;
base::TimeTicks viz_start_time_;
std::unique_ptr<ProcessedVizBreakdown> processed_viz_breakdown_;
struct TreesInVizTimestamps {
base::TimeTicks trees_in_viz_activate_time_;
base::TimeTicks trees_in_viz_branch_time_;
base::TimeTicks trees_in_viz_viz_start_time_;
};
std::optional<TreesInVizTimestamps> trees_in_viz_timestamps_;
std::unique_ptr<ProcessedTreesInVizBreakdown>
processed_trees_in_viz_breakdown_;
std::vector<StageData> stage_history_;
EventMetrics::List events_metrics_;
bool dropped_non_damaging_events_metrics_ = false;
std::optional<float> paint_metric_;
FrameReportTypes report_types_;
base::TimeTicks frame_termination_time_;
base::TimeTicks begin_main_frame_start_;
FrameTerminationStatus frame_termination_status_ =
FrameTerminationStatus::kUnknown;
const ActiveTrackers active_trackers_;
const FrameInfo::SmoothEffectDrivingThread scrolling_thread_;
bool did_finish_impl_frame_ = false;
base::TimeTicks impl_frame_finish_time_;
std::optional<base::TimeTicks> did_not_produce_frame_time_;
std::optional<FrameSkippedReason> frame_skip_reason_;
std::optional<base::TimeTicks> main_frame_abort_time_;
raw_ptr<const base::TickClock> tick_clock_ =
base::DefaultTickClock::GetInstance();
bool has_partial_update_ = false;
bool is_accompanied_by_main_thread_update_ = false;
const SmoothThread smooth_thread_;
const int layer_tree_host_id_;
bool checkerboarded_needs_raster_ = false;
bool checkerboarded_needs_record_ = false;
bool top_controls_moved_ = false;
bool is_forked_ = false;
bool is_backfill_ = false;
std::deque<base::WeakPtr<CompositorFrameReporter>> partial_update_dependents_;
base::WeakPtr<CompositorFrameReporter> partial_update_decider_;
std::queue<std::unique_ptr<CompositorFrameReporter>>
owned_partial_update_dependents_;
bool want_new_tree_ = false;
bool created_new_tree_ = false;
bool invalidate_raster_scroll_ = false;
bool will_throttle_main_ = false;
bool waiting_for_main_ = true;
uint64_t active_tree_staleness_ = 0;
std::optional<FrameSkippedReason> frame_skipped_reason_v4_;
const GlobalMetricsTrackers global_trackers_;
ReporterType reporter_type_;
base::WeakPtrFactory<CompositorFrameReporter> weak_factory_{this};
};
}
#endif